9 旅游线路的分页展示
点击了不同的分类后,将来看到的旅游线路不一样的。通过分析数据库表结构,旅游线路表和分类表是一个多对一的关系
查询不同分类的旅游线路sql
Select * from tab_route where cid = ?;
所以点击分类栏时,应该在页面访问路径里面传一个cid
9.1 类别的id的传递
js中 location.search 属性,是一个可读可写的字符串,可设置或返回当前 URL 的查询部分(问号 ? 之后的部分)
假设当前的URL就是 http://www.runoob.com/submit.htm?email=someone@ example.com
<script> document.write(location.search); </script>
输出
?email=someone@example.com
9.1.1 header.html
传递cid
var li = '<li><a href="route_list.html?cid='+ data[i].cid +'">' + data[i].cname + '</a></li>';
9.1.2 route_list.html
获取cid
<script> $(function () { var search = location.search; var cid = search.split("=")[1]; }); </script>
9.2 通过id查询不同类别的旅游线路数据
分页展示
9.2.1 分析
由于分页展示需要总记录数、总页数、当前页码、每页显示条数以及每页显示的数据集合,所以将这些数据封装成一个类 PageBean 来便于传递参数。
客户端向后台发送ajax请求,只用携带当前页码(currentPage)、每页显示条数(pageSize)以及分页id(cid)即可计算出其余信息,在我之前的博客中已经详细论述过,这里不做赘述。
9.2.2 服务器端
PageBean对象:
package cn.itcast.travel.domain; import java.util.List; // 分页对象 public class PageBean<T> { private int totalCount; // 总记录数 private int totalPage; // 总页数 private int currentPage; // 当前页码 private int pageSize; // 每页显示的条目数 private List<T> list; // 每页要显示的数据 public int getTotalCount() { return totalCount; } public void setTotalCount(int totalCount) { this.totalCount = totalCount; } public int getTotalPage() { return totalPage; } public void setTotalPage(int totalPage) { this.totalPage = totalPage; } public int getCurrentPage() { return currentPage; } public void setCurrentPage(int currentPage) { this.currentPage = currentPage; } public int getPageSize() { return pageSize; } public void setPageSize(int pageSize) { this.pageSize = pageSize; } public List<T> getList() { return list; } public void setList(List<T> list) { this.list = list; } }
RouteServlet:
处理客户端传来的三个参数:cid、当前页面和每页显示的条目数,并调用service层返回一个pb对象
package cn.itcast.travel.web.servlet; import cn.itcast.travel.domain.PageBean; import cn.itcast.travel.domain.Route; import cn.itcast.travel.service.RouteService; import cn.itcast.travel.service.impl.RouteServiceImpl; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/route/*") public class RouteServlet extends BaseServlet { private RouteService routeService = new RouteServiceImpl(); /** * 分页查询 * @param request * @param response * @throws ServletException * @throws IOException */ public void pageQuery(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String currentPageStr = request.getParameter("currentPage"); String pageSizeStr = request.getParameter("PageSize"); String cidStr = request.getParameter("cid"); int cid = 0; if (cidStr != null && cidStr.length() > 0 && !"null".equals(cidStr)){ cid = Integer.parseInt(cidStr); } int currentPage = 0; if (currentPageStr != null && currentPageStr.length() > 0){ currentPage = Integer.parseInt(currentPageStr); }else { currentPage = 1; // 默认是第一页 } int pageSize = 0; if (pageSizeStr != null && pageSizeStr.length() > 0){ pageSize = Integer.parseInt(pageSizeStr); }else { pageSize = 5; // 默认每页显示5条记录 } // 调用service查询PageBean对象 PageBean<Route> pb = routeService.pageQuery(cid, currentPage, pageSize); // 序列化为json writeValue(pb, response); } }
servlet调用了service层的 pageQuery 方法来请求一个 PageBean对象,实现如下:
RouteService:
接口
package cn.itcast.travel.service; import cn.itcast.travel.domain.PageBean; import cn.itcast.travel.domain.Route; // 旅游线路service public interface RouteService { /** * 根据类别进行分类查询 * @param cid * @param currentPage * @param pageSize * @return */ public PageBean<Route> pageQuery(int cid, int currentPage, int pageSize); }
实现类,封装PageBean对象并返回
package cn.itcast.travel.service.impl; import cn.itcast.travel.dao.RouteDao; import cn.itcast.travel.dao.impl.RouteDaoImpl; import cn.itcast.travel.domain.PageBean; import cn.itcast.travel.domain.Route; import cn.itcast.travel.service.RouteService; import java.util.List; public class RouteServiceImpl implements RouteService { private RouteDao routeDao = new RouteDaoImpl(); @Override public PageBean<Route> pageQuery(int cid, int currentPage, int pageSize) { // 封装PageBean PageBean<Route> pb = new PageBean<Route>(); pb.setCurrentPage(currentPage); pb.setPageSize(pageSize); int totalCount = routeDao.findTotalCount(cid); pb.setTotalCount(totalCount); // 总记录数 int start = (currentPage - 1) * pageSize; List<Route> list = routeDao.findByPage(cid, start, pageSize); pb.setList(list); // 要展示的数据 int totalPage = totalCount % pageSize == 0 ? totalCount/pageSize : (totalCount/pageSize) + 1; pb.setTotalPage(totalPage); // 总页数 return pb; } }
RouteDao:
接口
package cn.itcast.travel.dao; import cn.itcast.travel.domain.Route; import java.util.List; public interface RouteDao { /** * 根据cid查询总记录数 */ public int findTotalCount(int cid); /** * 根据cid,start,pageSize查询当前页的数据集合 */ public List<Route> findByPage(int cid, int start, int pageSize); }
实现类
package cn.itcast.travel.dao.impl; import cn.itcast.travel.dao.RouteDao; import cn.itcast.travel.domain.Route; import cn.itcast.travel.util.JDBCUtils; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import java.util.List; public class RouteDaoImpl implements RouteDao { private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource()); @Override public int findTotalCount(int cid) { String sql = "select count(*) from tab_route where cid = ?"; return template.queryForObject(sql, Integer.class, cid); } @Override public List<Route> findByPage(int cid, int start, int pageSize) { String sql = "select * from tab_route where cid = ? limit ? , ?"; return template.query(sql, new BeanPropertyRowMapper<>(Route.class), cid, start, pageSize); } }
9.2.3 客户端
route_list.html 中由于在异步请求数据的过程中还要异步请求数据,第一次是页面加载完成之后请求PageBean的数据,第二次是分页页码请求超链接的cid和当前页面数据,所以不能直接在
$(function () {}$(function () {}
里面写方法体了,要单独抽取出一个方法
function load(cid, currentPage) { $.get("route/pageQuery", {cid:cid,currentPage:currentPage}, function (pb) { }; }
load方法中展示分页工具条和分页页码的逻辑如下:
// 分页工具条 $("#totalPage").html(pb.totalPage); $("#totalCount").html(pb.totalCount); // 展示分页页码 var lis = ""; var firstPage = '<li onclick="javascript:load(' + cid + ',' + 1 + ')"><a href="javascript:void(0)">首页</a></li>'; var preNum = pb.currentPage - 1; if (preNum <= 0) preNum = 1; var prePage = '<li onclick="javascript:load(' + cid + ',' + preNum + ')" class="threeword"><a href="javascript:void(0)">上一页</a></li>'; lis += firstPage; lis += prePage; for (var i = 1; i <= pb.totalPage; i ++){ var li; if ( i == pb.currentPage){ li = '<li class="curPage" onclick="javascript:load(' + cid + ',' + i + ')"><a href="javascript:void(0)">' + i + '</a></li>'; }else { li = '<li onclick="javascript:load(' + cid + ',' + i + ')"><a href="javascript:void(0)">' + i + '</a></li>'; } lis += li; } var nextNum = pb.currentPage + 1; if (nextNum >= pb.totalPage) nextNum = pb.totalPage; var nextPage = '<li onclick="javascript:load(' + cid + ',' + nextNum + ')" class="threeword"><a href="javascript:;">下一页</a></li>'; var lastPage = '<li onclick="javascript:load(' + cid + ',' + pb.totalPage + ')" class="threeword"><a href="javascript:void(0;">末页</a></li>'; lis += nextPage; lis += lastPage; $("#pageNum").html(lis);
展示列表数据的逻辑和展示分类页码类似:
var route_lis = ""; for (var i = 0; i < pb.list.length; i++) { // {rid:1,rname:"xxxx"} var route = pb.list[i]; var li = '<li>\n' + ' <div class="img"><img src="' + route.rimage + '" style="width: 299px;"></div>\n' + ' <div class="text1">\n' + ' <p>' + route.rname + '</p>\n' + ' <br/>\n' + ' <p>' + route.routeIntroduce + '</p>\n' + ' </div>\n' + ' <div class="price">\n' + ' <p class="price_num">\n' + ' <span>¥</span>\n' + ' <span>'+route.price+'</span>\n' + ' <span>起</span>\n' + ' </p>\n' + ' <p><a href="route_detail.html">查看详情</a></p>\n' + ' </div>\n' + ' </li>'; route_lis += li; } $("#route").html(route_lis);
另外还需要控制导航栏的个数为10个,控制逻辑如下图:
修改分页页码的逻辑:
/* 1.一共展示10个页码,能够达到前5后4的效果 2.如果前边不够5个,后边补齐10个 3.如果后边不足4个,前边补齐10个 */ var begin; var end; if (pb.totalPage < 10){ begin = 1; end = pb.totalPage; }else { // 总页数超过10页 begin = pb.currentPage - 5 ; end = pb.currentPage + 4 ; if (begin < 1){ begin = 1; end = begin + 9; } if (end > pb.totalPage){ end = pb.totalPage; begin = end - 9; } } for (var i = begin; i < end; i++) { var li; if ( i == pb.currentPage){ li = '<li class="curPage" onclick="javascript:load(' + cid + ',' + i + ')"><a href="javascript:void(0)">' + i + '</a></li>'; }else { li = '<li onclick="javascript:load(' + cid + ',' + i + ')"><a href="javascript:void(0)">' + i + '</a></li>'; } lis += li; }
定位到页面顶部:
window.scrollTo(0,0);
10 旅游线路名称查询
10.1 查询参数的传递
10.1.1 工具类 getParameter.js
用于获取路径中key对应的值
//根据传递过来的参数name获取对应的值 function getParameter(name) { var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)","i"); var r = location.search.substr(1).match(reg); if (r!=null) return (r[2]); return null; }
10.1.2 header.html
将输入的要搜索的数据放到网页链接后面
$("#search-button").click(function () { // 待搜索的线路名称 var rname = $("#search-input").val(); var cid = getParameter("cid"); location.href = "http://localhost/travel/route_list.html?cid=" + cid + "&rname=" + rname; });
10.1.3 route_list.html
获取cid和rname,注意如果要获取的是汉字,则需要进行一个解码
var cid = getParameter("cid"); var rname = getParameter("rname"); if (rname){ rname = window.decodeURIComponent(rname); }
10.2 修改后台代码
10.2.1 RouteServlet
RouteServlet 原先并没有接收rname参数,需要添加
注意:如果用的是tomcat7而不是8则需要处理一下中文乱码的问题
String rname = request.getParameter("rname"); rname = new String(rname.getBytes("iso-8859-1"),"utf-8");
// 调用service查询PageBean对象 PageBean<Route> pb = routeService.pageQuery(cid, currentPage, pageSize, rname);
10.2.2 修改service层
RouteServiceImpl.java
int totalCount = routeDao.findTotalCount(cid, rname);
List<Route> list = routeDao.findByPage(cid, start, pageSize, rname);
10.2.3 dao层
sql语句要根据是否有cid的值和是否有rname的值动态生成
package cn.itcast.travel.dao.impl; import cn.itcast.travel.dao.RouteDao; import cn.itcast.travel.domain.Route; import cn.itcast.travel.util.JDBCUtils; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import java.util.ArrayList; import java.util.List; public class RouteDaoImpl implements RouteDao { private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource()); @Override public int findTotalCount(int cid, String rname) { // String sql = "select count(*) from tab_route where cid = ?"; String sql = " select count(*) from tab_route where 1 = 1 "; StringBuilder sb = new StringBuilder(sql); List params = new ArrayList(); // 问号对应的值 if (cid != 0){ sb.append(" and cid = ? "); params.add(cid); } if (rname != null && rname.length() > 0 && !"null".equals(rname)){ sb.append(" and rname like ? "); params.add("%" + rname + "%"); } sql = sb.toString(); return template.queryForObject(sql, Integer.class, params.toArray()); } @Override public List<Route> findByPage(int cid, int start, int pageSize, String rname) { String sql = " select * from tab_route where 1 = 1 "; StringBuilder sb = new StringBuilder(sql); List params = new ArrayList(); // 问号对应的值 if (cid != 0){ sb.append(" and cid = ? "); params.add(cid); } if (rname != null && rname.length() > 0 && !"null".equals(rname)){ sb.append(" and rname like ? "); params.add("%" + rname + "%"); } sb.append(" limit ? , ? "); params.add(start); params.add(pageSize); sql = sb.toString(); return template.query(sql, new BeanPropertyRowMapper<>(Route.class), params.toArray()); } }
10.3 修改前台代码
当页面加载完成后,调用load()发送ajax请求,加载数据,此时应该过了一个请求参数rname
$(function () { var cid = getParameter("cid"); var rname = getParameter("rname"); if (rname){ rname = window.decodeURIComponent(rname); } // 当页面加载完成后,调用load()发送ajax请求,加载数据 load(cid, null, rname); });
function load(cid, currentPage, rname) 部分代码(主要是调用load()时传入参数的改变):
// 展示分页页码 var lis = ""; var firstPage = '<li onclick="javascript:load(' + cid + ',1,\'' + rname + '\')"><a href="javascript:void(0)">首页</a></li>'; var preNum = pb.currentPage - 1; if (preNum <= 0) preNum = 1; var prePage = '<li onclick="javascript:load(' + cid + ',' + preNum + ',\'' + rname + '\')" class="threeword"><a href="javascript:void(0)">上一页</a></li>'; lis += firstPage; lis += prePage;
for (var i = begin; i < end; i++) { var li; if ( i == pb.currentPage){ li = '<li class="curPage" onclick="javascript:load(' + cid + ',' + i + ',\'' + rname + '\')"><a href="javascript:void(0)">' + i + '</a></li>'; }else { li = '<li onclick="javascript:load(' + cid + ',' + i + ',\'' + rname + '\')"><a href="javascript:void(0)">' + i + '</a></li>'; } lis += li; } var nextNum = pb.currentPage + 1; if (nextNum >= pb.totalPage) nextNum = pb.totalPage; var nextPage = '<li onclick="javascript:load(' + cid + ',' + nextNum + ',\'' + rname + '\')" class="threeword"><a href="javascript:;">下一页</a></li>'; var lastPage = '<li onclick="javascript:load(' + cid + ',' + pb.totalPage + ',\'' + rname + '\')" class="threeword"><a href="javascript:void(0;">末页</a></li>';
11 旅游线路的详细展示
11.1 分析
需要查询三张表:route_img表、route表、seller表
用户点击查看详情后传入路线的id:rid,后台Servlet调用service层,从三张表中分别查出相应的信息,封装到Route对象中返回
11.2 后台代码
11.2.1 RouteServlet 中添加 findOne 方法
public void findOne(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String rid = request.getParameter("rid"); Route route = routeService.findOne(rid); writeValue(route, response); }
11.2.2 RouteService 中添加 findOne 方法
实现从三个表中查询不同的数据,最终封装到Route类对象中并返回
public Route findOne(String rid) { // 查route表 Route route = routeDao.findOne(Integer.parseInt(rid)); // 查询route_img表,获得小图片集合信息 List<RouteImg> routeImgList = routeImgDao.findByRid(route.getRid()); route.setRouteImgList(routeImgList); // 查seller表,获得商家对象 Seller seller = sellerDao.findById(route.getSid()); route.setSeller(seller); return route; }
11.2.3 RouteDaoImpl 中添加 findOne 方法
public Route findOne(int rid) { String sql = "select * from tab_route where rid = ?"; return template.queryForObject(sql, new BeanPropertyRowMapper<Route>(Route.class), rid); }
11.2.4 RouteImgDaoImpl
public List<RouteImg> findByRid(int rid) { String sql = "select * from tab_route_img where rid = ? "; return template.query(sql, new BeanPropertyRowMapper<RouteImg>(RouteImg.class), rid); }
11.2.5 SellerDaoImpl
public Seller findById(int id) { String sql = "select * from tab_seller where sid = ? "; return template.queryForObject(sql, new BeanPropertyRowMapper<Seller>(Seller.class), id); }
11.3 前台代码
11.3.1 route_list.html
查看详情a标签的href要添加一个字段?rid=
<a href="route_detail.html?rid=' + route.rid + '">查看详情</a>
11.3.2 Route_detail.html
1.获取rid
2.发送ajax请求,获取route对象
.3.解析对象的数据
<script src="js/getParameter.js"></script>
$(document).ready(function() { //自动播放 goImg(); // var timer = setInterval("auto_play()", 5000); });
function goImg() { //焦点图效果 //点击图片切换图片 $('.little_img').on('mousemove', function() { $('.little_img').removeClass('cur_img'); var big_pic = $(this).data('bigpic'); $('.big_img').attr('src', big_pic); $(this).addClass('cur_img'); }); //上下切换 var picindex = 0; var nextindex = 4; $('.down_img').on('click',function(){ var num = $('.little_img').length; if((nextindex + 1) <= num){ $('.little_img:eq('+picindex+')').hide(); $('.little_img:eq('+nextindex+')').show(); picindex = picindex + 1; nextindex = nextindex + 1; } }); $('.up_img').on('click',function(){ var num = $('.little_img').length; if(picindex > 0){ $('.little_img:eq('+(nextindex-1)+')').hide(); $('.little_img:eq('+(picindex-1)+')').show(); picindex = picindex - 1; nextindex = nextindex - 1; } }); }
$(function () { var rid = getParameter("rid"); $.get("route/findOne", {rid: rid}, function (route) { $("#rname").html(route.rname); $("#routeIntroduce").html(route.routeIntroduce); $("#price").html("¥" + route.price); $("#sname").html(route.seller.sname); $("#consphone").html(route.seller.consphone); $("#address").html(route.seller.address); // 图片的展示 var ddstr = '<a class="up_img up_img_disable"></a>'; // 遍历routeImgList for (var i = 0; i < route.routeImgList.length; i++) { var astr; if (i >= 4){ astr = '<a title="" class="little_img" data-bigpic="' + route.routeImgList[i].bigPic + '" style="display:none;">\n' + ' <img src="' + route.routeImgList[i].smallPic + '">\n' + ' </a>'; }else { astr = '<a title="" class="little_img" data-bigpic="' + route.routeImgList[i].bigPic + '" >\n' + ' <img src="' + route.routeImgList[i].smallPic + '">\n' + ' </a>'; } ddstr += astr; } ddstr += '<a class="down_img down_img_disable" style="margin-bottom: 0;"></a>'; $("#dd").html(ddstr); // 图片展示和切换 goImg(); }); });
12 旅游线路收藏
12.1 分析
12.1.1 判断当前登录用户是否收藏过该线路
当页面加载完成后,发送ajax请求,获取用户是否收藏的标记
根据标记,展示不同的按钮样式
12.2 后台代码
12.2.1 dao
public class FavoriteDaoImpl implements FavoriteDao { private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource()); @Override public Favorite findByRidAndUid(int rid, int uid) { Favorite favorite = null; try { String sql = "select * from tab_favorite where rid = ? and uid = ?"; favorite = template.queryForObject(sql, new BeanPropertyRowMapper<>(Favorite.class), rid, uid); }catch (Exception e){ e.printStackTrace(); } return favorite; } }
12.2.2 service
public class FavoriteServiceImpl implements FavoriteService { private FavoriteDao favoriteDao = new FavoriteDaoImpl(); @Override public boolean isFavorite(String rid, int uid) { Favorite favorite = favoriteDao.findByRidAndUid(Integer.parseInt(rid), uid); return favorite != null; } }
12.2.3 servlet
在 RouteServlet 中添加方法判断当前登陆的用户是否收藏过该线路
public void isFavorite(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String rid = request.getParameter("rid"); User user = (User)request.getSession().getAttribute("user"); int uid; if (user == null){ // 未登录 uid = 0; }else { uid = user.getUid(); } // 调用FavoriteService查询是否收藏 boolean flag = favoriteService.isFavorite(rid, uid); writeValue(flag, response); }
12.3 前端代码
12.3.1 Route_detail.html
$(function () { // 发送请求,判断用户是否收藏过该线路 var rid = getParameter("rid"); $.get("route/isFavorite", {rid: rid}, function (flag) { alert(flag); if (flag == true){ // 用户收藏了 $("#favorite").addClass("already"); }else { $("#favorite").removeClass("already"); } }); });
12.4 收藏次数
12.4.1 RouteServiceImpl
在该类的 findOne 方法中添加对收藏次数的封装
int count = favoriteDao.findCountByRid(route.getRid()); route.setCount(count);
12.4.2 FavoriteDaoImpl
dao层添加相应的方法
public int findCountByRid(int rid) { String sql = "select count(*) from tab_favorite where rid = ?"; return template.queryForObject(sql, Integer.class, rid); }
12.4.3 Route_detail.html
在数据展示部分添加收藏次数的展示
$("#favoriteCount").html("已收藏" + route.count + "次");
12.5 点击按钮 实现 / 取消 收藏
12.5.1 分析
12.5.2 RouteServlet
增加一个添加收藏的方法
public void addFavorite(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String rid = request.getParameter("rid"); User user = (User) request.getSession().getAttribute("user"); int uid; if (user == null) { // 未登录 return; } else { uid = user.getUid(); } if (!favoriteService.isFavorite(rid, uid)) favoriteService.add(rid, uid); else favoriteService.remove(rid, uid); }
12.5.3 FavoriteService
@Override public void add(String rid, int uid) { favoriteDao.add(Integer.parseInt(rid),uid); } @Override public void remove(String rid, int uid) { favoriteDao.remove(Integer.parseInt(rid), uid); }
12.5.4 FavoriteDao
@Override public void add(int rid, int uid) { String sql = "insert into tab_favorite values(?,?,?)"; template.update(sql,rid,new Date(),uid); } @Override public void remove(int rid, int uid) { String sql = "delete from tab_favorite where rid = ? and uid = ?"; template.update(sql, rid, uid); }
12.5.5 前台 Route_detail.html
给<a>标签添加onclick方法如果要调用js代码,后面方法名一定要加括号!
onclick="addFavorite()"
// 点击收藏按钮 function addFavorite() { var rid = getParameter("rid"); $.get("user/findOne",{},function (user) { if(user){ $.get("route/addFavorite",{rid:rid},function () { // 刷新页面 location.reload(); }); }else { alert("尚未登录,请先登录"); location.href = "http://localhost/travel/login.html"; } }); }
源码下载链接:https://download.csdn.net/download/HNU_Csee_wjw/12560408