问题
目前我们系统中存在一部分老系统(jplugin框架孩子王自研系统)要改造成新的springboot框架。老系统中service层直接引用了mapper(对数据库进行数据持久化操作)缺少dao层(介于业务逻辑层和数据库之间,进行数据的访问和操作,不限于mysql,数据缓存操作可以放到这一层),改造成springboot的话,需要补上这一部分。在加入dao层过程中,老系统为主要的订单系统,存在大量的方法。如果用人工的方法一个个去改需要花费大量的时间(也可以说作者懒不愿意做这种重复性的工作)。
分析
因为service层引用的mapper的方法要换成到dao对应的方法,定义的dao接口需要重新实现一遍mapper中定义的方法。
两者接口定义的方法基本一致,而且dao层对应的实现基本为对baseMapper中对应方法的引用
直接用代码实现:
编码
version1
/**
* fs
*/
const fs = require('fs');
//nodejs子进程
const { exec } = require('child_process')
/**
* Pick类
*/
class Pick{
/**
*
* @param {*} pattern 匹配模式
* @param {*} data 匹配数据
* @param {*} callback 处理函数
*/
constructor(pattern,data,callback) {
//匹配对应数据
this.originData = data.match(pattern)
//定义私有化变量
this.data = []
//调用用私有处理方法存在data中
this.dealData(callback)
}
//处理函数
dealData(callback) {
let data = callback(this.originData)
this.data = data
}
//返回处理后数据
getData(){
return this.data
}
}
let getSpringDaoCode = function(){
//生成对应dao代码
let aimDaoCode = '';
//读取对应文件文本内容
let data = fs.readFileSync("data.txt").toString();
// 所有匹配方法
// @Override
// public int insert(UserInfoRecognizee record) {
// return this.baseMapper.insert(record);
// }
// 示例代码中的insert
let methods = new Pick(/\s[\w\d]*\(/g,data,(data)=>{
let dealData = []
if(data){
data.forEach(item=>{
let method = item.replace(/\(/,"").replace(/\s/,"")
dealData.push(method)
})
}else{
console.log("未匹配到方法")
}
return dealData
})
// 匹配所有参数
// @Override
// public int updateRecognizeInfoByOrderIds(UserInfoRecognizee userInfoRecognizee, List<String> orderIdList) {
// return this.baseMapper.updateRecognizeInfoByOrderIds(userInfoRecognizee,orderIdList);
// }
// 示例代码中的UserInfoRecognizee userInfoRecognizee, List<String> orderIdList
let params = new Pick(/\(.*\)/g,data,(data)=>{
let dealData = []
if(data){
data.forEach(item=>{
//获取对应变量名 先剔除括号 再剔除<>所包含的数据类型只留 UserInfoRecognizee userInfoRecognizee,List orderIdList 以,分组
let splitString = item.replace(/\(/,"").replace(/\)/,"").replace(/\<[\w,\s]*\>/g,"").split(",")
let param = []
splitString.forEach(it=>{
let array = it.split(" ")
//取最后一个元素作为变量
let pa = array[array.length-1]
param.push(pa)
}
)
//组装成,分割的字符串
param.join(",")
dealData.push(param)
})
}else{
console.log("未匹配到参数")
}
return dealData
});
//获取所有方法体
let allImpl = data.split("@Override");
//剔除第一个空元素 获取所有方法体
allImpl.shift()
//所有方法
let me = methods.getData();
//所有参数
let para = params.getData();
//组装对应的方法
for(let i =0;i<allImpl.length;i++){
let da = `this.baseMapper.${me[i]}(${para[i]})`
let ai = allImpl[i]
if(ai.indexOf("void")>-1){
ai=ai.replace(/\{[\s\n]*\}/gm,`{\n ${da};\n }`)
}else{
if(ai.indexOf("return 0")>-1){
ai=ai.replace(/return 0/g,`return ${da}`)
}else{
if(ai.indexOf("null")>-1){
ai=ai.replace("null",`${da}`)
}
}
}
//将组装好的方法替换指定位置并加入@Override 头
ai=ai.replace("public","@Override\n public");
aimDaoCode+=ai;
}
return aimDaoCode;
}
//fs观察指定文件 内容发生变化时 调用处理函数并将获得的代码复制到粘贴版
fs.watchFile("data.txt",(curr,prev)=>{
let code = getSpringDaoCode()
// Windows
exec('clip').stdin.end(code)
})
version2
const fs = require('fs');
const path = require('path');
//匹配指定方法
class Pick{
constructor(pattern,data,callback) {
this.originData = data.match(pattern)
this.data = []
this.dealData(callback)
}
dealData(callback) {
let data = callback(this.originData)
this.data = data
}
getData(){
return this.data
}
}
function getSpringDaoCode(data){
let aimDaoCode = '';
//获取方法
let methods = new Pick(/\s[\w\d]*\(/g,data,(data)=>{
let dealData = []
if(data){
data.forEach(item=>{
let method = item.replace(/\(/,"").replace(/\s/,"")
dealData.push(method)
})
}else{
console.log("未匹配到方法")
}
return dealData
})
//获取文件头
let headers = new Pick(/^(package)[\w\.\s\n\r;/*\<\>\u4e00-\u9fa5\@\-\(\),]*{$/gm,data,(data)=>{
let dealData =''
if(data){
dealData = data[0]+"\r\n"
}else{
console.log("未匹配到文件头")
}
return dealData
})
//获取参数
let params = new Pick(/\(.*\)/g,data,(data)=>{
let dealData = []
if(data){
data.forEach(item=>{
let splitString = item.replace(/\(/,"").replace(/\)/,"").replace(/\<[\w,\s]*\>/g,"").split(",")
let param = []
splitString.forEach(it=>{
let array = it.split(" ")
let pa = array[array.length-1]
param.push(pa)
}
)
param.join(",")
dealData.push(param)
})
}else{
console.log("未匹配到参数")
}
return dealData
});
let allImpl = data.split("@Override");
allImpl.shift()
let me = methods.getData();
let para = params.getData();
let he = headers.getData();
aimDaoCode+=he
let state = fs.existsSync("aim.txt")
if(state){
fs.unlinkSync("aim.txt")
}
for(let i =0;i<allImpl.length;i++){
let da = `this.baseMapper.${me[i]}(${para[i]})`
let ai = allImpl[i]
if(ai.indexOf("void")>-1){
ai=ai.replace(/\{[\s\n]*\}/gm,`{\n ${da};\n }`)
}else{
if(ai.indexOf("return 0")>-1){
ai=ai.replace(/return 0/g,`return ${da}`)
}else{
if(ai.indexOf("null")>-1){
ai=ai.replace("null",`${da}`)
}
}
}
ai=ai.replace("public","@Override\n public");
fs.appendFileSync("aim.txt",ai);
aimDaoCode+=ai;
}
return aimDaoCode;
}
let dir = "D:\\workspace\\ins2.0\\ins-biz\\src\\main\\java\\com\\haiziwang\\mzt\\fin\\biz\\dao\\db\\impl";
let fileEmmitMap = new Set();
fs.watch(dir,(eventType,filename)=>{
if(eventType=="change"){
}else if(eventType == "rename"){
let fullName = path.join(dir,filename)
if(fullName.indexOf("_")<=-1){
if(!fileEmmitMap.has(fullName)){
fileEmmitMap.add(fullName)
console.log("dealing"+fullName)
let data = fs.readFileSync(fullName).toString();
let daoCode = getSpringDaoCode(data)
fs.writeFileSync(fullName,daoCode)
}else{
console.log("dealed"+fullName)
}
}
}
})
效果图
version1
version2
选定指定文件夹保存指定文件自动替换相应代码