欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

黑马旅游网编写练习(6)--旅游线路分页展示功能

程序员文章站 2022-03-06 08:19:38
...

黑马旅游网编写练习(6)–旅游线路分页展示功能

首页的目录展示功能已经完成,在进入主页后,页面会自动向服务器发送Ajax请求,从而获取目录数据,我们将其名称cname展示到页面中;接下来要实现的是分页展示功能

分析
在点击了某一个目录后,需要展示该目录下的资源到页面中。由于前端展示是html页面,所以只能使用异步请求来获取数据,首先观察目录表与分页展示表在数据库中的关系,如下图所示。
黑马旅游网编写练习(6)--旅游线路分页展示功能
然后分析展示过程:当用户点击某一目录后,我们需要发送一个Ajax请求给服务器,请求中需要包含该目录对应的cid;通过该目录的cid,服务器查询与之关联的另一个目录,称作tab_route表;将该表中位于此目录下的数据获取出来,并以json形式返回给客户端,客户端完成展示。由于在展示过程中还涉及到分页功能,所以数据的交互分析结果图如下所示:
黑马旅游网编写练习(6)--旅游线路分页展示功能

在目录中加入类别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>&yen;</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>&yen;</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>&yen;</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);

至此,旅游路线的分页展示功能已经完成了。

相关标签: java-web综合练习