做了太多无用功,心情复杂

1. SpringBoot 中的 PageHelper

如果你也在用 MyBatis,建议尝试该分页插件,这一定是最方便使用的分页插件。分页插件支持任何复杂的单表、多表分页。

这不是我说的,官方是这么介绍来着。但是使用过程中也确实有特别方便的地方。也有我学艺不精,暗自头疼的时候。

最近可能是很闲,我看到室友的博客项目后,自己也想造轮子。其实自己之前也有计划写,但是我的懒惰还是打败了行动。最近一段时间开始用SpringBoot搭建一个博客项目。其中在后端展示留言信息时涉及分页。我之前也用过PageHelper寻思很方便这次也就直接上了。

1. 配置PageHelper

*1. *pomx.xml引入依赖

<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.3</version>
</dependency>

2. application.properties 配置

#分页插件
pagehelper.helper-dialect = mysql
pagehelper.params = count=countSql
pagehelper.reasonable = true
pagehelper.support-methods-arguments = true

简单赋值一下官网的解释

  1. helperDialect:分页插件会自动检测当前的数据库链接,自动选择合适的分页方式。配置时,可以使用下面的缩写值:oracle,mysql,mariadb,sqlite,hsqldb,postgresql,db2,sqlserver,informix,h2,sqlserver2012,derby

特别注意:使用 SqlServer2012 数据库时,需要手动指定为 sqlserver2012,否则会使用 SqlServer2005 的方式进行分页。
2. params:为了支持startPage(Object params)方法,增加了该参数来配置参数映射,用于从对象中根据属性名取值
3. reasonable:分页合理化参数,默认值为false。当该参数设置为 true 时,pageNum<=0 时会查询第一页, pageNum>pages(超过总数时),会查询最后一页。
4. supportMethodsArguments:支持通过 Mapper 接口参数来传递分页参数,默认值false,分页插件会从查询方法的参数值中,自动根据上面 params 配置的字段中取值,查找到合适的值时就会自动分页。

*3. * 操作代码

  1. Service
    public interface CommentService {

    List<Comment> listAllComment();
    }
//实现接口类中方法
/**
* 查询所有留言
* */
@Override
public List<Comment> listAllComment(){

CommentExample commentExample = new CommentExample();
commentExample.setOrderByClause("create_by desc");
List<Comment> commentList = commentMapper.selectByExample(commentExample);

return commentList;
}
  1. Controller
    /**
    * 获取所有留言(留言板)
    * */
    @ApiOperation("获取所有留言")
    @GetMapping("comments/list/{page}")
    public PageInfo listAllComment(@PathVariable("page") Integer pageNum){
    //第一个参数表述页数,第二个表示获取数量
    PageHelper.startPage(pageNum,5);
    List<Comment> commentList = commentService.listAllComment();

    PageInfo<Comment> pageInfo = new PageInfo<>(commentList);
    return pageInfo;
    }
    这里我用了参数来表示获取哪一页的数据

前端调用接口查看一下返回的数据
获取第一页的5条数据

前端获取的数据如下
api-comments-list-1

好了,前端想要的数据都有了,真的是很方便。前端通过js获取数据再向网页中填充渲染就可以了。
前端的操作就引人而异了自己前端太菜

我这里是用art-template模板插件和 jquery ajax 请求数据

具体如下

  1. <!-- 引入模板引擎js -->
    <script src='../js/template-web.js'></script>
    <!--制定卡片模板 -->
    <script type="text/html" id="commentTemplate">
    <tr>
    <td>{{index}}</td>
    <td>{{nickName}}</td>
    <td>{{email}}</td>
    <td width="30%">{{comment}}</td>
    <td>{{date}}</td>
    <td>{{address}}</td>
    <td>
    <button type="button" class="mb-2 btn btn-sm btn-danger mr-1" data-toggle="modal" data-target="#deleteModal" onclick="getCommentId(this)">删除</button>
    <p hidden>{{commentId}}</p>
    <button type="button" class="mb-2 btn btn-sm btn-primary mr-1">回复</button>
    </td>
    </tr>
    </script>

    <script type="text/html" id="page-distribution-template">
    <nav class="pagination-lg" aria-label="Page navigation" style=" margin-left: 35%;margin-top: 40px!important;">
    <ul class="pagination">
    <li class="page-item ">
    <a href="#" class="page-link first-page" aria-label="Previous" onclick="jumpPage(this)">
    <p hidden class="p-hidden">{{firstPage}}</p>
    <span aria-hidden="true">«</span>
    </a>
    </li>
    <li class="page-item ">
    <a href="#" class="page-link pre-page" onclick="jumpPage(this)">
    <p hidden class="p-hidden">{{prePage}}</p>
    <span aria-hidden="true"><</span>
    </a>
    </li>
    <li class="page-item "><a href="#" class="page-link">{{pageNum}}</a>
    </li>
    <li class="page-item ">
    <a href="#" class="page-link next-page" onclick="jumpPage(this)">
    <p hidden class="p-hidden">{{nextPage}}</p>
    <span aria-hidden="true">></span>
    </a>
    </li>
    <li class="page-item">
    <a href="#" class="page-link last-page" aria-label="Next" onclick="jumpPage(this)">
    <p hidden class="p-hidden">{{lastPage}}</p>
    <span aria-hidden="true">»</span>
    </a>
    </li>
    </ul>
    </nav>
    </script>

