简介
通常咱们批改某个服务的配置文件的时候,须要登入服务器,进入指定目录而后对配置文件例如 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;
@Data
public 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