SpringBoot日记本系统全程直播06:把日记的分页和增删改查搞起来撒~~

哈哈,我又来了,今天还是继续来撸这个《SpringBoot日记本系统》!

分页查询

上一讲,我们已经完成了日记的新增,新增完毕后自动跳转到首页。

首页的日记查询是分页的,用的layUI的layPage插件。

mybatis-plus自带一个分页组件,后来我发现之前用的版本有点低,可能还得配合pageHelper来做分页,于是我提升了版本。(3.4.1版本是可以的,亲测可行!)

<!-- mybatis plus 支持 -->
<dependency>
	<groupId>com.baomidou</groupId>
	<artifactId>mybatis-plus-boot-starter</artifactId>
	<version>3.4.1</version>
</dependency>
复制代码

配置分页插件

@Configuration
//mybatis扫包
@MapperScan("com.rabbit.diary.dao")
public class MybatisPlusConfig {

    //分页插件
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return interceptor;
    }


}
复制代码

开始编写查询日记的代码,controller

@RequestMapping("/select")
@SaCheckLogin
public Page<TblSynBlog> select(@RequestBody TblSynBlog blog,
                               @RequestParam Integer pageIndex, @RequestParam Integer size){
    Page<TblSynBlog> pageBean = new Page<>(pageIndex,size);
    Page<TblSynBlog> page = blogService.selectPage(pageBean,blog);
    return page;
}
复制代码

我们接收分页参数;pageIndex和size,还有blog对象(这个用于后面根据某些字段来查询,比如blogType,title等,先预留着)

blogService添加selectPage方法

Page<TblSynBlog> selectPage(Page<TblSynBlog> pageBean, TblSynBlog blog);
复制代码

具体实现

@Override
public Page<TblSynBlog> selectPage(Page<TblSynBlog> pageBean, TblSynBlog blog) {
    QueryWrapper<TblSynBlog> queryWrapper = new QueryWrapper<>();
    queryWrapper.orderByDesc("update_date");
    //只允许查看自己发布的日记
    queryWrapper.eq("user_id", StpUtil.getLoginId());
    queryWrapper.eq("is_delete", "0");
    return blogMapper.selectPage(pageBean,queryWrapper);
}
复制代码

我们规定,用户只能看到自己发布的日记,所以添加user_id的匹配,is_delete是逻辑删除的字段,我们只查询未删除的。还有就是,要根据最后更新日期倒叙排序。

前端代码

list.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<c:set var="basePath" value="${pageContext.request.contextPath}"></c:set>
<div id="dlist" class="layui-card dbox" style="border-right: 2px solid #eaeaea;">
  <div class="layui-card-header"><b><i class="layui-icon layui-icon-list" style="color: #000;"></i></b>日记列表</div>
  <div class="layui-card-body">
    <ul class="dlist">
      <li v-for="item in datalist"><a :href="'${basePath}/diary/' + item.id + '.html'">{{item.title}}</a></li>
    </ul>
    <div id="pageCode"></div>
  </div>
</div>
<script>

  var dlist = new Vue({
      el:"#dlist",

      data:{
        datalist:[],
        pageIndex:1,
        size:10,
        total:0
      },

      methods:{
        queryBlogs(){
          axios.post('${basePath}/blog/select?pageIndex='+this.pageIndex+'&size=' + this.size,{}).then(r =>{
            if(r.data.code != '0000'){
              layer.msg(r.data.message,{icon:2});
              return;
            }
            this.datalist = r.data.data.records;
            this.total = r.data.data.total;

            laypage.render({
              elem: 'pageCode' //注意,这里的 pageCode 是 ID,不用加 # 号
              ,count: dlist.total //数据总数,从服务端得到
              ,limit:dlist.size
              ,curr:r.data.data.current //必须加,不然死循环
              ,jump: function(obj,first) {
                let curr = obj.curr; //当前页码
                dlist.pageIndex = curr;//更新data的页码
                console.log(curr)
                if(!first) dlist.queryBlogs();//重新加载
              }
            });


          });
        }
    },

    created(){
      this.queryBlogs();
    }
  });
</script>
复制代码

配合Vue,我们每次用axios查询后都要重新渲染layPage,注意,一定要添加curr(当前页),不然会死循环的。

效果:

日记查看

每一篇日记都被一个a标签包裹着

<li v-for="item in datalist"><a :href="'${basePath}/diary/' + item.id + '.html'">{{item.title}}</a></li>
复制代码

点击后会跳转到  /diary/{id}.html ,这是PageController里面的一个方法。

@RequestMapping("diary/{id}.html")
@SaCheckLogin
public ModelAndView getDiary(@PathVariable Long id, ModelAndView mav){
    TblSynBlog tblSynBlog = blogService.selectOne(id);
    mav.addObject("blog",tblSynBlog);
    mav.setViewName("detail");
    return mav;
}
复制代码