这里我制定了两个模板,一个是表格中数据的载体模板,一个是分页Bar的模板

  1. ajax 请求数据
    <script type="text/javascript">

    $(document).ready(function(){
    //默认初始化第一页
    listComments(1);
    });


    function listComments(page) {
    $.ajax({
    type:"get",
    url:"/api/comments/list/"+page,
    dataType:"json",
    async: true,
    success:function (result) {
    var json = result; //数组

    var pageList = json.list;

    //渲染填充表格数据
    $.each(pageList,function (index,item) {
    var data = {
    index:"",
    commentId:"",
    nickName:"",
    email:"",
    comment:"",
    date:"",
    address:""
    };
    data.index = index+1;
    data.commentId=pageList[index].id;
    data.nickName=pageList[index].name;
    data.email = pageList[index].email;
    data.comment = pageList[index].content;
    data.date = pageList[index].create_by;
    data.address = pageList[index].ip;
    var res = template("commentTemplate", data);
    document.getElementById("comment_container").innerHTML += res;
    });

    //渲染填充分页数据
    //总页数,也是最后一页 向下取整加1
    var pages=json.pages;
    var pageNum = json.pageNum;//当前页
    var prePage;
    var nextPage;


    //前一页判断
    if(pageNum-1>=1){
    prePage = json.prePage;
    }else{
    prePage =1;
    }
    //后一页判断
    if(pageNum+1<=pages){
    nextPage = json.pageNum+1;
    }else{
    nextPage = pages;
    }

    var pageData ={
    firstPage:1,
    prePage:prePage,
    pageNum:pageNum,
    nextPage:nextPage,
    lastPage:pages
    }
    var res = template("page-distribution-template", pageData);
    document.getElementById("page-distribution").innerHTML += res;

    },
    error:function (error) {
    console.log(error);
    }
    });
    }

    function jumpPage(ob) {
    var pageNum =$(ob).children('p:first-child').text();
    $('.comment_container').empty();
    $('.page-distribution').empty();
    listComments(pageNum);
    }
    </script>

换页请求发送就清空原来模板位置的数据,重新请求填充。

写的比较杂乱,很多地方也有可以优化的之处。但是现在先把功能做出来再说。

效果图
Comments-table

大概就是这样。
其中有个体验非常不好的地方就是,由于留言内容长短不一样,在请求渲染过后就会很明显感到页面刷新闪动一下。感觉就比较恶心。我这里也还没想到怎么解决

2. 遇到的坑

上面是成功做出来了的时候,看着还比较简单。一开始我不是这个方案的。

其中遇到了两个比较突出的问题,都是涉及到了数据库设计这种最初的问题

  1. 其一
    我在数据库中储存的时间是 Date 类型,那当然我项目中对应的 entity 也是 Date 类型属性参数了。然后在返回前端的数据中时就出问题了。

JavaDate数据返回到前端变成了数字
后台在返回json数据的时候,用自身的序列化机制把时间变成一段很长的数字。类似图中(网上找的)
SpringMvc

解决方法
利用 @JsonFormat 注解对Date 属性参数进行注解就解决了。

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date create_by;
  1. 其二

我遇到最大的问题就返回给前端的数据不完整,或者说是不正确

如下图中
api-comments-false

除了list中的数据是对的,其他PageInfo属性均不对。
再贴一下正确的对比。
api-comments-list-1

我一开始始终没想到问题在哪。获取的留言信息都正确,为什么其他的属性不匹配

后来搜寻了半天,也去PageInfo看官网文档

常见问题 和 重要提示
在官方的FQA中我看到这样一条

为什么不支持一对一和一对多结果映射的分页查询?

在一对一和一对多时,根据分页条件查询出 100 条数据时,由于一对一和一对多会去重,经过嵌套处理后数据量会减少,因此分页想要获得 100 条数据无法实现。想要支持这种情况可以使用嵌套查询。嵌套查询是要额外执行SQL,主SQL可以得到正确的结果数量,因此可以正常分页。

这里说的在经过嵌套处理后会出现问题。

我想到一开始我的List 中对象不是对应的数据库中 entity,因为数据库中有这里不需要的字段,所以我重新封装了一个对象,只含有自己需要的字段。

在 Service 中我先将数据库中的 Comment list 全部取出来,然后再循环填充到我新封装的对象集合中去。

那么问题就在这里了,这里我用的是Comment对应的SQL 语句进行查询的,只是将返回的数据进行了转移填充。
实际上新对象是没有对应的SQL的,我是这样理解的。所以后面我用 PageInfo 进行接受时也仅仅只含有填充的数据,**其他需要Page Helper需要向数据库索取的数据都不含有,也就导致了数据的缺失。**

后面我直接用数据库对应的 entity 就正常了。总之还是自己在设计数据库的时候没有更多的考虑到这些问题。

坑就先留到这里,后面在有什么问题再继续补充。