SpringBoot + Vue实现博文上传+展示+博文列表

Posted Huterox

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot + Vue实现博文上传+展示+博文列表相关的知识,希望对你有一定的参考价值。

文章目录

前言

ok,又到了水文时间了,那么今天带来的是这个WhiteHole的最新的开发进度,也就是实现了我们的博文的基本功能。那么之后比较重大的功能就是我们的消息系统+流量统计(文章,问答之类的数据信息)其他的什么社区,社区管理什么的和我们先前的业务是类似的。所以的话这里就不想复述了,因为意义不大,那部分的话基本上技术没什么难的就是基本的CURD+调用微服务。实话实说,这部分的开发对我来说其实就是繁琐,其实很简单,当然要考虑的东西不少。然后的话还有咱们的后台管理系统,这部分用户端做的差不多了,这个后台的其实也快,无法也是CURD+一些高权限的操作。现阶段的代码还是一个初级阶段,后面把组件上齐了,咱们还会在修改说明的。

那么这次的话也是我们尽可能完整一点。
不过的话也是有部分内容重复的,所以请先阅读这篇文章:
Vue整合Markdown组件+SpringBoot文件上传+代码差异对比

实现效果

博文列表

文章编辑





文章显示

其实这里的实现逻辑和先前的那个很像,区别就是说,但是先前的话也是没有说完整,那么现在的话我们说仔细一点,完整的前端代码+后端的主要业务代码。

博文列表

首先来说的是我们的一个博文的列表。

先说一下我们的这个博文的这个数据表:

我们这边是将内容和我们的blog分开的。因为我们这边要实现很多的操作,比如文章的fork,合并修等等。

前端

我们先来看到前端的完整的代码,这里的话我就直接给出我这个显示的列表的代码。这里的前端的所有的代码都是没有封装的,好处是方便修改,方便理解。坏处是,不方便调用,但是不好维护,所以的话,不去封装了,开发完再说,还有很多的辅助功能没做呢。

那么我们就来看看吧:


<template>
  <div style="width: 100%">
    <el-empty
      image="/static/image/empty.gif" :image-size="600" description="暂时木有找到博文~"
      v-if="isEmpty"
    >
    </el-empty>
    <br>
    <br>
    <div v-if="!isEmpty" style="width: 100%;margin-left: 1%" class="main">
      <el-card shadow="hover" v-for="(message,index) in Messages" :key="index">

        <div style="height:100px">
          <div  style="width:14%;height: 100%;border-radius: 100px;display:inline-block;">
            <el-image
              style="width:100%;height: 100%;border-radius: 100px"
              v-bind:src="message.blogimg"
              class="image"
            />
          </div>
          <div style="display:inline-block;margin-left: 5%;width: 60%">
            <p class="message" style="font-weight:bold">
              <router-link class="alink" :to=" path: '/blogshow',query:'blogid':message.blogid">
                message.blogTitle
              </router-link>
            </p>
            <p style="font-weight: lighter" class="message">
              message.info
            </p>
            <p class="message">
              阅读:
              <i class="el-icon-view"></i>
              message.viewNumber
              &nbsp;&nbsp;
              收藏:
              <i class="el-icon-star-off"></i>
              message.collectNumber
              &nbsp;&nbsp;
              fork:message.forkNumber
            </p>

          </div>

          <div  style="width:18%;height: 100%;
          display:inline-block;
          "
          >
            <p style="text-align: center;font-size: 8px">message.createTime</p>
          <br><br>
          </div>

        </div>
        <br>
      </el-card>
    </div>
    <br>
    <div class="footer" style="margin: 0 auto;width: 100%;">
    </div>
  </div>
</template>

<script>
export default 
  name: "lastArticle",
  data()
    return
      isEmpty: true,
      total: 0,
      page: 1,
      limit: 10,
      Messages:[
        
          userid: null,
          info: null,
          blogid: null,
          contentid: null,
          blogTitle: null,
          userNickname: null,
          userImg: null,
          createTime: null,
          viewNumber: null,
          likeNumber: null,
          collectNumber: null,
          status: null,
          level: null,
          forkNumber: null,
          blogimg: null
        ,
      ]
    
  ,
  methods:
    getDataList()
      //这里客户端自己进行一个缓存
      let pageSession = sessionStorage.getItem("lastHomeBlogListPageSession");
      let total  = sessionStorage.getItem("lastHomeBlogListTotal");
      if(pageSession && total)
        this.Messages = JSON.parse(pageSession);
        this.total = parseInt(total);
        this.isEmpty = (this.total === 0);
      else 
        this.axios(
          url: "/blog/blog/home/last",
          method: 'get',
        ).then((res) => 
          res = res.data;
          if (res.code === 0) 
            //这个就是我们的默认展示图片
            let image_base_user = "https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg";
            let image_base_blog = "https://whiteholecloud-dev.oss-cn-shanghai.aliyuncs.com/2022-09-25/8cee84b4-1d03-483f-8376-14d419d84ca5_03.jpg"
            //同样的拿到数据后需要临时保存
            let page = res.page;
            this.total = page.totalCount;
            this.Messages = page.list
            this.isEmpty = (this.total === 0);
            for (let i=0;i<this.Messages.length;i++)
            
              if(!this.Messages[i].userImg)this.Messages[i].userImg=image_base_user;
              if(!this.Messages[i].blogimg)this.Messages[i].blogimg=image_base_blog
            
            //存储临时缓存
            sessionStorage.setItem("lastHomeBlogListPageSession", JSON.stringify(this.Messages));
            sessionStorage.setItem("lastHomeBlogListTotal",page.totalCount);
           else 
            this.$message.error(res.msg);
          
        );
      
    
  ,
  created() 
    this.getDataList();
  ,

