Vue+SpringBoot 前后端分离实战(mybatisplus多表分页查询+博客显示)
文章目录前言对博客封面的检测多表查询分页使用注解使用注解分页器博客显示显示图片尺寸代码高亮总结前言到今天总算是把最基本的功能做出来了,前面修修改改了不少主要是前端先前有点小毛病,调试花费了不少时间。之后就是关于在mybatisplus里面使用纯面对对象的方式来实现多表查询,我测试了最后决定还是手写sql香,对于稍微复杂一点的查询(多表),如果采用纯面对对象的写法的话有点难,而且很麻烦,还不如直接用
前言
到今天总算是把最基本的功能做出来了,前面修修改改了不少主要是前端先前有点小毛病,调试花费了不少时间。之后就是关于在mybatisplus里面使用纯面对对象的方式来实现多表查询,我测试了最后决定还是手写sql香,对于稍微复杂一点的查询(多表),如果采用纯面对对象的写法的话有点难,而且很麻烦,还不如直接用 xml文件映射过去。除此之外修复了几个小bug
对博客封面的检测
这个是先前偷懒没有去做,后面才发现的,其实我也是忘了,有些网站是不允许,js加载图片的,由于vue其实使用js动态加载图片的所以,有些网站有防护机制,所以我这边就必须检测一下那个图片是否可以被加载。这很重要,不然显示不出来。
这里上传博客的前端代码修改如下(其实主要还是前端)
<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,
},
okimg: 1,
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: {
//去发布文章
isokPic(){
this.axios({
url:this.editForm.first_picture,
}).catch(error=>{
this.okimg = 0
})
},
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("文章描述不能为空")
return
}
if(this.editForm.channel_id == ''){
alert("请选择分类")
return;
}
this.isokPic()
console.log(this.okimg)
setTimeout(this.sendBlog,2000)
},
sendBlog(){
if(this.okimg == 1){
//发布博客
this.editForm.content = this.html;
this.axios({
url: "/boot/userblog/saveblog",
method: "post",
data: {
boke: this.editForm
},
headers:{
"token": localStorage.getExpire("tokenhole"),
}
}).then(res=>{
if(res.data.success == 0){
this.dialogFormVisible = false
alert("博客发送失败")
return
}
alert("博客发布成功")
this.dialogFormVisible = false
})
console.log("博客发布")
} else {
return false;
}
if(this.okimg == 0){
alert("目标图片地址拒绝了我们的访问,请更换图片源!")
return
}
},
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>
可以看到我这里是故意沉睡了2秒,主要一方面是为了让那个去验证一下图片是否可以被访问,另一方面是故意让用户稍等的,防止爬虫,后面我会再搞个等待加载的玩意。
多表查询分页
那么开始进入正题,前面我介绍了我们整个表的结构,所以这里就不复述了。
需要使用到多表的地方就是那个 频道表和那个博客表,整个也就是整体所在了。
这里提供两个方法
使用注解
整个简单,我们直接在那个mapper文件里面写注解就好了。
@Mapper
public interface BaseChannelMapper extends BaseMapper<BaseChannel> {
@Select("select * from userblogs as blog inner join blogandbasechannel as channel on channel.ChannelId=#{id}")
IPage<UserBlogs> GetChannelBlogs(@Param("page") IPage<UserBlogs> page, @Param("id") int id);
}
使用xml配置文件
这里需要注意几个点。
首先是制定 你的 xml 放置目录,让myabtisplus 扫描到。
我这里放在
所以修改配置文件
mybatis-plus:
global-config:
db-config:
id-type: auto
table-underline: false
mapper-locations:
- classpath*:/mapping/*.xml
configuration:
map-underscore-to-camel-case: false
之后愉快的去写那个xml了
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.huterox.whiteholeboot.Entity.Mapper.BaseMapper.BaseChannelMapper">
<!--sql-->
<select id="GetChannelBlogs" resultType="com.huterox.whiteholeboot.Entity.Pojo.BokePojo.UserBlogs">
select * from userblogs as blog inner join blogandbasechannel as channel on channel.ChannelId=#{id} and blog.Id = channel.UserBlogsId
</select>
</mapper>
分页器
之后是分页器,单表的这个好说,主要是咱们自己定义的方法的分页器,这个很重要。
这个其实也很简单,但是注意细节。
ok 在此之前,不管是单表还是多表,咱们都得去开启咱们的配置
@Configuration
@EnableTransactionManagement
public class MyBatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor(){
PaginationInterceptor page = new PaginationInterceptor();
page.setDialectType("mysql");
return page;
}
}
之后在咱们的那个 mapper里面必须这样写
@Mapper
public interface BaseChannelMapper extends BaseMapper<BaseChannel> {
@Select("select * from userblogs as blog inner join blogandbasechannel as channel on channel.ChannelId=#{id}")
IPage<UserBlogs> GetChannelBlogs(@Param("page") IPage<UserBlogs> page, @Param("id") int id);
}
注意返回的类型,切记。我的是 mybatisplus 3.x 先前百度了一些方法,最后发现好像只有这个方法跑通了,至于还有没有其他的方式我也不太清楚,返回类型必须是 IPage 别的不行,至少我这里是这样的。
然后就是使用嘛。
public Page GetChannelBlogs(int channel_id,int page,int size){
Page<UserBlogs> page2 = new Page<>(page,size);
baseChannelMapper.GetChannelBlogs(page2,channel_id);
return page2;
}
之后就是其他的查询,都是很简单的。
博客显示
这个主要还是前端的问题。
这里说两个
显示图片尺寸
由于我这边的话是把html文件放到我们的数据库里面了,所以我们可以直接加载,但是是放在 v-html
里面的,所以我们要想修改里面的样式就必须这样(假设我修改图片样式,原来的太丑了)
/deep/ img{
width: 70%;
height: 400px;
margin-left: 15%;
margin-top: 2%;
}
加上 /deep/
代码高亮
这个主要是实现这个效果
这个其实也简单,我搞了小半天。
导入这个玩意
import 'highlight.js/styles/googlecode.css'
最后来看看整体代码吧
<template>
<div style="background-color: #f8f8e7">
<el-row class="main" type="flex" justify="center">
<el-col :span="16">
<div style="margin: 0 auto">
<h3>{{title}}</h3>
</div>
<br>
<h5>
作者:{{author}}
</h5>
<h4>
<i class="el-icon-time"></i>: {{time}}
</h4>
<br>
<p> 原文: </p>
<div class="markdown-body" style="border-radius: 5px;border: solid 2px #47aeef" v-model="body" v-html="body"></div>
</el-col>
</el-row>
</div>
</template>
<script>
import 'mavon-editor/dist/css/index.css'
import 'highlight.js/styles/googlecode.css'
export default {
name: 'article',
data(){
return{
author :this.$route.params.autoer,
blogsId: this.$route.params.blogsId,
title: this.$route.params.title,
time: this.$route.params.time,
body: null
}
},
mounted() {
this.axios({
url: "/boot/base/viewblog",
params:{
BlogId:this.blogsId
}
}).then(res=>{
this.body = res.data.body.body
if(res.data.success == "0"){
alert("博客加载异常,请重试~")
}
})
}
}
</script>
<style scoped>
#artcle-info {
padding: 20px;
background-image: url(../assets/vue.jpg);
margin-bottom: 40px;
}
#artcle-info .abstract {
color: #ffffff;
border-left: 3px solid #F56C6C;
padding: 10px;
background-color: rgba(126, 129, 135, 0.3);
}
#artcle-info .timeAndView {
padding: 20px;
line-height: 30px;
font-size: 16px;
color: #ffffff;
}
pre.has {
color: #ffffff;
background-color: rgba(0, 0, 0, 0.8);
}
img.has {
width: 100%;
}
#statement {
border-left: 3px solid #F56C6C;
padding: 20px;
background-color: #EBEEF5;
}
/deep/ img{
width: 70%;
height: 400px;
margin-left: 15%;
margin-top: 2%;
}
</style>
总结
到目前为止的话,最基础的功能做好了,勉强能用来,但是目前还是没有时间,所以先到这里,并且我现在还缺少后台管理 的前端代码所以没法继续做下去了(这里如果你有现成的后台管理模板最好是vue 2x的话,如果可以的话,分享分享呗~~)。目前的效果的话大概是这个样子的(后面再整理整理推送github gitee):
首页
文章页
写博客页
频道页面
进入频道
个人中心
趣味工具
交换友链
更多推荐
所有评论(0)