玩轉字符串篇--Gradle+代碼生成器=懶人必備

前言:我是愛偷懶的勤快人

咱們的口號是:
能用腦子解決的絕對不靠體力,能用電腦完成的絕對不靠腦子,能懶就懶,懶出奇跡java

1.1:關於代碼

你眼中的代碼是什麼,類的邏輯關係?方法的實現?不要忽略一個重要的本質:
代碼是人能夠讀懂的可編譯成可執行文件的字符串,因此字符串很重要。
陸陸續續寫了好幾篇關於字符串的文章了,量變的基類每每帶來質變的昇華
今天我靈光一閃,便有此文。爲了避免讓優秀石沉大海,以前寫的幾篇鏈接放在下面:bash

1.玩轉字符串篇--代碼自動生成,解放雙手
2.玩轉字符串篇--數據遍地是,看你取不取
3.玩轉字符串篇--練習MySQL沒素材?來一波字符串操做 link
4.玩轉字符串篇--替換的鬼斧神工app


1.2:本篇起由

今天寫Flutter自定義組件,感受寫個StatefulWidget要羅裏吧嗦一大堆
並且一開始都是差很少的,因而想來個一鍵生成,並放到gradle裏
寫着寫着發現用上次的字符串替代類能夠用,不用走平時的拼接了
果真有心栽花花不開,無意插柳柳成蔭!本文主要的是對字符串的想法函數


2.模板替換解析器:TemplateParser

這是我再玩轉字符串篇--替換的鬼斧神工的基礎上進行完善的產物工具

1).可指定匹配符
2).優化告終構,使用Properties替換了HashMap,並使用配置文件  
3).支持單文件和文件夾多文件替換
複製代碼

2.1:Properties的使用

在此以前,先說一下Properties的使用,感受這個也挺好的,能夠根據配置文件讀成映射表
他繼承自HashTable,只存放String到String的映射,下面來看一下他的用法
這裏在項目最外面建立一個config.properties,寫着鍵值對className=TolyWidgetpost

public class Generation {
    public static void main(String[] args) throws IOException {
        Properties prop = new Properties();
        //讀取屬性文件a.properties
        InputStream in = new BufferedInputStream(new FileInputStream("config.properties"));
        prop.load(in);     ///加載屬性列表
        Iterator<String> it = prop.stringPropertyNames().iterator();
        while (it.hasNext()) {
            String key = it.next();
            System.out.println(key + ":" + prop.getProperty(key));
        }
        in.close();
    }
}
---->[控制檯輸出]----
className:TolyWidget
複製代碼

這樣就能夠根據配置文件在代碼中使用字符串的鍵值對了gradle


2.2:解析類

最終的效果是能夠經過配置文件的映射字符串,替換掉一個模板中的全部相應被標識部分
默認配置文件的位置在項目根部,名稱config.properties,輸出到模板的父目錄同級的dest下優化

package generation;

