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

@[toc] 通过前面的磨合,总算是习惯了,调整好了,前后端的一些事情。主要是先前前端有一些坑没处理好,导致我这边状况百出,不过还好,只是现在比较容易出问题的那些地方已经解决了,像什么文件上传之类的。那么今天也是实现了博客的上传。

博客表的设计

这里的话不像原来Django的ORM,这里的话还是要自己去键表的。哦对了这里我也将尝试使用mybatisplus完全使用面对对象的写法来实现多表查询(这里的话我还要测试一下,主要是想看看这样写有什么大毛病没有,能不能直接实现)。不然的话mybatisplus的优势真不太大。

博客表

(PS:我这里的数据库命名并不规范,但是先前没反应过来只能将错就错了,原来Django里面直接写得model习惯了,所以当时没反应过来)。


create table userblogs
(
    Id         bigint auto_increment comment '博文的ID',
    Title      varchar(24)   not null,
    UserId     bigint        not null comment '存储用户的ID,一对多嘛',
    BodyId     bigint        not null comment '存放博文内容 Id 的字段,到时候根据这个去找博客的具体内容',
    ShuoMing   varchar(256)  not null comment '博文的描述,本来我是想要实现前端自己截取一段摘要的
但是有点难',
    UpDateTime datetime      null,
    Autoer     varchar(24)   not null,
    CreateTime datetime      null,
    IsDelete   int default 0 not null comment '逻辑删除,0 表示没有 1 表示被删除',
    BlogPic    varchar(256)  null comment '博客的封面',
    Pass       int default 0 null comment '文章是否被审核通过 0 没有 1 通过',
    constraint UserBlogs_Id_uindex
        unique (Id)
)
    comment '用户上传的博文,我们这里存储的是博文内容的表的id,
由于根据阿里的规则数据库不允许外键,所以所有的外键由代码
层实现!
';
复制代码

频道表

目前我暂时砍掉了用户自己创建频道的功能,原因是用户消息系统没做,所以相关的评论收藏点赞都做不了。但是现在还是开发阶段嘛,这个是会不断更新的。(其实很大原因是我前端不想写了,烦呀)

那么这里是官方频道表


create table basechannel
(
    Id          bigint auto_increment comment '官方频道的主键',
    ChannelName varchar(24)  not null,
    ChannelDesc varchar(256) not null comment '频道的描述
',
    ChannelPic  varchar(128) null comment '频道封面,不过官方的频道封面是直接在前端就有的',
    constraint BaseChannel_ChannelName_uindex
        unique (ChannelName),
    constraint BaseChannel_Id_uindex
        unique (Id)
)
    comment '基本的官方频道';

alter table basechannel
    add primary key (Id);



复制代码

博客内容表

我单独把博客内容给拆分出一张表了

create table blogsbody
(
    Id         bigint auto_increment comment '博客内容的主键',
    Body       text   not null,
    UserBlogId bigint null,
    constraint BlogsBody_Id_uindex
        unique (Id)
)
    comment '博客的内容,这里存放的是博客的HTML代码,
前端完成了博客的页面转化';

alter table blogsbody
    add primary key (Id);

复制代码

拆出来是可以保存用户博客原有的记录,方便文章复原。

中间表

这个主要是频道和博客之间的关系表,其实在当前这个应该是一对多的关系,但是这里还是设计成多对多的关系吧。


create table blogandbasechannel
(
    Id          bigint auto_increment comment '中间表的主键',
    ChannelId   bigint not null,
    UserBlogsId bigint not null,
    constraint BlogAndBaseChannel_Id_uindex
        unique (Id)
)
    comment '博客和官方频道的中间表
';

alter table blogandbasechannel
    add primary key (Id);

复制代码

关系图

在这里插入图片描述

前端页面

这个写博客的前端页面我又改了一下。


<template>
  <div class="m_container">

    <!-- 博客内容 -->
    <div class="m_content">
      <el-form ref="editForm" status-icon :model="editForm"   label-width="80px">

        <input type="text" name="blogname" placeholder="请输入文章标题" v-model="editForm.title">
        <el-button  id="submit" type="primary" @click="tosubmitForm('editForm')">发布文章</el-button>


        <br>
        <br>
        <mavon-editor
          v-model="editForm.content"
          ref="md"
          @imgAdd="imgAdd"
          @change="change"
          style="min-height: 800px;width: 100%"
        />

      </el-form>
    </div>

    <!-- 对话框内容 -->
    <el-dialog title="发布文章" :visible.sync="dialogFormVisible" width="35%">
      <el-form :model="editForm" ref="editForm2">

        <el-form-item label="描述" prop="description">
          <textarea :maxlength="120"
                    v-model="editForm.description" style="  width: 80%;height: 150px;border-color: lightgrey;border-radius: 5px"
                    class="texti" placeholder="请编写博文描述(必填)"
          ></textarea>
        </el-form-item>
        <el-form-item label="分类专栏" prop="channel_id" :rules="{ required: true, message: '分类专栏不能为空', trigger: 'blur'}">

          <el-select v-model="editForm.channel_id" placeholder="请选择频道">
            <el-option v-for="(item,index) in baseChannels" :key="item.index" :label="item.channelName" :value="item.id + ''"></el-option>
          </el-select>

        </el-form-item>
        <el-form-item label="博客封面" prop="first_picture" >
          <el-input v-model="editForm.first_picture" placeholder="请输入封面URL"></el-input>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogFormVisible = false">取消</el-button>
        <el-button type="primary" @click="submitBlog('editForm2')">确定</el-button>
      </div>
    </el-dialog>




  </div>
