简介

通常咱们批改某个服务的配置文件的时候,须要登入服务器,进入指定目录而后对配置文件例如xml进行批改,偶然一次操作还能够,然而频繁操作的确有点麻烦。
所以咱们间接把这项性能放到前端界面来进行操作,来晋升运维的效率。

思路

  1. 后端通过I/O来将服务端XML文件读取并发送给前端
  2. 前端把接管回来的xml文件在前端web编辑器里进行渲染
  3. 前端把批改过的xml文件再次发送给后端
  4. 后端把接管回来的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接口,借助dom4jasXML()将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