import java.io.*;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class TemplateParser {
    /**
     * 默認:$[X],自定義注意\\轉義 
     */
    private String symbol;

    private Properties properties;

    public TemplateParser() {
        this("\\$\\[X\\]", "config.properties");
    }

    public TemplateParser(String symbol, String propFilePath) {
        this.symbol = symbol;
        loadProperties(propFilePath);
    }

    /**
     * 載入配置文件
     * @param path 配置文件路徑
     */
    private void loadProperties(String path) {
        properties = new Properties();
        //讀取屬性文件a.properties
        InputStream in = null;
        try {
            in = new BufferedInputStream(new FileInputStream(path));
            properties.load(in);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 解析字符串
     *
     * @param target 目標字符串
     * @return 處理後的字符串
     */
    public String parser(String target) {
        String[] symbols = symbol.split("X");

        Map<Integer, String> cutPos = new TreeMap<>();
        String regex = symbols[0] + "(?<result>.*?)" + symbols[1];
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(target);
        while (matcher.find()) {
            String matchStr = matcher.group("result");
            cutPos.put(matcher.end(), matchStr);
        }

        Iterator<Map.Entry<Integer, String>> iterator = cutPos.entrySet().iterator();
        String temp;
        int offset = 0;
        while (iterator.hasNext()) {
            Map.Entry<Integer, String> e = iterator.next();
            int k = e.getKey();
            String v = e.getValue();
            String src = "$[" + v + "]";
            String result = properties.getProperty(v);
            String substring = target.substring(0, k + offset);
            temp = substring.replace(src, result);
            target = target.replace(substring, temp);
            offset += result.length() - src.length();
        }
        return target;
    }


    /**
     * 根據路徑解析全部文件
     * @param path 路徑
     */
    public void parserDir(String path) {
        copyDir(path, path + "-dest");//先拷貝一分
        parserDir(new File(path + "-dest"));
    }

    private void parserDir(File file) {
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            if (files == null) {
                return;
            }
            for (File f : files) {
                if (f.isDirectory()) {
                    parserDir(f);
                } else {
                    saveFile(f, parserFile(file));
                }
            }
        } else {
            parserFile(file);
        }
    }


    /**
     * 解析一個文件
     *
     * @param path 路徑
     * @return 解析後的字符串
     */
    public String parserFile(String path) {
        File file = new File(path);
        String result = parserFile(new File(path));
        String out = file.getParentFile().getParentFile().getAbsolutePath() + File.separator + "dest" + File.separator + file.getName();
        saveFile(new File(out), result);
        return result;
    }

    /**
     * 根據文件解析
     *
     * @param file 文件
     * @return 解析後的字符串
     */
    private String parserFile(File file) {
        InputStream is = null;
        StringBuilder sb = new StringBuilder();
        try {
            is = new FileInputStream(file);
            int len = 0;
            byte[] buffer = new byte[1024];
            while ((len = is.read(buffer)) != -1) {
                sb.append(new String(buffer, 0, len));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return parser(sb.toString());
    }

    //==========================文件相關操做===========================
    /**
     * 保存字符串文件
     *
     * @param file    文件
     * @param content 字符串內容
     */
    private void saveFile(File file, String content) {
        ifNotExistMakeIt(file);
        FileWriter fw = null;

        try {
            fw = new FileWriter(file);//寫出到磁盤
            fw.write(content);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fw != null) {
                    fw.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 判斷文件是否存在,不存在則建立它
     *
     * @param file
     */
    private static void ifNotExistMakeIt(File file) {
        if (file.exists()) {//2.判斷文件是否存在
            return;
        }
        File parent = file.getParentFile();//3.獲取父文件
        if (!parent.exists()) {
            if (!parent.mkdirs()) {//4.建立父文件
                return;
            }
        }
        try {
            file.createNewFile();//5.建立文件
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void ifNotExistMakeIt(String path) {
        File file = new File(path);//1.建立文件
        ifNotExistMakeIt(file);
    }


    /**
     * 複製整個文件夾內容
     *
     * @param oldPath String 原文件路徑
     * @param newPath String 複製後路徑
     * @return boolean
     */
    private void copyDir(String oldPath, String newPath) {
        try {
            (new File(newPath)).mkdirs(); //若是文件夾不存在 則創建新文件夾
            File a = new File(oldPath);
            String[] file = a.list();
            File temp = null;
            if (file == null) {
                return;
            }
            for (int i = 0; i < file.length; i++) {
                if (oldPath.endsWith(File.separator)) {
                    temp = new File(oldPath + file[i]);
                } else {
                    temp = new File(oldPath + File.separator + file[i]);
                }
                if (temp.isFile()) {
                    FileInputStream input = new FileInputStream(temp);
                    FileOutputStream output = new FileOutputStream(newPath + "/" +
                            (temp.getName()).toString());
                    byte[] b = new byte[1024 * 5];
                    int len;
                    while ((len = input.read(b)) != -1) {
                        output.write(b, 0, len);
                    }
                    output.flush();
                    output.close();
                    input.close();
                }
                if (temp.isDirectory()) {//若是是子文件夾
                    copyDir(oldPath + "/" + file[i], newPath + "/" + file[i]);
                }
            }
        } catch (Exception e) {
            System.out.println("複製出錯");
            e.printStackTrace();
        }
    }
}
複製代碼

裏面有不少文件經常使用的操做,也能夠抽出一個工具類收藏一下ui


3.Gradle裏如何使用Java代碼

關於Gradle的知識我有一篇專文:雜篇:一代版本一代神[-Gradle-]this

3.1:Gradle裏的task和路徑獲取

新建一個task在左邊Gradle->other會有相應的任務,點一下就能夠運行其中的代碼
能夠用System.getProperty("user.dir")獲取當前項目的根目錄

---->[app/build.gradle最後面]----
task generationTask() {//自定義一個任務
    doFirst {
        String root=System.getProperty("user.dir");
        println("hello gradel:"+root)
}
複製代碼

3.2:Gradle中讀取配置文件

因爲Gradle中使用的是和Java兼容的Groovy語言,因此Java代碼也是能運行的
這裏在項目根文件下建立generation文件夾用來盛放配置文件以及模板和輸出文件

task generationTask() {//自定義一個任務
    doFirst {

        String root=System.getProperty("user.dir");
        println("hello gradel:"+root)

        Properties prop = new Properties();
        //讀取屬性文件a.properties
        InputStream is = new BufferedInputStream(new FileInputStream(root+"/generation/config.properties"));
        prop.load(is);     ///加載屬性列表
        Iterator<String> itor = prop.stringPropertyNames().iterator();
        while (itor.hasNext()) {
            String key = itor.next();
            System.out.println(key + ":" + prop.getProperty(key));
        }
        is.close();
    }
}
複製代碼

而後運行就能夠看到獲取的結果:className:TolyWidget


3.3:使用

把剛纔寫的類所有拷到下面。說幾個比較坑的點吧

1.Groovy中正則匹配不能用分組,我勒個去  
2.符號$要用單引號,不然報錯  
3.函數不能重載,我勒個去
複製代碼


3.4:插件以及拆分文件導入

那麼大一段寫在一塊不怎麼雅觀,拆一下唄,將插件邏輯所有抽到另外一個文件了
也放在generation包裏,這樣整個流程所須要的東西都在一塊兒,整個gradle只管用就好了
咱們只須要在乎模板和配置,兩個都寫好以後,輕輕一點,模板中須要替換的所有搞定

---->[使用方法,app/build.gradle]----
apply from: "./generation/generation.gradle"
複製代碼

3.5: generation.gradle全覽

把這個拷過去用就好了,之後有什麼寫着比較煩並且沒有技術含量的批量換一下唄。

// Create By 張風捷特烈(toly) in 2019.7.17 ---------

apply plugin: TemplateParserPlugin//聲明使用插件

//----------------------------如下是插件部分--------------------------------
class TemplateParserPlugin implements Plugin<Project> {
    //該接口定義了一個apply()方法,在該方法中,咱們能夠操做Project,
    //好比向其中加入Task,定義額外的Property等。
    void apply(Project project) {
        //加載Extension
        project.extensions.create("Config", Extension)

        //使用Extension配置信息
        project.task('TemplateParser') << {
            String path = project.Config.root
            new TemplateParser(path+"config.properties")
                    .parserFile(path+"template/StatefulTemplate.txt")
        }

    }
}

class Extension {//拓展參數
    String root = System.getProperty("user.dir")+"/generation/"
}

///----------------- 如下是解析類 -----------------

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class TemplateParser {
    /**
     * 默認:$[X],自定義注意\\轉義
     */
    private String symbol;

    private Properties properties;

    public TemplateParser() {
        this('\\$\\[X\\]', "config.properties");
    }

    public TemplateParser( String propFilePath) {
        this('\\$\\[X\\]',propFilePath);
    }

    public TemplateParser(String symbol, String propFilePath) {
        this.symbol = symbol;
        loadProperties(propFilePath);
    }

    /**
     * 載入配置文件
     * @param path 配置文件路徑
     */
    private void loadProperties(String path) {
        properties = new Properties();
        //讀取屬性文件a.properties
        InputStream is = null;
        try {
            is = new BufferedInputStream(new FileInputStream(path));
            properties.load(is);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 解析字符串
     *
     * @param target 目標字符串
     * @return 處理後的字符串
     */
    public String parser(String target) {
        String[] symbols = symbol.split("X");

        Map<Integer, String> cutPos = new TreeMap<>();
        String regex = symbols[0] + ".*?" + symbols[1];
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(target);

        while (matcher.find()) {
            String matchStr = matcher.group(0);
            String v = matchStr.split(symbols[0])[1].split(symbols[1])[0]
            cutPos.put(matcher.end(), v);
        }

        Iterator<Map.Entry<Integer, String>> iterator = cutPos.entrySet().iterator();
        String temp;
        int offset = 0;
        while (iterator.hasNext()) {
            Map.Entry<Integer, String> e = iterator.next();
            int k = e.getKey();
            String v = e.getValue();
            String src = '$[' + v + "]";
            String result = properties.getProperty(v);
            String substring = target.substring(0, k + offset);
            temp = substring.replace(src, result);
            target = target.replace(substring, temp);
            offset += result.length() - src.length();
        }
        return target;
    }


    /**
     * 根據路徑解析全部文件
     * @param path 路徑
     */
    public void parserDir(String path) {
        copyDir(path, path + "-dest");//先拷貝一分
        _parserDir(new File(path + "-dest"));
    }

    private void _parserDir(File file) {
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            if (files == null) {
                return;
            }
            for (File f : files) {
                if (f.isDirectory()) {
                    parserDir(f);
                } else {
                    saveFile(f, parserFile(file));
                }
            }
        } else {
            parserFile(file);
        }
    }


    /**
     * 解析一個文件
     *
     * @param path 路徑
     * @return 解析後的字符串
     */
    public String parserFile(String path) {
        File file = new File(path);
        String result = _parserFile(new File(path));
        String out = file.getParentFile().getParentFile().getAbsolutePath() + File.separator + "dest" + File.separator + file.getName();
        saveFile(new File(out), result);
        return result;
    }

    /**
     * 根據文件解析
     *
     * @param file 文件
     * @return 解析後的字符串
     */
    private String _parserFile(File file) {
        InputStream is = null;
        StringBuilder sb = new StringBuilder();
        try {
            is = new FileInputStream(file);
            int len = 0;
            byte[] buffer = new byte[1024];
            while ((len = is.read(buffer)) != -1) {
                sb.append(new String(buffer, 0, len));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return parser(sb.toString());
    }

    //=============================================文件相關操做=============================================

    /**
     * 保存字符串文件
     *
     * @param file    文件
     * @param content 字符串內容
     */
    private void saveFile(File file, String content) {
        ifNotExistMakeIt(file);
        FileWriter fw = null;

        try {
            fw = new FileWriter(file);//寫出到磁盤
            fw.write(content);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fw != null) {
                    fw.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 判斷文件是否存在,不存在則建立它
     *
     * @param file
     */
    private static void ifNotExistMakeIt(File file) {
        if (file.exists()) {//2.判斷文件是否存在
            return;
        }
        File parent = file.getParentFile();//3.獲取父文件
        if (!parent.exists()) {
            if (!parent.mkdirs()) {//4.建立父文件
                return;
            }
        }
        try {
            file.createNewFile();//5.建立文件
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void ifNotExistMakeIt(String path) {
        File file = new File(path);//1.建立文件
        ifNotExistMakeIt(file);
    }

    /**
     * 複製整個文件夾內容
     *
     * @param oldPath String 原文件路徑
     * @param newPath String 複製後路徑
     * @return boolean
     */
    private void copyDir(String oldPath, String newPath) {
        try {
            (new File(newPath)).mkdirs(); //若是文件夾不存在 則創建新文件夾
            File a = new File(oldPath);
            String[] file = a.list();
            File temp = null;
            if (file == null) {
                return;
            }
            for (int i = 0; i < file.length; i++) {
                if (oldPath.endsWith(File.separator)) {
                    temp = new File(oldPath + file[i]);
                } else {
                    temp = new File(oldPath + File.separator + file[i]);
                }
                if (temp.isFile()) {
                    FileInputStream input = new FileInputStream(temp);
                    FileOutputStream output = new FileOutputStream(newPath + "/" +
                            (temp.getName()).toString());
                    byte[] b = new byte[1024 * 5];
                    int len;
                    while ((len = input.read(b)) != -1) {
                        output.write(b, 0, len);
                    }
                    output.flush();
                    output.close();
                    input.close();
                }
                if (temp.isDirectory()) {//若是是子文件夾
                    copyDir(oldPath + "/" + file[i], newPath + "/" + file[i]);
                }
            }
        } catch (Exception e) {
            System.out.println("複製整個文件夾內容操做出錯");
            e.printStackTrace();
        }
    }
}
複製代碼
相關文章
相關標籤/搜索