黑马旅游网——分页数据展示(难点)和旅游线路名称查询

狗都能看懂的代码分析!!!,虽然这一块比较绕但是我还是决定让狗都能看懂

期望效果:

数据展示功能:
当我们点击分页展示栏中任意一页时,就会展示相应板块(cid)的数据
在这里插入图片描述
如我们点击国内游(cid=5),就会展示国内游的数据,这里数据库中只存了国内游的数据,我们点击之后就会以这样的方式展示数据:
在这里插入图片描述
图面中的1、2、3部分就是我们要展示的数据了(记住图中1、2、3三个位置,以后会再出现),我们需要的是在1处把旅游路线按照每页规定的展示页数(此处是5页)分页展示到页面上,在2处展示总共有多少信息,和总共有多少页,3处是一个分页展示条,采用前5后4的方式进行展示(不足则补全),点击首页会回到第一页数据,点击上一页会展示上一页的数据。

**查询功能:**当我们在搜索框中输入感兴趣的某一旅游路线时,展示的就是关于改路线的信息了

在这里插入图片描述
如我们搜索西安时,1处展示的就应该是西安的数据(一个关于路线名称的模糊查询):
在这里插入图片描述
并且这个查询有多种情况,我们可以通过首页的输入框查询,也可以通过国内游页面进行查询,都要保证数据的正确展示。

实现逻辑(详细版)

1、从首页点击国内游页面:

在header.html中,加入了js代码:

 //查询分类数据
        $.get("category/findAll",{},function (data) {
            //[{cid:1,cname:国内游},{},{}]
            var lis = '<li class="nav-active"><a href="index.html">首页</a></li>';
            //遍历数组,拼接字符串(<li>)
            for (var i = 0; i < data.length; i++) {
                var li = '<li><a href="route_list.html?cid='+data[i].cid+'">'+data[i].cname+'</a></li>';

                lis += li;

            }


            //拼接收藏排行榜的li,<li><a href="favoriterank.html">收藏排行榜</a></li>

            lis+= '<li><a href="favoriterank.html">收藏排行榜</a></li>';

            //将lis字符串,设置到ul的html内容中
            $("#category").html(lis);
        });

由这段代码可见,分类展示栏中的几个选项是从数据库中进行读取的(redis),然后采取拼接字符串的形式拼接的li标签加载到前端页面上,此刻的分类展示栏的每个按钮都是一个携带了cid的超链接,根据cid即可完成后续的功能,数据库中表的结构如图所示:
在这里插入图片描述
我们点击国内游以后,就跳转到了route_list.html页面,并且携带了cid = 5 的参数。

2、route_list.html中的逻辑

进入到route_list.html中后,逻辑比之前要复杂一些:

