一、前言
在上篇博客中,介绍了RuoYi中如何实现文件的上传与下载,那么这篇博客讲一下如何在RuoYi中使用富文本编辑器,这部分的内容是向B站程序员青戈学习的,当然我这里就会把学到的内容做一个总结,当然也会说一下在RuoYi中使用富文本编辑器会出现的一些问题。希望对大家有所帮助!
二、准备工作
1、安装wangdietor
npm install @wangeditor/editor --save
2、导入相关的包
三、Vue代码
首先我想说一下使用这个wangdietor富文本编辑器的主要思路:先对需要使用wangdietor的字段绑定标签id=''editor",然后使用我们自己写的setRichText()函数对编辑器进行初始化和对一些图片、视频上传的接口进行自定义;最后要将富文本编辑器的内容存在数据中。当然数据显示的时候可能会有一些标签,此时我们可以通过按钮,出现弹窗来规避这种情况。
核心代码如下:
setRichText(){
this.$nextTick( () => {
this.editor=new E('#editor')//创建对象
this.editor.highlight = hljs//代码高亮
this.editor.config.uploadImgServer = process.env.VUE_APP_BASE_API+'/file/editor/upload'//图片上传的接口
this.editor.config.uploadFileName = 'file'
this.editor.config.uploadImgParams = {
type:"img"
}
this.editor.config.uploadVideoServer = process.env.VUE_APP_BASE_API+"/file/editor/upload"//视频上传的接口
this.editor.config.uploadVideoName = 'file'
this.editor.config.uploadVideoParams = {
type:"video"
}
this.editor.create()
})
}
四、Java代码
后端代码主要就是在图片和视频的上传了,下面是wangdietor规定的图片和视频的上传的格式
核心代码如下:
@RestController
@Api(tags = "文件上传与下载模块")
@RequestMapping("/file")
public class FileController extends BaseController {
@Value("${ip:localhost}")
String ip;//通过配置文件拿到ip
@Value("${server.port}")
String port;
private static final String ROOT_PATH = System.getProperty("user.dir")+ File.separator+"files";//文件根目录
@PostMapping("/editor/upload")
public Dict editorUpload(MultipartFile file,@RequestParam String type) throws IOException {
System.out.println(6767);
String originalFilename = file.getOriginalFilename();
String mainName = FileUtil.mainName(originalFilename);
String extName = FileUtil.extName(originalFilename);
if(!FileUtil.exist(ROOT_PATH)){
FileUtil.mkdir(ROOT_PATH);
}
if(FileUtil.exist(ROOT_PATH+File.separator+originalFilename)){
originalFilename=System.currentTimeMillis()+"_"+mainName+"."+extName;
}
File saveFile = new File(ROOT_PATH + File.separator + originalFilename);
file.transferTo(saveFile);
String url ="http://"+ip+":"+port+"/file/download/"+originalFilename;
if("img".equals(type)){//上传图片
return Dict.create().set("errno",0).set("data", CollUtil.newArrayList(Dict.create().set("url",url)));
}else if("video".equals(type)){
return Dict.create().set("errno",0).set("data", Dict.create().set("url",url));
}
return Dict.create().set("errno",0);
}
@ApiOperation(value = "文件下载")
@GetMapping("/download/{fileName}")
public void download(@PathVariable String fileName, HttpServletResponse response) throws IOException {
// response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName,"UTF-8"));//文件下载
// response.addHeader("Content-Disposition", "inline;filename=" + URLEncoder.encode(fileName,"UTF-8"));//文件预览
String filePath = ROOT_PATH+File.separator+fileName;//拿到文件的路径
if(!FileUtil.exist(filePath)){//文件不存在,就不用管,因为没有东西可写
return;
}
byte[] bytes = FileUtil.readBytes(filePath);//使用FileUtil从filePath中去读取文件
ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(bytes);//把文件的字节数写出去
outputStream.flush();//刷新一下
outputStream.close();//一定要关闭文件流
}
}
后端报错
如果出现这个错误,我们改一下对应的XSS中的内容即可
效果图
全部代码
以下的代码是包含了上述效果图中的所有代码,至于一些按钮、弹窗的设计、数据的请求与显示在该代码中都有,都是一些比较小的点,我就不详细介绍了,大家感兴趣的话就在评论区评论就好了,我看到了都会回复的。
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="学号" prop="stuNum">
<el-input
v-model="queryParams.stuNum"
placeholder="请输入学号"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="姓名" prop="stuName">
<el-input
v-model="queryParams.stuName"
placeholder="请输入姓名"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['system:student:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['system:student:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:student:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
v-hasPermi="['system:student:export']"
>导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="studentList" @selection-change="handleSelectionChange" @close="closeDialog()">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="表编号" align="center" prop="tableId" />
<el-table-column label="学号" align="center" prop="stuNum" />
<el-table-column label="姓名" align="center" prop="stuName" />
<el-table-column label="性别" align="center" prop="stuSex" />
<el-table-column label="爱好" align="center" prop="stuHobby" >
<template v-slot="scope">
<el-button type="primary" size="mini" @click="handleStuHobbyContent(scope.row)">显示</el-button>
</template>
</el-table-column>
<el-table-column label="家庭信息">
<template slot-scope="scope">
<el-button type="success" size="mini" @click="handleJump(scope.row)">按钮</el-button>
</template>
</el-table-column>
<el-table-column label="头像上传">
<template v-slot="scope">
<el-upload
action="http://localhost:8080/file/upload"
:show-file-list="false"
:on-success="(row,file,filelist) => handleTableFileUpload(scope.row,file,filelist)"
>
<el-button slot="trigger" size="mini" type="primary">选取文件</el-button>
</el-upload>
</template>
</el-table-column>
<el-table-column label="头像" align="center" prop="stuAvatar" >
<template v-slot="scope">
<el-image v-if="scope.row.stuAvatar" :src="scope.row.stuAvatar" style="with:50px;height: 50px"></el-image>
<div>
<el-button type="success" size="mini" @click="preview(scope.row.stuAvatar)">预览</el-button>
</div>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['system:student:edit']"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['system:student:remove']"
>删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改学生信息列表对话框 -->
<el-dialog :title="title" :visible.sync="open" width="60%" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="学号" prop="stuNum">
<el-input v-model="form.stuNum" placeholder="请输入学号" />
</el-form-item>
<el-form-item label="姓名" prop="stuName">
<el-input v-model="form.stuName" placeholder="请输入姓名" />
</el-form-item>
<el-form-item label="性别" prop="stuSex">
<el-input v-model="form.stuSex" placeholder="请输入性别" />
</el-form-item>
<el-form-item label="爱好" prop="stuHobby" class="w-e-text">
<div id="editor"></div>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</el-dialog>
<div style="margin:10px 0">
<el-upload
class="upload-demo"
drag
action="http://localhost:8080/file/upload"
:on-success="handleMultipleUpload"
multiple>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>
</div>
<el-dialog title="爱好" :visible.sync="open1" width="60%" append-to-body :close-on-click-modal="false">
<el-card class="w-e-text" >
<div v-html="stuHobbyContent"></div>
</el-card>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="open1 = false">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listStudent, getStudent, delStudent, addStudent, updateStudent } from "@/api/system/student";
import E from "wangeditor"
import hljs from "highlight.js"
export default {
name: "Student",
data() {
return {
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 学生信息列表表格数据
studentList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
stuNum: null,
stuName: null,
},
// 表单参数
form: {},
// 表单校验
rules: {
stuNum: [
{ required: true, message: "学号不能为空", trigger: "blur" }
],
stuName: [
{ required: true, message: "姓名不能为空", trigger: "blur" }
],
},
urls:'',
editor:null,
open1:false,
stuHobbyContent:''
};
},
created() {
this.getList();
},
methods: {
handleStuHobbyContent(row){
this.stuHobbyContent=row.stuHobby;
this.open1=true;
},
setRichText(){
this.$nextTick( () => {
this.editor=new E('#editor')
this.editor.highlight = hljs
this.editor.config.uploadImgServer = process.env.VUE_APP_BASE_API+'/file/editor/upload'
this.editor.config.uploadFileName = 'file'
this.editor.config.uploadImgParams = {
type:"img"
}
this.editor.config.uploadVideoServer = process.env.VUE_APP_BASE_API+"/file/editor/upload"
this.editor.config.uploadVideoName = 'file'
this.editor.config.uploadVideoParams = {
type:"video"
}
this.editor.create()//
})
},
closeDialog() {
this.editor.destroy()
this.editor = null
},
handleMultipleUpload(response,file,fileList){
this.urls=fileList.map(v => v.response?.msg)
console.log(this.urls)//拿到我们的图片的路径
},
preview(url){
window.open(url)
},
handleTableFileUpload(row,file,fileList){
console.log(row,file)
row.stuAvatar=file.response.msg//注意我们使用的是RuoYi框架中的AjaxResult结果集,返回的数据是在response下的msg中
//触发更新
//使用RuoYi中封装好的updateStudent()函数,将当前对象更新
updateStudent(row).then(response => {
if(response.code=='200'){
this.$message.success("上传成功")
}else{
this.$message.success("上传失败")
}
this.form = response.data;
});
},
/** 查询学生信息列表列表 */
getList() {
this.loading = true;
listStudent(this.queryParams).then(response => {
this.studentList = response.rows;
this.total = response.total;
this.loading = false;
});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
tableId: null,
stuNum: null,
stuName: null,
stuSex: null,
stuHobby: null,
stuAvatar: null,
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.tableId)
this.single = selection.length!==1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加学生信息列表";
this.setRichText();
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
this.setRichText();
setTimeout(()=>{//延时加载
this.editor.txt.html(row.stuHobby)
},0);
const tableId = row.tableId || this.ids
getStudent(tableId).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改学生信息列表";
});
},
/** 页面跳转按钮操作 */
handleJump(row){
const tableId = row.tableId || this.ids
getStudent(tableId).then(response => {
this.$router.push("/student/family-data/index/"+tableId)
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
let content = this.editor.txt.html();
this.form.stuHobby=content;
if (this.form.tableId != null) {
updateStudent(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
addStudent(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const tableIds = row.tableId || this.ids;
this.$modal.confirm('是否确认删除学生信息列表编号为"' + tableIds + '"的数据项?').then(function() {
return delStudent(tableIds);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
this.download('system/student/export', {
...this.queryParams
}, `student_${new Date().getTime()}.xlsx`)
}
}
};
</script>
五、总结
学无止尽,大家加油哦!希望我们都能在顶峰想见!