美文网首页
问题列表-我的问题列表-底层分页逻辑-(4)

问题列表-我的问题列表-底层分页逻辑-(4)

作者: 弹钢琴的崽崽 | 来源:发表于2020-03-06 09:20 被阅读0次

    1. 问题列表功能实现

    1.1 index.html代码修改

    <div class="container-fluid main">
        <div class="row">
            <div class="col-lg-9 col-md-12 col-sm-12 col-xs-12">
                <h2><span class="glyphicon glyphicon-list" aria-hidden="true"></span> 发现</h2>
                <hr>
                <div class="media" th:each="question : ${questions}">
                    <div class="media-left">
                        <a href="">
                            <img th:src="${question.user.getAvatarUrl()}" class="media-object img-rounded">
                        </a>
                    </div>
                    <div class="media-body">
                        <h4 class="media-heading" th:text="${question.title}"></h4>
                        <span th:text="${question.description}"></span>
                        <span class="text-desc">[[${question.commentCount}]] 个回复 • [[${question.viewCount}]] 次浏览 • [[${#dates.format(question.gmtCreate,'dd MM yyyy')}]]</span>
                    </div>
                </div>
            </div>
    
            <div class="col-lg-3 col-md-12 col-sm-12 col-xs-12">
                <h3>热门话题</h3>
            </div>
        </div>
    </div>
    

    1.2 自定义图片样式

    body{
        background-color: #efefef;
    }
    .main{
        margin: 30px;
        background-color: white;
    }
    
    .btn-publish{
        float: right;
        margin-bottom: 15px;
    }
    .media-object{
        width: 38px;
        height: 38px;
    }
    .text-desc{
        font-size:12px;
        font-weight:normal;
        color:#999;
    }
    

    不要忘记引用样式

    <link rel="stylesheet" href="css/community.css"/>
    

    添加跳到首页的连接

    1.3 创建QuestionDTO对象

    对应数据库对象Question唯一的区别是多个User对象属性,它是属于传输层的

    1.4 indexController编写

    package life.guohui.community.controller;
    @Controller
    public class IndexController {
        @Autowired
        private UserMapper userMapper;
        @Autowired
        private QuestionService questionService;
    
        @GetMapping("/")
        public String index(HttpServletRequest request,
                            Model model){
            Cookie[] cookies = request.getCookies();
            if(cookies != null && cookies.length != 0){
                for(Cookie cookie: cookies){
                    if(cookie.getName().equals("token")){
                        String token = cookie.getValue();
                        User user = userMapper.findByToken(token);
                        if(user != null){
                            request.getSession().setAttribute("user",user);
                        }
                        break;
                    }
                }
            }
            List<QuestionDTO> questionList = questionService.list();
            model.addAttribute("questions",questionList);
            return "index";
        }
    
    }
    

    由于返回的是QuestionDTO对象,需要service层解决通过creator字段查找用户对象中的头像图片

    1.5 创建QuestionService

    1.6 Mybatis需要开启驼峰命名规则

    # 开启驼峰命名规则
    mybatis.configuration.map-underscore-to-camel-case=true
    

    1.7 页面效果

    2. 分页实现

    2.1 数据库添加数据

    2.2 indexController

    增加参数,page:当前页码,size:每页显示数

    package life.guohui.community.controller;
    @Controller
    public class IndexController {
        @Autowired
        private UserMapper userMapper;
        @Autowired
        private QuestionService questionService;
    
        @GetMapping("/")
        public String index(HttpServletRequest request,
                            Model model,
                            @RequestParam(name = "page",defaultValue = "1")Integer page,
                            @RequestParam(name = "size",defaultValue = "2")Integer size){
            Cookie[] cookies = request.getCookies();
            if(cookies != null && cookies.length != 0){
                for(Cookie cookie: cookies){
                    if(cookie.getName().equals("token")){
                        String token = cookie.getValue();
                        User user = userMapper.findByToken(token);
                        if(user != null){
                            request.getSession().setAttribute("user",user);
                        }
                        break;
                    }
                }
            }
            PaginationDTO pagination = questionService.list(page,size);
            model.addAttribute("pagination",pagination);
            return "index";
        }
    
    }
    

    2.3 创建分页PaginationDTO

    不用插件,自己实现分页。

    • pages:要显示的所有页码。
    • questions:每页的所有数据放到List集合中。
    • page:当前页码。
    • totalPage:总页数
    package life.guohui.community.dto;
    @Data
    public class PaginationDTO {
        private List<QuestionDTO> questions;
        private boolean showPrevious;
        private boolean showFirstPage;
        private boolean showNext;
        private boolean showEndPage;
        private Integer page;
        private Integer totalPage;
        private List<Integer> pages = new ArrayList<>();
    
    
        public void setPagination(Integer totalCount, Integer page, Integer size) {
    
    
            if(totalCount % size == 0){
                totalPage = totalCount/size;
            }else{
                totalPage = totalCount/size + 1;
            }
    
            if(page<1){
                page = 1;
            }
            if(page>totalPage){
                page = totalPage;
            }
            this.page = page;
            pages.add(page);
            for(int i = 1;i <=3; i++){
                if(page-i>0){
                    pages.add(0,page-i);
                }
                if(page+i <= totalPage){
                    pages.add(page+i);
                }
            }
            //是否展示上一页
            if(page == 1){
                showPrevious = false;
            }else {
                showPrevious = true;
            }
            //是否展示下一页
            if(page == totalPage){
                showNext = false;
            }else{
                showNext = true;
            }
            //是否展示第一页
            if(pages.contains(1)){
                showFirstPage = false;
            }else{
                showFirstPage = true;
            }
            //是否展示最后一页
            if(pages.contains(totalPage)){
                showEndPage = false;
            }else{
                showEndPage = true;
            }
        }
    }
    

    2.4 Service层返回分页数据

    2.5 查总数mapper

    package life.guohui.community.mapper;
    @Mapper
    public interface QuestionMapper {
    ......
        @Select("select count(1) from question")
        Integer count();
    }
    
    

    2.6 分页mapper

    package life.guohui.community.mapper;
    @Mapper
    public interface QuestionMapper {
    ......
        @Select("select * from question limit #{offset},#{size}")
        List<Question> list(@Param(value = "offset") Integer offset,@Param(value = "size") Integer size);
    ......
    }
    
    

    2.7 引入分页HTML

    当前页码高亮

    <nav aria-label="Page navigation">
        <ul class="pagination">
            <li>
                <a href="/?page=1" aria-label="Previous" th:if="${pagination.showPrevious}">
                    <span aria-hidden="true">&lt;&lt;</span>
                </a>
            </li>
            <li>
                <a th:href="@{/(page=${pagination.page - 1})}" aria-label="Previous"
                   th:if="${pagination.showFirstPage}">
                    <span aria-hidden="true">&lt;</span>
                </a>
            </li>
    
            <li th:each="page : ${pagination.pages}" th:class="${pagination.page == page}?'active':''">
                <a th:href="@{/(page=${page})}" th:text="${page}">
                    <span aria-hidden="true">&lt;</span>
                </a>
            </li>
            <li>
                <a th:href="@{/(page=${pagination.page + 1})}" aria-label="Previous"
                   th:if="${pagination.showNext}">
                    <span aria-hidden="true">&gt;</span>
                </a>
            </li>
            <li>
                <a th:href="@{/(page=${pagination.totalPage})}" aria-label="Previous"
                   th:if="${pagination.showEndPage}">
                    <span aria-hidden="true">&gt;&gt;</span>
                </a>
            </li>
    
        </ul>
    </nav>
    

    3. 我的问题列表功能实现

    3.1 js效果

    加入js文件

    页面中引入文件

    <script src="js/jquery-3.4.1.min.js"></script>
    

    3.2 提取公共页面

    新建HTML文件

    <div th:fragment="nav"><!--给模块命名-->
    

    在index.html和publish.html引入

    <div th:insert="~{navigation :: nav}"></div>
    

    模块代码

    <!DOCTYPE HTML>
    <html xmlns:th="http://www.thymeleaf.org">
        <div th:fragment="nav">
            <nav class="navbar navbar-default">
                <div class="container-fluid">
                    <div class="navbar-header">
                        <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
                                data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                            <span class="sr-only">Code社区</span>
    
                        </button>
                        <a class="navbar-brand" href="/">Code社区</a>
                    </div>
                    <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                        <form class="navbar-form navbar-left">
                            <div class="form-group">
                                <input type="text" class="form-control" placeholder="搜索问题">
                            </div>
                            <button type="submit" class="btn btn-default">搜索</button>
                        </form>
                        <ul class="nav navbar-nav navbar-right">
                            <li th:if="${session.user != null}">
                                <a href="/publish">发布</a>
                            </li>
                            <li class="dropdown" th:if="${session.user != null}">
                                <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
                                   aria-expanded="false">
                                    <span th:text="${session.user.getName()}"></span>
                                    <span class="caret"></span></a>
                                <ul class="dropdown-menu">
                                    <li><a href="/profile/question">我的问题</a></li>
                                    <li><a href="#">个人资料</a></li>
                                    <li><a href="#">退出登陆</a></li>
    
                                </ul>
                            </li>
                            <li th:unless="${session.user != null}">
                                <a href="https://github.com/login/oauth/authorize?client_id=Iv1.bf5154208e60707f&redirect_uri=http://localhost:8887/callback&scope=user&state=1">登陆</a>
                            </li>
                        </ul>
                    </div>
                </div>
            </nav>
        </div>
    

    3.3 创建profile.html

    采用这个样式

    <nav aria-label="Page navigation">
        <ul class="pagination">
            <li>
                <a href="#" aria-label="Previous">
                    <span aria-hidden="true">&laquo;</span>
                </a>
            </li>
            <li><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="#" aria-label="Next">
                    <span aria-hidden="true">&raquo;</span>
                </a>
            </li>
        </ul>
    </nav>
    

    3.4 ProfileController

    a. 选中模块高亮通过参数传递@GetMapping("/profile/{action}")

    b. 通过cookie判断User,分页

    package life.guohui.community.controller;
    @Controller
    public class ProfileController {
    
        @Autowired
        private UserMapper userMapper;
        @Autowired
        private QuestionService questionService;
    
        @GetMapping("/profile/{action}")
        public String profile(@PathVariable(name = "action") String action,
                              Model model,
                              HttpServletRequest request,
                              @RequestParam(name = "page",defaultValue = "1")Integer page,
                              @RequestParam(name = "size",defaultValue = "5")Integer size){
    
            User user = null;
            Cookie[] cookies = request.getCookies();
            if(cookies != null && cookies.length != 0){
                for(Cookie cookie: cookies){
                    if(cookie.getName().equals("token")){
                        String token = cookie.getValue();
                        user = userMapper.findByToken(token);
                        if(user != null){
                            request.getSession().setAttribute("user",user);
                        }
                        break;
                    }
                }
            }
            if(user == null){
                return "redirect:/";
            }
    
            if("questions".equals(action)){
                model.addAttribute("section","questions");
                model.addAttribute("sectionName","我的提问");
            }else if("replies".equals(action)){
                model.addAttribute("section","replies");
                model.addAttribute("sectionName","最新回复");
            }
            PaginationDTO paginationDTO = questionService.listByUserId(user.getId(), page, size);
            model.addAttribute("pagination",paginationDTO);
            return "profile";
        }
    }
    

    3.5 自定义样式

    3.6 QuestionService

    创建两个方法listByUserIdcountByUserId

    package life.guohui.community.mapper;
    @Mapper
    public interface QuestionMapper {
    ......
        @Select("select * from question where creator = #{userId} limit #{offset},#{size}")
        List<Question> listByUserId(@Param("userId") Integer userId, @Param(value = "offset") Integer offset, @Param(value = "size") Integer size);
    
        @Select("select count(1) from question where creator = #{userId}")
        Integer countByUserId(@Param("userId") Integer userId);
    }
    

    a 拿到总记录数totalCount

    通过计算拿到总页数totalPage

    if(totalCount % size == 0){
        totalPage = totalCount/size;
    }else{
        totalPage = totalCount/size + 1;
    }
    

    b. 页码不能出现负数或超过总页数

    if(page<1){
        page = 1;
    }
    if(page>totalPage){
        page = totalPage;
    }
    

    c. 修改PaginationDTO类

    修改setPagination方法,通过总页数totalPage和当前页page算出显示页码pages

    package life.guohui.community.dto;
    @Data
    public class PaginationDTO {
        private List<QuestionDTO> questions;
        private boolean showPrevious;
        private boolean showFirstPage;
        private boolean showNext;
        private boolean showEndPage;
        private Integer page;
        private Integer totalPage;
        private List<Integer> pages = new ArrayList<>();
    
        public void setPagination(Integer totalPage, Integer page) {
            this.totalPage = totalPage;
            this.page = page;
            pages.add(page);
            for(int i = 1;i <=3; i++){
                if(page-i>0){
                    pages.add(0,page-i);
                }
                if(page+i <= totalPage){
                    pages.add(page+i);
                }
            }
            //是否展示上一页
            if(page == 1){
                showPrevious = false;
            }else {
                showPrevious = true;
            }
            //是否展示下一页
            if(page == totalPage){
                showNext = false;
            }else{
                showNext = true;
            }
            //是否展示第一页
            if(pages.contains(1)){
                showFirstPage = false;
            }else{
                showFirstPage = true;
            }
            //是否展示最后一页
            if(pages.contains(totalPage)){
                showEndPage = false;
            }else{
                showEndPage = true;
            }
        }
    }
    

    d. 通过size和page计算offset

    Integer offset = size * (page - 1);
    

    e. 所有代码

    package life.guohui.community.service;
    
    @Service
    public class QuestionService {
    
        @Autowired
        private QuestionMapper questionMapper;
        @Autowired
        private UserMapper userMapper;
        public PaginationDTO listByUserId(Integer userId, Integer page, Integer size) {
            PaginationDTO paginationDTO = new PaginationDTO();
            Integer totalPage;
            //拿到总数
            Integer totalCount = questionMapper.countByUserId(userId);
    
            if(totalCount % size == 0){totalPage = totalCount/size;}else{totalPage = totalCount/size + 1;}
            if(page<1){            page = 1;        }
            if(page>totalPage){            page = totalPage;        }
            paginationDTO.setPagination(totalPage,page);
            Integer offset = size * (page - 1);
            List<Question> questions = questionMapper.listByUserId(userId,offset,size);
            List<QuestionDTO> questionDTOList = new ArrayList<>();
            for(Question question : questions){
                User user = userMapper.findById(question.getCreator());
                QuestionDTO questionDTO = new QuestionDTO();
                BeanUtils.copyProperties(question,questionDTO);
                questionDTO.setUser(user);
                questionDTOList.add(questionDTO);
            }
            paginationDTO.setQuestions(questionDTOList);
            return paginationDTO;
        }
    }
    

    f. 由于PaginationDTO修改,所以list方法也要修改

    3.7 页面部分高亮显示

    a. 地址正确显示

    b. 链接的写法

    <a th:href="@{'/profile/'+${section}(page=${1})}
    

    对应@GetMapping("/profile/{action}")

    c. 我的问题,最新回复高亮改变样式

    <a href="/profile/questions"
       th:class="${section == 'questions'}? 'active list-group-item' : 'list-group-item'">我的问题</a>
    <a href="/profile/replies"
       th:class="${section == 'replies'}? 'active list-group-item' : 'list-group-item'">
        最新回复
    </a>
    

    d. profile.html页面

    <!DOCTYPE HTML>
    <html xmlns:th="http://www.thymeleaf.org">
        ......
        <body>
        <div th:insert="~{navigation :: nav}"></div>
            <div class="container-fluid main profile">
                <div class="row">
                    <div class="col-lg-9 col-md-12 col-sm-12 col-xs-12">
                        <h2><span th:text="${sectionName}"></span></h2>
                        <hr>
                        <div class="media" th:each="question : ${pagination.questions}">
                            <div class="media-left">
                                <a href="">
                                    <img th:src="${question.user.getAvatarUrl()}" class="media-object img-rounded">
                                </a>
                            </div>
                            <div class="media-body">
                                <h4 class="media-heading" th:text="${question.title}"></h4>
                                <span class="text-desc">[[${question.commentCount}]] 个回复 • [[${question.viewCount}]] 次浏览 • [[${#dates.format(question.gmtCreate,'yyyy-MM-dd HH:mm')}]]</span>
                            </div>
                        </div>
                        <nav aria-label="Page navigation">
                            <ul class="pagination">
    
                                <li th:if="${pagination.showFirstPage}">
                                    <a th:href="@{'/profile/'+${section}(page=${1})}" aria-label="Previous"
                                       >
                                        <span aria-hidden="true">&lt;&lt;</span>
                                    </a>
                                </li>
                                <li>
                                    <a th:href="@{'/profile/'+${section}(page=${pagination.page - 1})}" aria-label="Previous" th:if="${pagination.showPrevious}">
                                        <span aria-hidden="true">&lt;</span>
                                    </a>
                                </li>
    
    
                                <li th:each="page : ${pagination.pages}" th:class="${pagination.page == page}?'active':''">
                                    <a th:href="@{'/profile/'+${section}(page=${page})}" th:text="${page}">
                                        <span aria-hidden="true">&lt;</span>
                                    </a>
                                </li>
                                <li>
                                    <a th:href="@{'/profile/'+${section}(page=${pagination.page + 1})}" aria-label="Previous"
                                       th:if="${pagination.showNext}">
                                        <span aria-hidden="true">&gt;</span>
                                    </a>
                                </li>
                                <li>
                                    <a th:href="@{'/profile/'+${section}(page=${pagination.totalPage})}" aria-label="Previous"
                                       th:if="${pagination.showEndPage}">
                                        <span aria-hidden="true">&gt;&gt;</span>
                                    </a>
                                </li>
    
                            </ul>
                        </nav>
                    </div>
    
                    <div class="col-lg-3 col-md-12 col-sm-12 col-xs-12">
                        <div class="list-group section">
                            <a href="/profile/questions"
                               th:class="${section == 'questions'}? 'active list-group-item' : 'list-group-item'">我的问题</a>
                            <a href="/profile/replies"
                               th:class="${section == 'replies'}? 'active list-group-item' : 'list-group-item'">
                                最新回复
                                <span class="badge" th:text="${session.unreadCount}"></span>
                            </a>
                        </div>
                    </div>
                </div>
            </div>
        </body>
    </html>
    

    相关文章

      网友评论

          本文标题:问题列表-我的问题列表-底层分页逻辑-(4)

          本文链接:https://www.haomeiwen.com/subject/adqvrhtx.html