简介
通常咱们批改某个服务的配置文件的时候,须要登入服务器,进入指定目录而后对配置文件例如xml
进行批改,偶然一次操作还能够,然而频繁操作的确有点麻烦。
所以咱们间接把这项性能放到前端界面来进行操作,来晋升运维的效率。
思路
- 后端通过I/O来将服务端XML文件读取并发送给前端
- 前端把接管回来的xml文件在前端web编辑器里进行渲染
- 前端把批改过的xml文件再次发送给后端
- 后端把接管回来的xml写回服务端配置文件
依赖
1.springBoot
2.dom4j(xml读写库)
3.vue-element-admin
4.ace.js(web编辑器)
实现
后端
导入依赖
<dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1</version></dependency>
在resources
目录下新建hdfs-site.xml
,并写入如下内容进行测试
测试demo中门路为写死的,后续可改为动静配置即可
<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet type="text/xsl" href="configuration.xsl"?><configuration> <!-- 指定HDFS正本的数量 --> <property> <name>dfs.replication</name> <value>1.2</value> </property> <!-- 指定Hadoop辅助名称节点主机配置 --> <property> <name>dfs.namenode.secondary.http-address</name> <value>java151:50090</value> </property> <property> <name>dfs.webhdfs.enabled</name> <value>true</value> </property> </configuration>
新建XmlUtil
工具类
import org.dom4j.*;import org.dom4j.io.*;import java.io.*;public class XmlUtil { /** * 获取xml文档 */ public static Document getDocument(String filename) { File xmlFile = new File(filename); Document document = null; if (xmlFile.exists()) { try { SAXReader saxReader = new SAXReader(); document = saxReader.read(xmlFile); } catch (Exception e) { e.printStackTrace(); } } return document; } /** * 写入xml节点,没有就新建,存在就笼罩 */ public static void coverElement(String filePath, Document document) throws Exception { if (document != null) { OutputFormat format = OutputFormat.createPrettyPrint(); File xmlFile = new File(filePath); format.setEncoding("UTF-8"); XMLWriter writer = new XMLWriter(new FileOutputStream(xmlFile), format); writer.write(document); writer.close(); } }}
新建getXmlFile
接口,借助dom4j
的asXML()
将xml以字符串
模式返回给前端,Result
类自行依据我的项目返回需要实现即可
@ApiOperation(value = "获取xml文件", notes = "获取xml文件")@GetMapping(value = "/getXmlFile")public Object getXmlFile(HttpServletRequest request, HttpServletResponse response) throws Exception { String filePath = "src/main/resources/hdfs-site.xml"; Document document = XmlUtil.getDocument(filePath); String docXmlText = document.asXML();//输入xml字符串 return new Result(true, 20000, "获取hdfs-site.xml胜利", docXmlText);}
新建putXmlFile
接口,借助DocumentHelper.parseText
将前端返回的字符串转为xml
@ApiOperation(value = "批改xml文件", notes = "批改xml文件")@ResponseBody()@PostMapping(value = "/putXmlFile")public Object putXmlFile(@RequestBody XmlDO body, HttpServletResponse response) throws Exception { Document document = DocumentHelper.parseText(body.getData());//字符串转xml String filePath = "src/main/resources/hdfs-site.xml"; XmlUtil.coverElement(filePath, document); return new Result(true, 20000, "批改hdfs-site.xml胜利", body.getData());}
XmlDO
import lombok.Data;@Datapublic class XmlDO { private String type; private String data;}
前端
插件依赖
"xml-formatter": "^2.4.0""lodash": "^4.17.20",
在api
目录下新建xml.js
接口,url依据本人的理论状况批改即可
import request from '@/utils/request'export function getXmlFile() { return request({ url: '/api/test/getXmlFile', method: 'get' })}export function putXmlFile(data) { return request({ url: '/api/test/putXmlFile', method: 'post', data })}
导入ace.js
,包含主题以及语言public/index.html
写入
//css<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/ace/1.4.9/theme-xcode.css">//js<script src="https://cdn.bootcdn.net/ajax/libs/ace/1.4.9/ace.js"></script><script src="https://cdn.bootcdn.net/ajax/libs/ace/1.4.9/ext-beautify.js"></script><script src="https://cdn.bootcdn.net/ajax/libs/ace/1.4.9/ext-language_tools.js"></script><script src="https://cdn.bootcdn.net/ajax/libs/ace/1.4.9/theme-xcode.js"></script><script src="https://cdn.bootcdn.net/ajax/libs/ace/1.4.9/mode-xml.js"></script>
新建编辑器组件src/components/codeEditor/index.vue
, lodash
依赖自行isntall
<template> <div :id="Id" ref="editor" :style="{ 'max-height': height }" class="ace-editor" /></template><script>import uniqueId from 'lodash/uniqueId'export default { name: 'AceEditor', props: { value: { type: String, default: '' }, height: { type: String, default: '300px' }, readOnly: { type: Boolean, default: false }, mode: { type: String, default: 'json' } }, data() { this.editor = null this.Id = uniqueId('aceEditor') return { annot: [] } }, computed: { code: { // 数据更新告诉父组件更新数据 set(val) { this.$emit('input', val) }, get() { return this.value } } }, watch: { code() { // 父组件中数据变动,同步到ace Editor // aceEditor.setValue调用后默认会全选所有文本内容,须要对光标进行非凡解决 // 缓存光标地位 const position = this.editor.getCursorPosition() this.syncData() this.editor.clearSelection() this.editor.moveCursorToPosition(position) }, mode(mode) { this.changeMode(mode) }, readOnly(b) { this.setReadOnly(b) } }, mounted() { this.initEditor() }, methods: { initEditor() { // eslint-disable-next-line no-undef this.editor = ace.edit(this.Id) this.editor.setTheme('ace/theme/xcode') // 编辑时同步数据 this.editor.session.on('change', () => { this.code = this.editor.getValue() }) this.editor.getSession().on('changeAnnotation', () => { this.annot = this.editor.getSession().getAnnotations() this.$emit('annot', this.annot) for (var key in this.annot) { // eslint-disable-next-line no-prototype-builtins if (this.annot.hasOwnProperty(key)) { console.log(this.annot[key].text + 'on line ' + ' ' + this.annot[key].row) } } }) // 字体大小 this.editor.setFontSize(14) this.syncData() this.syncOptions() }, changeMode(modeName) { const mode = { yaml: 'ace/mode/yaml', json: 'ace/mode/json', xml: 'ace/mode/xml', javascript: 'ace/mode/javascript' } this.editor.session.setMode(mode[modeName]) }, setReadOnly(readOnly) { this.editor.setReadOnly(readOnly) }, syncOptions() { this.setReadOnly(this.readOnly) this.changeMode(this.mode) }, syncData() { this.editor.setValue(this.code) } }}</script><style scoped>.ace-editor { position: relative; height: 800px; border: 1px solid #ccc; border-radius: 2px;}.ace-editor /deep/ .ace_print-margin { display: none;}</style>
新建页面src/views/xmlTest/index.vue
<template> <div id="contain"> <div> <div id="select"> <h3>批改配置文件(xml)</h3> <el-button type="primary" @click="testApi">批改</el-button> </div> <aceEditor v-model="resquestCode" height="800px" mode="xml" @annot="annot" /> </div> </div></template><script>import { getXmlFile, putXmlFile } from '@/api/xml'import aceEditor from '@/components/codeEditor'export default { name: '', components: { aceEditor }, props: {}, data() { return { errcode: [], resquestCode: `` } }, watch: { }, mounted() { this.getXml() }, methods: { isError() { if (this.errcode.length > 0) { this.$message.error(`代码第${this.errcode[0].row + 1}行语法错误,${this.errcode[0].text}`) return true } return false }, testApi() { if (!this.isError()) { this.format() this.select() } }, getXml() { getXmlFile().then(res => { console.log('res: ', res) this.resquestCode = res.data || '' this.format() }) }, annot(e) { this.errcode = e }, format() { var format = require('xml-formatter') this.resquestCode = format(this.resquestCode, { collapseContent: true }) }, select() { putXmlFile({ data: this.resquestCode }).then(res => { console.log('res: ', res) this.$message.success('批改胜利') }) } }}</script><style lang="scss">#contain { margin: 0 20px; display: block !important; #select { .el-select .el-input { width: 100px; } .input-with-select .el-input-group__prepend { background-color: #fff; } }}#editor { width: 100%; height: 300px;}</style>
增加路由配置
{ path: '/xml', component: Layout, children: [ { path: '', name: 'xml', component: () => import('@/views/xmlTest/index'), meta: { title: 'xml', icon: 'xml' } } ] }
界面
更多问题欢送退出前端交换群交换749539640