</script>

<style scoped>
.message
  width: 25em;
  overflow: hidden;
  text-overflow:ellipsis;
  white-space: nowrap;


.alink
  text-decoration: none;
  color: #333333;


</style>

我们这边的话,为了防止客户端的数据丢失以及降低我们的服务端的压力,所以的话做一个缓存,当然我们服务端还是有哨兵的,双重限流嘛。

后端接口

之后的话,就是接口的实现,这个其实相当简单,查表就好了,当然我们这边 还要做一个缓存,这个缓存的话就是直接使用SpringCache来做的。
首先是我们的接口:

    @RequestMapping("/last")
    @Cacheable(value="homePageBlog:lastHomePageList",key = "#root.methodName")
    public R lastHomePageList() throws Exception 
        return blogHomePageService.lastBlogList();
    

之后的话是我们的实现类:

   @Override
    public R lastBlogList() throws Exception 
        HashMap<String, Object> params = new HashMap<>();
        //组装请求博文列表所需要的数据,当访问的为内部接口时,所有的参数均为Map形式
        params.put("page","1");
        params.put("limit","10");
        params.put("accurate","single");
        //此时指定HoleNULL,那么这个key不参与查询,但是需要进行占位,不能为空
        params.put("table_name","HoleNULL");
        params.put("key","1");
        params.put("order","desc");
        params.put("status","1");
        params.put("level","1");
        PageUtils page = blogService.queryPage(params);
        return R.ok().put("page", page);
    

这里的话我们重写了这个queryPage的方法来实现分页。

public class BlogServiceImpl extends ServiceImpl<BlogDao, BlogEntity> implements BlogService 

    /**
     *
     * 在所有的基础方法当中我们做出如下约定,(因为有大量的请求是需要使用到分页查询的,并且这个方法相当重要)
     * key,表示需要模糊查询或者精确查询的值,和 accurate 相互配合。
     * accurate表示改查询需要进行精确查询 当accurate=single 表示精确查询,需要指定
     * table_name 还有order:desc,asc当为many,表示需要更加复杂的查询,此时需要附带 accurate_query 即查询QueryWrapper
     * 所有的附加值都需要具备
     * 最后必须参数为
     * 'page': 第几页
     * 'limit':每页多少,
     * 此外对于用户端的查询,需要指明status,和 level否则处理将失败
     * */

    @Override
    public PageUtils queryPage(Map<String, Object> params) throws Exception 
        String key = (String) params.get("key");
        String accurate = (String) params.get("accurate");
        IPage<BlogEntity> page_params = new Query<BlogEntity>().getPage(params);
        QueryWrapper<BlogEntity> blogEntityQueryWrapper = new QueryWrapper<>();
        if(key!=null)
            if(accurate==null)
                //此时表示只有key,没有accurate,说明是后台管理系统在调用
                blogEntityQueryWrapper.like("userid",key).or().
                        like("blogid",key).or().
                        like("user_nickname",key).or().
                        like("blog_title",key);
            else 
                //此时有accurate说明是用户端在调用
                if(accurate.equals("single"))
                    String table_name = (String) params.get("table_name");
                    String order = (String) params.get("order");
                    Integer status = Integer.valueOf((String) params.get("status"));
                    Integer level = Integer.valueOf((String) params.get("level"));
                    if(table_name.equals("HoleNULL"))
                        blogEntityQueryWrapper.eq("status",status)
                                .eq("level",level);
                    else 
                        blogEntityQueryWrapper.eq(table_name,key)
                                .eq("status",status)
                                .eq("level",level);
                    

                    if(order.equals("desc"))
                        blogEntityQueryWrapper.orderByDesc("blogid");
                    

                else if(accurate.equals("many"))
                    Object accurate_query = params.get("accurate_query");
                    QueryWrapper<BlogEntity> deserialize = (QueryWrapper<BlogEntity>) SerializeUtil.deserialize(accurate_query.toString());
                    blogEntityQueryWrapper = deserialize;
                
            
        
        IPage<BlogEntity> page = this.page(
                page_params,
                blogEntityQueryWrapper
        );

        return new PageUtils(page);
    


这些代码后面在做一个映射封装。

这里的话还有我们的R类:

public class R extends HashMap<String, Object> 
	private static final long serialVersionUID = 1L;
	
	public R() 
		put("code", 0);
		put("msg", "success");
	
	
	public static R error() 
		return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, "未知异常,请联系管理员");
	
	
	以上是关于SpringBoot + Vue实现博文上传+展示+博文列表的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot + Vue + ElementUI 实现后台管理系统模板 -- 后端篇: 整合阿里云 OSS 服务 -- 上传下载文件图片

SpringBoot + Vue(前后端分离之博客上传)

SpringBoot+Vue+token实现(表单+图片)上传图片地址保存到数据库。上传图片保存位置自己定义图片可以在前端回显)

Vue + Element(文件上传控件)+ SpringBoot 文件上传功能

springboot整合vue实现上传下载文件

SpringBoot+Vue+kkFileView实现文档管理(文档上传下载在线预览)