</template>
<script>
import { mavonEditor } from 'mavon-editor'
import 'mavon-editor/dist/css/index.css'
import axios from "axios";

export default {
  name: "Writeboke",
  data() {
    return {
      editForm: {  //博客文章表单

        title: '',
        description: '',
        first_picture: '',
        content: '',
        channel_id: '',
        flag:'',
        published: null,

      },
      baseChannels: [],  // 进入页面的时候需要被加载的玩意儿
      success: null, //交互状态!

      editForm2: {  //用来校验的表单

        channel_id: null,
        flag:'',
        published: null,
      },
      oldtags:'',  //字符串类型的标签
      type:{  //分类专栏
        name:''
      },

      dialogFormVisible: false,  //控制发布博客对话框
      dialog2: false,  //控制新增分类专栏对话框


    }
  },
  mounted() {
    //获取频道,本来是打算直接在前端获取的,但是想了想还是算了吧,从服务器这边拿数据吧
    this.axios({
      url: "/boot/getbasechannels",
      method: 'post',
    }).then(res=>{
      this.baseChannels = res.data.baseChannels
      this.success = res.data.success
      if(this.success == '0'){
        alert("数据加载异常")
      }
    })

  },
  methods: {
    //去发布文章
    toSubmit() {
      this.dialogFormVisible = true
      this.initType()
    },
    //初始化文章专栏
    initType(){

    },

    submitForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          this.addNewType()
        } else {
          return false;
        }
      });
    },
    //校验博客基本内容表单
    tosubmitForm(formName) {
      if(this.editForm.title == ''){
        alert("文章标题不能为空")
        return
      }
      if(this.editForm.content == ''){
        alert("文章内容不能为空")
        return
      }

      this.toSubmit()

    },
    //校验发布博客表单,校验成功后发布博客
    submitBlog(formName) {
      if(this.editForm.description == ''){
        alert("文章描述不能为空")
      }
      this.$refs[formName].validate((valid) => {
        if (valid) {
          //发布博客

          this.axios({
            url: "/boot/saveblog",
            method: "post",
            data: {
              boke: this.editForm
            },
            headers:{

              "token": localStorage.getExpire("tokenhole"),
            }
          }).then(res=>{
            if(res.data.success == 0){
              alert("博客发送失败")
              return
            }
            alert("博客发布成功")
            this.dialogFormVisible = false

          })

          console.log("博客发布")

        } else {
          return false;
        }
      });
    },

    imgAdd(pos, $file){
      let param = new FormData()
      param.append("file",$file)
      this.axios({
        url: "/boot/boke/bokeImg",
        method: "post",
        data: param,
        headers:{
          'Content-Type': 'multipart/form-data',
          "token": localStorage.getExpire("tokenhole"),
        }
      }).then(res=>{
        if(res.data.success == 0){
          alert("图片上传失败")
          return
        }
        let url = "/boot"+ res.data.bokeImg
        this.$refs.md.$img2Url(pos,url)

      })

    },


    // 所有操作都会被解析重新渲染
    change(value, render){        //value为编辑器中的实际内容,即markdown的内容,render为被解析成的html的内容
      this.html = render;
    },
    // 提交
    submit(){                    //点击提交后既可以获取html内容,又可以获得markdown的内容,之后存入到服务端就可以了
      console.log(this.editForm.content);
      console.log(this.html);
    },

  }
}
</script>

<style>
.m_container{
  margin-top: 20px;
}
.el-tag + .el-tag {
  margin-left: 10px;
}
.button-new-tag {
  margin-left: 10px;
  height: 32px;
  line-height: 30px;
  padding-top: 0;
  padding-bottom: 0;
}
.input-new-tag {
  width: 90px;
  margin-left: 10px;
  vertical-align: bottom;
}



input {

  width: 85%;
  height: 30px;
  border-width: 2px;
  border-radius: 5px;
  border-color: #00c4ff;
  border-bottom-color: #2C7EEA;
  color: #586e75;
  font-size: 15px;

}

#submit {
  width: 10%;
  height: 35px;
  border-width: 0px;
  margin-left: 3%;
  border-radius: 10px;
  background: #1E90FF;
  cursor: pointer;
  outline: none;
  color: white;
  font-size: 17px;
}
#submit:hover {
  background-color: #1E90FF;
  box-shadow: 0 4px 0 powderblue;
}

.texti:focus{
  border-color: #1e88e1;
  outline: 0;
  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);
  box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)
}
textarea {
  resize: none;

}
</style>
复制代码

主要是搞了个弹出,然后显示一下提交的玩意。 这里前端又两个接口,要注意,一个是获取 官方频道的,一个就是提交的。

后端频道接口

这个就是获取频道的没啥

    @PostMapping("/getbasechannels")
    public BaseChannelMessage GetAllChannels(){
        try {
            List<BaseChannel> baseChannels = baseChannelServer.GetAllChannel();
            baseChannelMessage.setSuccess(1);
            baseChannelMessage.setBaseChannels(baseChannels);
            return baseChannelMessage;
        }catch (Exception e){
            baseChannelMessage.setSuccess(0);
            return baseChannelMessage;
        }
    }



复制代码

然后在前端显示的效果就是 在这里插入图片描述

后端博文保存

这个其实也没啥,要注意的就是用了事务。

@EnableTransactionManagement 在你的配置类开启 然后使用 在这里插入图片描述

效果

这里的话接口还没写完,主要是前端还有点毛病没办法直观演示。 在这里插入图片描述

猜你喜欢

转载自juejin.im/post/7041831632734519332