我们根据id调用selectOne方法,去获取具体的日记对象,添加到视图ModelAndView,返回。

方法实现:

@Override
public TblSynBlog selectOne(Long id) {
    /**
     * 根据id和用户ID查询日志
     */
    QueryWrapper<TblSynBlog> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("id",id);
    queryWrapper.eq("user_id", StpUtil.getLoginId());

    return blogMapper.selectOne(queryWrapper);
}
复制代码

效果:

 

detail.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<c:set var="basePath" value="${pageContext.request.contextPath}"></c:set>
<html>
<head>
    <title>日记本详情页</title>
    <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
    <script src="${basePath}/layui/layui.all.js" charset="utf-8"></script>
    <script src="${basePath}/js/vue.js"></script>
    <script src="${basePath}/js/axios.min.js"></script>
    <link rel="stylesheet" href="${basePath}/layui/css/layui.css" media="all">
    <style>
        .title {margin: 20px;text-align: center;}
        .title2{text-align: center;color: #666;}
        .content {text-indent: 2em;margin-top: 50px;}
        .tools{margin-top: 100px;text-align: right;}
    </style>
</head>
<body>
<div id="app" class="layui-container">
    <div class="layui-row layui-col-space10">
        <div class="layui-row">
            <div class="layui-col-md12">
                <jsp:include page="common/header.jsp"></jsp:include>
            </div>
            <div class="layui-col-md9">
                <div class="layui-card dbox" style="border-right: 2px solid #eaeaea;height: 90%;padding: 16px;">
                    <h1 class="title">${blog.title}</h1>
                    <div class="title2">发布时间:${blog.createDate} &nbsp;&nbsp;&nbsp; 日志类别:${blog.blogType}</div>
                    <div class="content">${blog.content}</div>
                    <div class="tools">
                        <a href="${basePath}/diary/add.html?id=${blog.id}"><button type="button" class="layui-btn layui-btn-normal">修改</button></a>
                        <button onclick="del()" type="button" class="layui-btn layui-btn-danger">删除</button>
                        <a href="${basePath}/"><button type="button" class="layui-btn layui-btn-warm">返回</button></a>
                    </div>
                </div>


            </div>
            <div class="layui-col-md3" style="">
                <jsp:include page="common/sider.jsp"></jsp:include>
            </div>



        </div>
    </div>
    <jsp:include page="common/footer.jsp"></jsp:include>
</div>



<script>

    function del(){
        if(confirm('您确定要删除这个日记吗?')){
            var index = layer.load(1); //添加laoding,0-2两种方式
            axios.post('${basePath}/blog/delete?id=${id}',{}).then(r =>{
                layer.close(index);    //返回数据关闭loading
                if(r.data.code != '0000'){
                    layer.msg(r.data.message,{icon:2});
                    return;
                }
                layer.msg('日记删除成功!',{icon:1});
                setTimeout(()=>{location.href="/"},500)
            }).catch(error => {
                layer.msg(error.response.status,{icon:2});
                layer.close(index);    //返回数据关闭loading
            })
        }
    }


</script>
</body>
</html>
复制代码

修改日记

点击修改按钮,会触发a链接跳转

中间经过Controller

@RequestMapping("diary/add.html")
@SaCheckLogin
public ModelAndView addDiary(@RequestParam(required=false) Long id, ModelAndView mav){
    mav.setViewName("diary/add");
    mav.addObject("id",id);
    return mav;
}
复制代码

 意思就是把id传到add.jsp

为什么我不专门写一个修改页面呢?

因为一般在企业中,新增和修改我们都是共用的,只需要根据有没有id,来判断是新增还修改。

在add.jsp中,我们就做了如下判断

form.on('submit(demo1)', function(data){
    data = {...data.field ,...{content:layedit.getContent(editIndex)}}

    if(data.content.length < 10){
        layer.msg('内容至少10个字符!',{icon:2});
        return false;
    }
    var index = layer.load(1); //添加laoding,0-2两种方式

    //如果有id,就把id传过去
    if("${id}"){
        data.id = "${id}";
    }
    axios.post('${basePath}/blog/add',data).then(r =>{
        layer.close(index);    //返回数据关闭loading
        if(r.data.code != '0000'){
            layer.msg(r.data.message,{icon:2});
            return;
        }
        layer.msg('日记记录成功!',{icon:1});
        setTimeout(()=>{location.href="/"},500)
    });
    return false;
});
复制代码

这是保存日记的逻辑,如果有id传过来,就把id增加到保存的参数中,交给后台去判断是新增还是修改。

当add.jsp被打开,我们需要判断有没有id过来,如果有,就填充日记的数据。

if("${id}"){
    /**
     * 如果id存在,说明是修改
     */
    let index = layer.load(1); //添加laoding,0-2两种方式
    axios.post('${basePath}/blog/get?id=${id}',{}).then(r =>{
        layer.close(index);    //返回数据关闭loading
        if(r.data.code != '0000'){
            layer.msg(r.data.message,{icon:2});
            return;
        }
        //渲染数据
        form.val('blog',r.data.data);
        layedit.setContent(editIndex,r.data.data.content)
    });

}else{
    //默认今天的日期
    fillDate(form);
}
复制代码

效果:

保存日记的接口也需要做改变

/**
 * 新增或者修改
 * @param blog
 * @return
 */
@RequestMapping("/add")
@SaCheckLogin
public Result add(@RequestBody TblSynBlog blog){

    //新增
    if(StrUtil.isBlankIfStr(blog.getId())){
        //拼装BlogBean
        blog.setId(redisServiceImpl.getIncr("BlogId")); //redis自增ID
        blog.setCreateDate(DateUtil.now());
        blog.setUserId(StpUtil.getLoginIdAsLong());
        blog.setUpdateDate(DateUtil.now());
        blogService.save(blog);
    }else{
        //修改
        TblSynBlog tblSynBlog = blogService.selectOne(blog.getId());
        BeanUtil.copyProperties(blog,tblSynBlog);
        tblSynBlog.setUpdateDate(DateUtil.now());
        blogService.updateById(tblSynBlog);
    }


    return Result.success();
}
复制代码

修改的逻辑是,根据id查到数据库中的数据。这边可能会有一个BUG,我们后面再说。

测试一下修改

提交

报错了,MD,看日志

2022-04-16 13:15:46.404  WARN 12852 --- [p-nio-80-exec-6] .m.m.a.ExceptionHandlerExceptionResolver : Resolved [org.springframework.dao.DataIntegrityViolationException: <EOL><EOL>### Error updating database.  Cause: com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column 'title' at row 1<EOL><EOL>### The error may exist in com/rabbit/diary/dao/BlogMapper.java (best guess)<EOL><EOL>### The error may involve com.rabbit.diary.dao.BlogMapper.updateById-Inline<EOL><EOL>### The error occurred while setting parameters<EOL><EOL>### SQL: UPDATE tbl_syn_blog  SET title=?,  blog_type=?, content=?,   update_date=?  WHERE id=?<EOL><EOL>### Cause: com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column 'title' at row 1<EOL>; Data truncation: Data too long for column 'title' at row 1; nested exception is com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column 'title' at row 1]
复制代码

 哦,title字段太短了,那就加长!

alter TABLE tbl_syn_blog MODIFY title VARCHAR(100)
复制代码

执行以上sql即可。

再来

 

删除功能

 看下删除按钮

<button onclick="del()" type="button" class="layui-btn layui-btn-danger">删除</button>
复制代码

 del方法

function del(){
    if(confirm('您确定要删除这个日记吗?')){
        var index = layer.load(1); //添加laoding,0-2两种方式
        axios.post('${basePath}/blog/delete?id=${id}',{}).then(r =>{
            layer.close(index);    //返回数据关闭loading
            if(r.data.code != '0000'){
                layer.msg(r.data.message,{icon:2});
                return;
            }
            layer.msg('日记删除成功!',{icon:1});
            setTimeout(()=>{location.href="/"},500)
        }).catch(error => {
            layer.msg(error.response.status,{icon:2});
            layer.close(index);    //返回数据关闭loading
        })
    }
}
复制代码

调用后台的删除接口,把id传过去

@RequestMapping("/delete")
@SaCheckLogin
public Result delete(@RequestParam Long id ){
    blogService.delete(id);
    return Result.success();
}
复制代码

delete方法实现

@Override
public void delete(Long id) {
    blogMapper.deleteByIdLogic(id);
}
复制代码

我们要做的是逻辑删除,不是真的把日记删除,后期可以考虑做个回收站功能。

deleteByIdLogic方法

@Mapper
public interface BlogMapper extends BaseMapper<TblSynBlog> {

    @Update("update tbl_syn_blog set is_delete = '1' where id = #{id}")
    void deleteByIdLogic(Long id);
}
复制代码

测试删除

 

 

 搞定!

让我们来总结一下这一节的几个要点吧:

1.mybatis-plus分页有默认的插件可以使用,但是请确保MP的版本号不能太低。

2.工作中新增和修改一般是共用一套逻辑,根据id是否存在来判断是新增还是修改。

猜你喜欢

转载自juejin.im/post/7087953445705449479
今日推荐