$(function () {
            // var search = location.search;
             //alert(search);//?id=5
             // 切割字符串,拿到第二个值
             //var cid = search.split("=")[1];
            //获取cid的参数值
            // 使用封装好的一个js文件的方法 getParameter 直接根据键获得值
            var cid = getParameter("cid");
            //获取rname的参数值
            var rname = getParameter("rname");
            //判断rname如果不为null或者""
            if(rname){
                //url解码
                rname = window.decodeURIComponent(rname);
            }
            if (rname==null){
                rname=''; //rname为空则让其变成空字符,后面的servlet会处理,避免变成'null'字符串
            }
            //当页码加载完成后,调用load方法,发送ajax请求加载数据
            load(cid,null,rname);
        });

        function load(cid ,currentPage,rname){
            //发送ajax请求,请求route/pageQuery,传递cid
            $.get("route/pageQuery",{cid:cid,currentPage:currentPage,rname:rname},function (pb) {
                //解析pagebean数据,展示到页面上

                //1.分页工具条数据展示
                //1.1 展示总页码和总记录数
                $("#totalPage").html(pb.totalPage);
                $("#totalCount").html(pb.totalCount);

                /*
                        <li><a href="">首页</a></li>
                        <li class="threeword"><a href="#">上一页</a></li>
                        <li class="curPage"><a href="#">1</a></li>
                        <li><a href="#">2</a></li>
                        <li><a href="#">3</a></li>
                        <li><a href="#">4</a></li>
                        <li><a href="#">5</a></li>
                        <li><a href="#">6</a></li>
                        <li><a href="#">7</a></li>
                        <li><a href="#">8</a></li>
                        <li><a href="#">9</a></li>
                        <li><a href="#">10</a></li>
                        <li class="threeword"><a href="javascript:;">下一页</a></li>
                        <li class="threeword"><a href="javascript:;">末页</a></li>


                 */
                var lis = "";
                // a href="javascript:void(0)">是为了保证点击超链接什么都不做,而是使用点击事件进行ajax操作
                var fristPage = '<li οnclick="javascipt:load('+cid+',1,\''+rname+'\')"><a href="javascript:void(0)">首页</a></li>';

                //计算上一页的页码,为了不产生异常,如果不注意点击第一页的上一页就没了
                var beforeNum =  pb.currentPage - 1;
                if(beforeNum <= 0){
                    beforeNum = 1;
                }

                var beforePage = '<li  οnclick="javascipt:load('+cid+','+beforeNum+',\''+rname+'\')" class="threeword"><a href="javascript:void(0)">上一页</a></li>';

                lis += fristPage;
                lis += beforePage;
                //1.2 展示分页页码
                /*
                    1.一共展示10个页码,能够达到前5后4的效果
                    2.如果前边不够5个,后边补齐10个
                    3.如果后边不足4个,前边补齐10个
                */

                // 定义开始位置begin,结束位置 end
                var begin; // 开始位置
                var end ; //  结束位置


                //1.要显示10个页码
                if(pb.totalPage < 10){
                    //总页码不够10页

                    begin = 1;
                    end = pb.totalPage;
                }else{
                    //总页码超过10页

                    begin = pb.currentPage - 5 ;
                    end = pb.currentPage + 4 ;

                    //2.如果前边不够5个,后边补齐10个
                    if(begin < 1){
                        begin = 1;
                        end = begin + 9;
                    }

                    //3.如果后边不足4个,前边补齐10个
                    if(end > pb.totalPage){
                        end = pb.totalPage;
                        begin = end - 9 ;
                    }
                }


                for (var i = begin; i <= end ; i++) {
                    var li;
                    //判断当前页码是否等于i
                    if(pb.currentPage == i){

                        li = '<li class="curPage" οnclick="javascipt:load('+cid+','+i+',\''+rname+'\')"><a href="javascript:void(0)">'+i+'</a></li>';

                    }else{
                        //创建页码的li
                        li = '<li οnclick="javascipt:load('+cid+','+i+',\''+rname+'\')"><a href="javascript:void(0)">'+i+'</a></li>';
                    }
                    //拼接字符串
                    lis += li;
                }





                /* for (var i = 1; i <= pb.totalPage ; i++) {
                     var li;
                     //判断当前页码是否等于i
                     if(pb.currentPage == i){

                         li = '<li class="curPage" οnclick="javascipt:load('+cid+','+i+')"><a href="javascript:void(0)">'+i+'</a></li>';

                     }else{
                         //创建页码的li
                         li = '<li οnclick="javascipt:load('+cid+','+i+')"><a href="javascript:void(0)">'+i+'</a></li>';
                     }
                     //拼接字符串
                     lis += li;
                 }*/            // 下一页和末页就不做出效果了
                var lastPage = '<li class="threeword"><a href="javascript:;">末页</a></li>';
                var nextPage = '<li class="threeword"><a href="javascript:;">下一页</a></li>';

                lis += nextPage;
                lis += lastPage;


                //将lis内容设置到 ul
                $("#pageNum").html(lis);



                /*
                    <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>

                 */

                //2.列表数据展示
                var route_lis = "";

                for (var i = 0; i < pb.list.length; i++) {
                    //获取{rid:1,rname:"xxx"}
                    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>&yen;</span>\n' +
                    '                                <span>'+route.price+'</span>\n' +
                    '                                <span>起</span>\n' +
                    '                            </p>\n' +
                    '                            <p><a href="route_detail.html?rid='+route.rid+'">查看详情</a></p>\n' +
                    '                        </div>\n' +
                    '                    </li>';
                    route_lis += li;
                }
                $("#route").html(route_lis);

                //定位到页面顶部
                window.scrollTo(0,0);
            });

        }


    </script>

