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

2020-03-06  本文已影响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

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

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>
上一篇 下一篇

猜你喜欢

热点阅读