node fs模块的watch应用

136 阅读3分钟

问题

目前我们系统中存在一部分老系统(jplugin框架孩子王自研系统)要改造成新的springboot框架。老系统中service层直接引用了mapper(对数据库进行数据持久化操作)缺少dao层(介于业务逻辑层和数据库之间,进行数据的访问和操作,不限于mysql,数据缓存操作可以放到这一层),改造成springboot的话,需要补上这一部分。在加入dao层过程中,老系统为主要的订单系统,存在大量的方法。如果用人工的方法一个个去改需要花费大量的时间(也可以说作者懒不愿意做这种重复性的工作)。

分析

因为service层引用的mapper的方法要换成到dao对应的方法,定义的dao接口需要重新实现一遍mapper中定义的方法。

516e33d5720b3d20360680be6f185c8.jpg

83a074a6a39371828899a377161d32d.jpg 两者接口定义的方法基本一致,而且dao层对应的实现基本为对baseMapper中对应方法的引用

image.png 直接用代码实现:

编码

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

version1.gif

version2

选定指定文件夹保存指定文件自动替换相应代码