前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >补档 后端开发日常:国家电网CMS系统

补档 后端开发日常:国家电网CMS系统

作者头像
DioxideCN
发布2022-08-05 19:51:06
8260
发布2022-08-05 19:51:06
举报

Vue开发日常:开发国家电网CMS系统

引言

在我上一个 WordPress 博客中写过,后来这个服务器拿去做 Springboot 测试之后数据库就炸了,然后也没备份,文章就全没了。所以这是一期补档!

项目介绍

这是 国家电网 下子公司委派开发的 扬州市充电桩后台管理系统 开发任务。本人主要负责其中的 CMS 模块开发。 你问我什么是 CMS ?那我一定会怀疑你没用过百度。

项目分析

鲁迅说过:要想做好项目必先研究项目结构

  • 后端:使用 SSM Tomcat8.5.73
  • 后台:使用 Vue2 ElementUI Vendor
  • 数据库:MySQL5.7
image-1651836212296
image-1651836212296
  • 目标:在公告管理系统中重新开发 CMS 富文本系统并能在前端中同步显示。需要考虑 xss 防注入的安全问题。

如何实现

我们在学前班学习 Vue 时,鱿鱼须(不是) 老师就教过我们如何使用 Vue 的 组件通讯 ,这里就不在赘述其原理。 我们将使用 WangEditor v4 进行架构(小广告: WangEditor v4-lite 是我基于 WangEditor v4 重新开发的一款更精致的富文本编辑器,你可以在 👉🏻这里 了解到它)。 防 xss 注入策略,我们这里使用 URI code 进行转码并将所有内容移动至 "" 中来规避不必要的 html 标签的出现。

心动不如行动

  1. 实例化我们的 WangEditor 组件,通过 Vue 继承后我们开始处理其中的逻辑:
代码语言:javascript
复制
// 这个是子组件向父组件传值的组件
const Editor = Vue.extend({
    template: `
        <div id="div_mount" style="width: 80%;">
            <p>在此处输入文本...</p>
        </div>`,
    mounted() {
        const E = window.wangEditor
        const editor = new E('#div_mount')
        editor.config.menus = [
            'bold',
            'head',
            'link',
            'italic',
            'underline',
            'image'
        ]
        editor.config.uploadImgShowBase64 = true
        editor.create()
    }
})
// 同样的,父组件向子组件传值也用一样的方法构造
  1. 这样我们就构造好了一个 we 富文本编辑器,我们将它注入到 Vue 原型中,并构造他的逻辑:
代码语言:javascript
复制
var vue = new Vue({
    el: "#app",
    components: {
        Editor,
        Update
    },
    data: function() {
        return {
            editor_main:'',
        	// 查询字段
            title:'',
            // 表格数据
            tableData: [],
            // 勾选
            multipleSelection: [],
            // 分页相关
            totalSize: 0,
            pageIndex: 1,
            pageSize: 15,
            // 门户信息类型
            allInfoType: [],
            // 门户信息来源
            allInfoSource: [],
			// 表单
            insertForm: { // 插入
                id:'',
                title:'',
                keyWords:'',
                content:'', // 对象内容数组
                type:'',
                picUrl:'',
                attachmentUrl:'',
                crtDate:'',
                infoSource:'',
                externalLinks:''
            },
            updateForm: { // 更新
            	id:'',
            	title:'',
            	keyWords:'',
            	content: '', // 更新内容
            	type:'',
            	picUrl:'',
            	attachmentUrl:'',
            	crtDate:'',
            	infoSource:'',
            	externalLinks:''
            },
            ruleOne: {
            	title: [{
                    required: true,
                    message: '请输入',
                    trigger: 'blur'
                }],
            	keyWords: [{
                    required: true,
                    message: '请输入',
                    trigger: 'blur'
                }],
            	content: [{
                }],
            	type: [{
                    required: true,
                    message: '请输入',
                    trigger: 'blur'
                }],
            	picUrl: [{
                }],
            	attachmentUrl: [{
                }],
            	infoSource: [{
                    required: true,
                    message: '请输入',
                    trigger: 'blur'
                }]
            },
            formLabelWidth: '120px',
            // 对话框
            dialogAddVisible: false,
            dialogModityVisible: false,
            // 上传相关
            uploadFileUrl: 'portalInfo/upload',
            uploadParamPic: {
                subPath: 'portalPic'
            },
            uploadParamAtta: {
                subPath: 'portalAttachment'
            }
        }
    },
    mounted() {
        this.refresh();
    },
    methods: {
        replaceM:function(input){
            return input.replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace('alt','src');
        },
    	search: function() {...},
        refresh: function() {...},
        adjustTableTransDic: function(theTableData) {...},
        transInfoType: function(code) {...},
        transInfoSource: function(code) {...},
        // 列选中
        rowClick: function(row, event, column) {...},
        toggleSelection: function(rows) {...},
        handleSelectionChange: function(val) {...},
        // 分页
        handleSizeChange: function(val) {...},
        handleCurrentChange: function(val) {...},
        rowModify: function(rowItem) {...},
        addClose: function(done) {...},
        modityClose: function(done) {...},
        deleteBatch: function() {...},

        updateHandle: function(formName) { // 更新方法
            var that = this;
            this.updateForm.content = document.getElementById('div_mount2').firstChild.nextSibling.firstChild.innerHTML;
            this.$refs[formName].validate((valid) => {
            	if (valid) {
		            $.post("portalInfo/update", this.updateForm, function(result) {
		                if (result > 0) {
		                	that.$message({
		              			showClose: true,
		                        message: '修改成功!',
		              		});
		                } else {
		                	that.$message({
		              			showClose: true,
		                        message: '修改失败!',
		              		});
		                }
		                that.closeUpdatePop();
		            });
		        }
            });
        },
        insertHandle: function(formName) { // 插入方法
            var that = this;
            this.insertForm.content = document.getElementById('div_mount').firstChild.nextSibling.firstChild.innerHTML;
            this.$refs[formName].validate((valid) => {
            	if (valid) {
  	           		 $.post("portalInfo/save", this.insertForm, function(result) {
  	           			if(result ==3){
  	           				that.$message({
  		                        message: '添加失败,机构代码已存在!',
  		              		});
  	           			}else if (result > 0) {
  		                	that.$message({
  		              			showClose: true,
  		                        message: '添加成功!',
  		              		});
  		                }else {
  		                	that.$message({
  		              			showClose: true,
  		                        message: '添加失败!',
  		              		});
  		                }
  	           			that.closeInsertPop();
  	           		 });
	            }
            });
        },

        closeInsertPop: function() {...},
        closeUpdatePop: function() {...},

        // 上传成功后的回调
        uploadSuccessInsertPic: function(response, file, fileList) {...},
        uploadSuccessInsertAtta: function(response, file, fileList) {...},
        uploadSuccessUpdatePic: function(response, file, fileList) {...},
        uploadSuccessUpdateAtta: function(response, file, fileList) {...},
        // 上传错误
        uploadError: function(response, file, fileList) {...},

        // 清除上传
        clearUpdatePic: function() {...},
        clearUpdateFile: function() {...},
        clearInsertPic: function() {...},
        clearInsertFile: function() {...}
    }
});

现在我们来分析其中的核心方法:

replaceM()

该方法在提交表单时用来替换所有的 <> 字符来防范 xss 注入。

updateHandle()

该方法旨在更新公告内容,很简单,不赘述,看代码就行。

insertHandle()

该方法旨在插入行的公告,很简单,不赘述,看代码就行。

通讯传值

这里的 insertHandle() 与 updateHandle() 方法使用的是 dom 节点操作法来获取内容 document.get......Child.innerHtml 随后将内容传递给 Vue 的数据 this.inserForm.content 再通过 elmentUI 的携带数据上传 v-model 双向绑定的功能提交至后端处理。

代码语言:javascript
复制
<el-form-item label="内容" prop="content">
  <el-row>
    <el-col :span="24">
      <Editor></Editor>
    </el-col>
  </el-row>
</el-form-item>

获得公告并修改

这里,我们使用父子组件传值来处理。先看源码:

代码语言:javascript
复制
<!-- 修改弹窗 -->
<el-dialog v-if="dialogModityVisible" title="修改门户信息" :visible.sync="dialogModityVisible" :before-close="closeUpdatePop" :close-on-click-modal="false" width="50%">
    <el-form :model="updateForm" ref="updateForm" :rules="ruleOne" :label-width="formLabelWidth">
        <el-form-item label="信息标题" prop="title">
        	<el-input v-model="updateForm.title" auto-complete="off" class="width-form-input"></el-input>
        </el-form-item>
        <el-form-item label="关键字" prop="keyWords">
        	<el-input v-model="updateForm.keyWords" auto-complete="off" class="width-form-input"></el-input>
        </el-form-item>

        <el-form-item label="内容" prop="content">
                <!--  获取数据源  -->
                <Update :demo="updateForm.content" v-html="replaceM(updateForm.content)"></Update>
        <!--  <el-input class="width-form-input" type="textarea" :rows="10" v-model="updateForm.content" auto-complete="off">  -->
        <!--  </el-input>  -->
        </el-form-item>

        <el-form-item label="信息类型" prop="type">
                    <el-select v-model="updateForm.type" placeholder="请选择" :filterable="true" class="width-form-input">
                        <el-option v-for="item in allInfoType" :label="item.NAME" :key="item.CODE"
                            :value="item.CODE">
                        </el-option>
                    </el-select>
        </el-form-item>
        <el-form-item label="信息来源" prop="infoSource">
                    <el-select v-model="updateForm.infoSource" placeholder="请选择" :filterable="true" class="width-form-input">
                        <el-option v-for="item in allInfoSource" :label="item.NAME" :key="item.CODE"
                            :value="item.CODE">
                        </el-option>
                    </el-select>
        </el-form-item>
        <el-form-item label="外部链接" prop="externalLinks">
                    <el-input v-model="updateForm.externalLinks" auto-complete="off" class="width-form-input"></el-input>
        </el-form-item>
        <el-form-item label="图片地址" prop="picUrl">
            <el-row>
                <el-col :span="11" style="margin-right: 5px">
                    <el-input v-model="updateForm.picUrl" auto-complete="off" readonly="readonly"></el-input>
                </el-col>
                <el-col :span="4" style="margin-right: 5px">
                    <el-upload ref="uploadElPicUpdate" :action="uploadFileUrl" :data="uploadParamPic" :limit="1"
                        :auto-upload="true" :show-file-list="false" :on-error="uploadError"
                        :on-success="uploadSuccessUpdatePic">
                        <el-button size="small" type="primary" class="el-icon-upload"
                            style="width: 100%; height:40px;">点击上传</el-button>
                    </el-upload>
                </el-col>
                <el-col :span="4">
                    <el-button size="small" type="warning" style="width: 100%; height:40px;"
                        @click="clearUpdatePic">清除</el-button>
                </el-col>
            </el-row>
        </el-form-item>
        <el-form-item label="附件" prop="attachmentUrl">
            <el-row>
                <el-col :span="11" style="margin-right: 5px">
                    <el-input v-model="updateForm.attachmentUrl" auto-complete="off" readonly="readonly">
                    </el-input>
                </el-col>
                <el-col :span="4" style="margin-right: 5px">
                    <el-upload ref="uploadElAttaUpdate" :action="uploadFileUrl" :data="uploadParamAtta"
                        :limit="1" :auto-upload="true" :show-file-list="false" :on-error="uploadError"
                        :on-success="uploadSuccessUpdateAtta">
                        <el-button size="small" type="primary" class="el-icon-upload"
                            style="width: 100%; height:40px;">点击上传</el-button>
                    </el-upload>
                </el-col>
                <el-col :span="4">
                    <el-button size="small" type="warning" style="width: 100%; height:40px;"
                        @click="clearUpdateFile">清除</el-button>
                </el-col>
            </el-row>
        </el-form-item>
        <el-form-item label="创建时间" prop="crtDate">
                    <el-input :disabled="true" v-model="updateForm.crtDate" class="width-form-input"></el-input>
        </el-form-item>
    </el-form>

    <div slot="footer">
        <el-button @click="closeUpdatePop">取消</el-button>
        <el-button type="primary" @click="updateHandle('updateForm')">确定</el-button>
    </div>
</el-dialog>

你一定注意到 <Update :demo="updateForm.content" v-html="replaceM(updateForm.content)"></Update> 这一行了,这里父子组件传递了 demo 这个数据值。 在执行方法时我们直接拿到了原先的公告内容,在提交时通过 updateHandle() 方法进行了处理。

反馈至前端

这里很简单,只讲原理。通过 Spring 提供的 数据库数据获取 接口拿到公告内容后传递给 Vue 原型中的数组。 使用 v-for 与 :key 属性罗列出所有的公告内容即可。

总结

这是一个非常简单的项目,主要使用了 Vue 的几个知识点。需要突破的难点为构造一个 CMS 编辑器并注入到 Vue 的组件中。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-05-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Vue开发日常:开发国家电网CMS系统
    • 引言
      • 项目介绍
    • 项目分析
      • 如何实现
        • 心动不如行动
          • replaceM()
          • updateHandle()
          • insertHandle()
          • 通讯传值
        • 获得公告并修改
          • 反馈至前端
            • 总结
            相关产品与服务
            数据库
            云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档