黑马旅游网编写练习(6)--旅游线路分页展示功能
黑马旅游网编写练习(6)–旅游线路分页展示功能
首页的目录展示功能已经完成,在进入主页后,页面会自动向服务器发送Ajax请求,从而获取目录数据,我们将其名称cname展示到页面中;接下来要实现的是分页展示功能
分析
在点击了某一个目录后,需要展示该目录下的资源到页面中。由于前端展示是html页面,所以只能使用异步请求来获取数据,首先观察目录表与分页展示表在数据库中的关系,如下图所示。
然后分析展示过程:当用户点击某一目录后,我们需要发送一个Ajax请求给服务器,请求中需要包含该目录对应的cid;通过该目录的cid,服务器查询与之关联的另一个目录,称作tab_route表;将该表中位于此目录下的数据获取出来,并以json形式返回给客户端,客户端完成展示。由于在展示过程中还涉及到分页功能,所以数据的交互分析结果图如下所示:
在目录中加入类别cid的传递
前面编写的目录展示只保存了cname,并未保存cid,所以修改Category的service层代码,加入cid的保存。修改后的代码如下:
/**
* 查询数据库中tab_category,查询成功返回list集合
* 使用redis缓存进行优化
* @return
*/
@Override
public List<Category> findTab() {
// 定义一个set集合,存放redis中集合
//Set<String> categorys = null;
Set<Tuple> categorys = null;
// 定义一个list集合,存放数据库中集合
List<Category> list = null;
// 查询缓存中是否存在category
//categorys = jedis.zrange("category",0,-1);
// 查询redis中的分数cid和值cname
categorys = jedis.zrangeWithScores("category",0,-1);
if(categorys == null || categorys.size() == 0){
// redis中不存在
System.out.println("redis中不存在Category,从数据库中查询...");
// 调用dao层方法查询数据
list = dao.findTab();
// 将查询的结果存到redis中,key为category
for (Category category : list) {
jedis.zadd("category",category.getCid(),category.getCname());
}
}else{
// redis中存在
System.out.println("redis中存在Category,从redis中查询...");
// 将redis中的set集合转换为list集合
list = new ArrayList<Category>();
for (Tuple tuple : categorys) {
Category category = new Category();
category.setCid((int) tuple.getScore());
category.setCname(tuple.getElement());
list.add(category);
}
}
return list;
}
修改前端cid的传递
此时服务器响应回来的数据中已经包含了cid,我们接下来需要在点击响应的目录后,将cid信息进行传递,只需要在header.html的获取分类目录请求中加入cid即可:
// 获取分类目录请求
$.post("category/findTab",{},function (data) {
// data格式:[{"cid":8,"cname":"全球*行"},{"cid":5,"cname":"国内游"},{},{},{}]
var list = '<li class="nav-active"><a href="index.html">首页</a></li>';
var li;
// 遍历集合
for (var i=0;i<data.length; i++){
// 拼接目录,并加入每个目录对应的cid传递
li = '<li><a href="route_list.html?cid='+data[i].cid+'">'+data[i].cname+'</a></li>';
list+=li;
}
list+='<li><a href="favoriterank.html">收藏排行榜</a></li>';
// 将list字符串,显示到ul标签中
$("#category").html(list);
});
路由线路的分页展示
当在主页点击了分类目录后,会跳转到route_list.html页面,并且传递该目录对应的cid,所以可以在route_list.html页面中加入Ajax请求,当页面加载完成后,便向服务器发送请求,将服务器响应的json数据添加到页面中。
首先完成请求route_list.html页面的cid的获取:
// 在入口函数中加入一下代码来获取cid
// 根据请求当前资源的路径获取cid
// 请求路径 http://localhost/travel/route_list.html?cid=7
var cid = location.search.split("=")[1];
至此我们完成了cid数据的获取,前面具体的展示功能暂时先不做;先完成后台的数据查询与响应,关于数据的交互在前的分析过程中已经给出了说明,所以开始从dao层,逐次向servlet层编写后台代码。
首先创建一个PageBean实体类,用来存放响应的数据。主要包含上述列出的所有变量,并添加get与set方法形成。具体代码如下:
/**
* 分页展示数据的实体类
*/
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;
}
}
dao层代码
dao层主要包含两个方法,一个用来查询指定cid的数据总共有多少条;另一个方法则查询指定cid下,从指定位置开始查,查询页面显示数据条数的数据。
两个方法具体实现如下:
// 定义jdbc连接对象
private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
/**
* 根据cid查询指定目录下的数据总条数
* @param cid
* @return
*/
@Override
public int findTotalCount(int cid) {
// 定义数据总条数
int totalCount = -1;
// 定义sql
String sql = "select count(*) from tab_route where cid = ? ";
try {
// 执行sql
totalCount = template.queryForObject(sql,Integer.class,cid);
} catch (DataAccessException e) {
//e.printStackTrace(); //查询数据总条数失败
System.out.println("Routedao查询数据总条数出错!");
}
return totalCount;
}
/**
* 查询页面数据,根据cid查询指定目录下的数据,告知起始位置start以及查询数据条数pageSize
* @param cid
* @param start
* @param pageSize
* @return
*/
@Override
public List<Route> findPage(int cid, int start, int pageSize) {
// 定义存储路由路线的记录集合
List<Route> list = null;
// 定义sql
String sql = "select * from tab_route where cid = ? limit ? , ? ";
try {
// 执行sql
template.query(sql, new BeanPropertyRowMapper<Route>(Route.class),cid,start,pageSize);
} catch (DataAccessException e) {
//e.printStackTrace(); // 查询页面数据失败
System.out.println("Routedao查询页面数据出错!");
}
return list;
}
service层代码
service层需要编写一个方法,该方法首先调用dao层查询cid下数据总条数totalCount;计算出总页面数totalPage;然后计算起始位置,调用dao层查询页面数据方法获取指定数目的数据,将所有要响应的数据封装到PageBean对象中,返回给web层的Servlet。
该方法具体代码如下:
// 定义dao对象
private RouteDao dao = new RouteDaoImpl();
/**
* 页面查询方法,将数据封装到PageBean对象中返回
* @param cid
* @param currentPage
* @param pageSize
* @return
*/
@Override
public PageBean<Route> pageQuery(int cid, int currentPage, int pageSize) {
// 定义PageBean对象
PageBean<Route> pageBean = new PageBean<Route>();
// 调用dao查询总记录条数
int totalCount = dao.findTotalCount(cid);
// 计算总页面数
int totalPage = (totalCount % pageSize == 0)?(totalCount / pageSize):(totalCount / pageSize + 1);
// 计算开始查询位置
int start = (currentPage - 1) * pageSize;
// 调用dao查询页面数据
List<Route> list = dao.findPage(cid,start,pageSize);
// 封装PageBean对象并返回
pageBean.setTotalCount(totalCount);
pageBean.setTotalPage(totalPage);
pageBean.setCurrentPage(currentPage);
pageBean.setPageSize(pageSize);
pageBean.setList(list);
return pageBean;
}
web层Servlet代码
web层则主要接收用户的请求数据cid,此数据必须有,否则请求不合法;另外当前页面以及每页显示记录条数若没有的话,则分别设置默认值;然后调用service层查询方法,得到PageBean对象,将其序列化为json并返回给客户端。
web层具体代码如下:
@WebServlet("/route/*")
public class RouteServlet extends BaseServlet {
public void pageQuery(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 接收cid,并判断是否为空
String cid_str = request.getParameter("cid");
if(cid_str == null || cid_str.length() == 0){
// cid为空,请求错误
System.out.println("cid为空,请求错误");
return;
}
int cid = Integer.parseInt(cid_str);
// 接收当前页面currentPage
String currentPage_str = request.getParameter("currentPage");
if(currentPage_str == null || currentPage_str.length() == 0){
// currentPage为空,设置默认值为1,访问首页
currentPage_str = "1";
}
int currentPage = Integer.parseInt(currentPage_str);
// 接收页面总记录数pageSize
String pageSize_str = request.getParameter("pageSize");
if(pageSize_str == null || pageSize_str.length() == 0){
// pageSize为空,设置默认值为5
pageSize_str = "5";
}
int pageSize = Integer.parseInt(pageSize_str);
// 调用service层获取PageBean对象
RouteService service = new RouteServiceImpl();
PageBean<Route> pageBean = service.pageQuery(cid, currentPage, pageSize);
// 将pageBean对象序列化为json,并响应给客户端
responseJson(response,pageBean);
}
}
前端继续完成Ajax请求代码
以上能够将对应目录的数据查询出来,并且响应给客户端;由于数据库中只存储了国内游,即cid=3的数据,所以目前只能操作国内游;当然,若数据库中加入了其他条目的数据,则也是可以直接查询出来的。接下来继续完成前端的展示,在route_list.html页面中完成数据的展示。在之前获取cid的入口函数中,编写了Ajax请求,在此处完成对响应数据的展示。
关于整个页面数据的展示,主要分为页面分页工具条的展示,以及商品信息的展示;商品信息的展示是静态的,比较简单,先来完成商品信息的展示,再做分页工具条的展示
1.商品信息的展示
只需要遍历json数据中的list集合,将其中的内容拿出来放到对应的标签体中即可。
具体代码如下:
//先来完成商品信息的展示
/*
<li>
<div class="img"><img src="images/04-search_03.jpg" alt=""></div>
<div class="text1">
<p>【减100元 含除夕/春节出发】广州增城三英温泉度假酒店/*行套票</p>
<br/>
<p>1-2月出发,网付立享¥1099/2人起!爆款位置有限,抢完即止!</p>
</div>
<div class="price">
<p class="price_num">
<span>¥</span>
<span>299</span>
<span>起</span>
</p>
<p><a href="route_detail.html">查看详情</a></p>
</div>
</li>
*/
var route_lis = "";
// 遍历集合
for (var i = 0; i < data.list.length; i++) {
var route = data.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_lis填充到对应的ul中
$("#route").html(route_lis);
2.分页工具条的展示
在点击了上一页或者下一页等按钮时,需要向服务器发送Ajax请求来查询数据;然后将该数据展示到页面,所以需要将自身ajax请求封装为一个函数,当点击下一页时,为该按钮添加点击事件,让其调用自身这个函数去查询,同时需要将自身的页码传递给服务器,所以需要对Ajax请求的参数进行添加。以下代码可以实现分页工具条的功能,点击不同页码会展示该页码对应的内容;上页,下一页,首页及尾页均实现了相应的功能。具体代码如下:
function load(cid,currentPage) {
// 此页面加载完成后便向服务器发送Ajax请求获取页面数据
$.post("route/pageQuery",{cid:cid,currentPage:currentPage},function (data) {
// 响应的数据格式:{"totalCount":513,"totalPage":103,"currentPage":1,"pageSize":5,"list":[{"rid":1,"rname":..]}
//先来完成商品信息的展示
var route_lis = "";
// 遍历集合
for (var i = 0; i < data.list.length; i++) {
var route = data.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_lis填充到对应的ul中
$("#route").html(route_lis);
// 接下来完成分页工具条的展示
// 展示共多少页,共多少条记录
$("#totalPage").html(data.totalPage);
$("#totalCount").html(data.totalCount);
// 展示分页工具条数据
var page_lis = "";
var firstPage = '<li οnclick="javascript:load('+cid+')"><a href="javascript:void(0);">首页</a></li>';
// 设置上一页
var beforeNum = data.currentPage - 1;
if(beforeNum <= 0){
beforeNum = 1;
}
var beforePage = '<li οnclick="javascript:load('+cid+','+beforeNum+')"><a href="javascript:void(0);">上一页</a></li>';
// 拼接首页,上一页字符串
page_lis += firstPage;
page_lis += beforePage;
for (var i = 1; i <= data.totalPage; i++) {
var li ="";
if(data.currentPage == i){
li = '<li class="curPage" οnclick="javascript:load('+cid+','+i+')"><a href="javascript:void(0);">'+i+'</a></li>';
}else{
li = '<li οnclick="javascript:load('+cid+','+i+')"><a href="javascript:void(0);">'+i+'</a></li>';
}
page_lis += li;
}
// 设置下一页
var nextNum = data.currentPage + 1;
if(nextNum > data.totalPage){
nextNum = data.totalPage;
}
var nextPage = '<li οnclick="javascript:load('+cid+','+nextNum+')"><a href="javascript:void(0);">下一页</a></li>';
var lastPage = '<li οnclick="javascript:load('+cid+','+data.totalPage+')"><a href="javascript:void(0);">末页</a></li>';
page_lis += nextPage;
page_lis += lastPage;
// 将page_lis加到ul中
$("#pageNum").html(page_lis);
});
}
分页工具条展示优化
上述实现了分页条的功能,但是分页条全部进行了展示,当页码很多时,分页条的显示便显得有些难看;所以需要对其展示进行一些优化;此处借鉴百度搜索页面分页条的展示效果。
一共展示10个页码,能够达到前5后4的效果;
如果当前页码的前面不足5个,则后面补齐10个;
如果当前页码的后面不足4个,则前面补齐10个。
实现该显示方案的主要做法是定义两个变量,一个控制开始页码,一个控制结束页码,并设置为上述显示页码的循环的开始变量和结束变量。具体实现代码如下:
// 优化页码工具条的显示效果
var beginNum = data.currentPage - 5;
var endNum = data.currentPage + 4;
if(beginNum <= 0){
beginNum = 1;
endNum = beginNum + 9;
}
if(endNum > data.totalPage){
endNum = data.totalPage;
beginNum = endNum - 9;
}
for (var i = beginNum; i <= endNum; i++) {
var li ="";
if(data.currentPage == i){
li = '<li class="curPage" οnclick="javascript:load('+cid+','+i+')"><a href="javascript:void(0);">'+i+'</a></li>';
}else{
li = '<li οnclick="javascript:load('+cid+','+i+')"><a href="javascript:void(0);">'+i+'</a></li>';
}
page_lis += li;
}
定位页面到顶端
当点击了页面工具条后,定位到页面的顶部,方便客户继续阅读。主要在执行完了页面的加载后,进行一下定位即可;具体代码如下
// 定位页面到顶部 其中第一个代表x坐标;第二个代表y的坐标
window.scrollTo(0,0);
至此,旅游路线的分页展示功能已经完成了。
上一篇: Harbor 1.10搭建