我来一点一点给大家分析整个过程,进入到入口函数$(function ()后,会从之前来的location中获取cid和rname两个参数,这里的getParameter方法是引入了一个封装好的js文件,根据不同的情况,这两个参数会有不同的值,如果是从直接点击的国内游,那么cid为5、rname的值为null,如果是从国内游页面查询的具体旅游路线,那么这两个参数就都有值,要是只在首页直接搜索的,那么rname参数是有值的,但是cid是null,这三种情况我们都应该让他们不会出错。

然后我们就调用load方法,传入三个参数加载页面。首先发送ajax请求到route/pageQuery这个servlet中得到PageBean对象,这个对象封装了:总记录数totalCount、总页数totalPage、当前页码currentPage、每页显示条数pageSize、还有每页显示的数据list。我们先把最简单的处理的总页码和总记录数展示到页面的2处,然后就是实现3处的分页展示条,我们展点击任何一个按钮(如1、如首页、如上一页)是不是就相当于在请求本页的数据呢?所以拼接的每个标签我们都给他绑定单击事件:
如首页按钮:

var fristPage = '<li οnclick="javascipt:load('+cid+',1,\''+rname+'\')"><a href="javascript:void(0)">首页</a></li>';

点击首页我们就会再调用load方法,并且指定当前页为1。
首页和上一页写完后,我们就要拼接前5后4设计的数字分页条:

for (var i = begin; i <= end ; i++) {
                    var li;
                    //判断当前页码是否等于i
                    if(pb.currentPage == i){

                        li = '<li class="curPage" οnclick="javascipt:load('+cid+','+i+',\''+rname+'\')"><a href="javascript:void(0)">'+i+'</a></li>';

                    }else{
                        //创建页码的li
                        li = '<li οnclick="javascipt:load('+cid+','+i+',\''+rname+'\')"><a href="javascript:void(0)">'+i+'</a></li>';
                    }
                    //拼接字符串
                    lis += li;
                }

当前页面我们给他加一个黄色的样式,其他页码的话增加单击事件,重新传递当前页面这个参数调用load方法。至于末页和下一页按钮是同理的,我们就不做了(偷懒)
最后就是图片中1处的5个信息了,我们从得到的list数据中把他们取出来放到前端页面上,这样你需要那一页的数据,就可以进行展示了。

3、后端数据的逻辑

后端数据就比前端简单些:
首先是web的servlet:

@WebServlet("/route/*")
public class RouteServlet extends BaseServlet{
    private RouteService routeService = new RouteServiceImpl();

    /**
     * 分页查询
     * @param request
     * @param response
     */
    public void pageQuery(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
            {
        //1.接受参数
        String currentPageStr = request.getParameter("currentPage");
        String pageSizeStr = request.getParameter("pageSize");
        String cidStr = request.getParameter("cid");

        // 接受线路名称 rname
        String rname = request.getParameter("rname");
        //解决get方式的乱码问题
        rname = new String(rname.getBytes("iso-8859-1"),"utf-8");

        if(rname.length()<=0){ //如果rname为空字符串"" 让其为null
            rname = null;  //  这里出现了一个很烦人的bug,靠csdn解决了,就是当rname为null的时候,前端拼接会拼成空字符串,这样点击第二页就不会有任何数据了
        }
        int cid = 0;  // 类别id

        //2.处理参数
        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; // 每条显示条数,如果不传递,默认每页显示5条记录
        if (pageSizeStr != null && pageSizeStr.length() > 0){
            pageSize = Integer.parseInt(pageSizeStr);

        }else {
            pageSize = 5;
        }

        //3. 调用service查询PageBean对象
        PageBean<Route> pb = routeService.pageQuery(cid,
                currentPage, pageSize,rname);

        //4. 将pageBean对象序列化为json,返回
        writeValue(pb,response);

    }
}

首先要接受前端load方法ajax请求的参数,如果没有传递页码,默认是第一页,这里没有传递每页显示条数,所以默认是5条了,然后就用Service层的对象处理业务了:
Service代码:

public class RouteServiceImpl  implements RouteService {
    private RouteDao routeDao = new RouteDaoImpl();
    @Override
    public PageBean<Route> pageQuery(int cid, int currentPage, int pageSize,String rname) {
       // 封装PageBean
        PageBean<Route> pb = new PageBean<Route>();
        //设置当前页码
        pb.setCurrentPage(currentPage);
        //设置每页显示条数
        pb.setPageSize(pageSize);
        //设置总记录数
        int totalCount = routeDao.findTotalCount(cid,rname);
        pb.setTotalCount(totalCount);
        
        // 设置当前显示的数据集合
        int start = (currentPage - 1)*pageSize;  //开始的记录数
        List<Route> list = routeDao.findByPage(cid, start, pageSize,rname);
        pb.setList(list);

        //设置总页数 = 总记录数/每页显示条数
        int totalPage = totalCount % pageSize == 0 ? totalCount / pageSize : (totalCount/pageSize)+1;
        pb.setTotalPage(totalPage);

        return  pb;

    }
}

总记录数和需要展示的数据都是要用dao层查询的,总页数可以直接计算,无需查询数据库。
Dao层代码:

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 = ?";
        //1.定义sql模板
        String sql = "select count(*) from tab_route where 1=1 ";
        StringBuilder sb = new StringBuilder(sql);

        List params = new ArrayList();//条件们
        //2.判断参数是否有值
        if(cid != 0){
            sb.append( " and cid = ? ");

            params.add(cid);//添加?对应的值
        }

        if(rname != null && rname.length() > 0){
            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 cid = ? and rname like ?  limit ? , ?";
        String sql = " select * from tab_route where 1 = 1 ";
        //1.定义sql模板
        StringBuilder sb = new StringBuilder(sql);

        List params = new ArrayList();//条件们
        //2.判断参数是否有值
        if(cid != 0){
            sb.append( " and cid = ? ");

            params.add(cid);//添加?对应的值
        }

        if(rname != null && rname.length() > 0){
            sb.append(" and rname like ? ");

            params.add("%"+rname+"%");
        }
        sb.append(" limit ? , ? ");//分页条件

        sql = sb.toString();

        params.add(start);
        params.add(pageSize);


        return template.query(sql,new BeanPropertyRowMapper<Route>(Route.class),params.toArray());
    }


}

要使用两个方法查询总数和要展示的数据,这里和往常不一样的是,参数的个数是不确定的,因为可能有三种方式来查询数据,cid或rname两者都有可能是null的,所以要定义一个sql模板根据情况来进行查询,这里有一个小技巧:使用where 1=1,当cid和rname都没有值的时候,sql语句也不会报错,相当于:
select count(*) from tab_route;
然后我们根据不同情况拼接sql语句,有rname的情况下我们就对rname进行模糊查询。另外,由于参数个数不确定,我们不能直接在queryForObject方法中输入参数,而是用list集合装载参数,然后转为数组即可,此时参数类型为 Object[]类型。

至此,从前台到后台的一系列流程就明了了。


一些烦人的bug

在前端拼接字符串时,当rname为null的时候,会把rname拼接成一个null字符串,这样当我们从国内游进入时,就没法点击数字分页进行换页,点击2页面后即为空页面。

我们把数据库中的

if(rname != null && rname.length() > 0 )

改为

if(rname != null && rname.length() > 0 && !“null”.equals(rname))

增加一个条件的判断即可。

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值