簡(jiǎn)單java代碼生成器

最近公司新開一個(gè)項(xiàng)目,很多基本的dao和service層代碼都重復(fù)遗遵,所以打算寫個(gè)簡(jiǎn)單的代碼生成器直接生成逸嘀,
免得一個(gè)一個(gè)復(fù)制麻煩车要。但是在使用Velocity的時(shí)候發(fā)現(xiàn)獲取模板信息有點(diǎn)繁瑣,需要修改配置崭倘。索性自己寫個(gè)
簡(jiǎn)單實(shí)用的自己用用翼岁,在此也做個(gè)記錄,有興趣的也可以看看司光,實(shí)現(xiàn)思路很簡(jiǎn)單琅坡。


  • 代碼如下:
/**
 * 測(cè)試
 * Created by GN on 2016/11/27.
 */
public class GnTest {

    @Test
    public void testGn() throws IOException {
        GnContext gnContext = new GnContext();
        gnContext.put("domain","User");
        gnContext.put("lowerDomain","user");
        String path = "E:\\WorkSpace\\Idea\\ztx\\gn-cc\\src\\main\\resources\\DaoImpl.java";
        Template template = GnUtil.getTemplate(path);
        String target = "G:\\DaoImpl.java";
        File file = new File(target);
        template.merge(gnContext,file);
    }

}
/**
 * 定義模板插入值
 * Created by GN on 2016/11/27.
 */
public class GnContext {

    /**
     * 存儲(chǔ)模板值
     */
    private Map<String, String> context = new HashMap<>();

    public GnContext() {

    }

    public GnContext(Map<String, String> context) {
        this.context = context;
    }

    public void put(String key, String value) {
        context.put(key, value);
    }

    public String get(String key) {
        return context.get(key);
    }

}
/**
 * Created by GN on 2016/11/27.
 */
public abstract class GnUtil {

    /**
     * 獲取模板信息
     * @param filePath 模板路徑
     * @return
     */
    public static Template getTemplate(String filePath) throws IOException {
        if (!StringUtil.hasLength(filePath)){
            throw new IllegalArgumentException("模板路徑不能為空");
        }
        File file = new File(filePath);
        if (!file.isFile() || !file.exists()){
            throw new IllegalArgumentException("無(wú)法找到指定文件:"+filePath);
        }
        return new Template(file);
    }

}
/**
 * 模板處理
 * Created by GN on 2016/11/27.
 */
public class Template {

    private static final String TAG_PREFIX = "${";
    private static final String TAG_POSTFIX = "}";

    /**
     * 模板信息
     */
    private BufferedReader reader;
    private File file;
    /**
     * 模板標(biāo)簽,eg:${domain}:key=domain,value=${domain}
     */
    private Map<String, String> tag = new HashMap<>();

    public Template(File file) throws IOException {
        this.file = file;
        //初始化模板輸入流
        initReader();
    }

    private void initReader() {
        if (file == null) {
            throw new IllegalArgumentException("獲取模板失敗");
        }
        try {
            InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(file), "UTF-8");
            this.reader = new BufferedReader(inputStreamReader);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    /**
     * 處理標(biāo)簽到tag中
     *
     * @param text
     */
    private void initTag(String text) {
        if (!StringUtil.hasLength(text)) {
            return;
        }
        String tagFlag = getTagFlag(text);
        String tagText = getTagText(text);
        this.tag.put(tagText, tagFlag);
        //遞歸解析一行中的多個(gè)標(biāo)簽
        int prefix = text.indexOf(TAG_PREFIX);
        String subText = text.substring(prefix + 2 + tagText.length());
        if (hasTag(subText)) {
            initTag(subText);
        }
    }

    /**
     * 獲取標(biāo)簽,${domain}
     *
     * @param text
     * @return
     */
    private String getTagFlag(String text) {
        int prefix = text.indexOf(TAG_PREFIX);
        int postfix = text.indexOf(TAG_POSTFIX);
        return text.substring(prefix, postfix + 1);
    }

    /**
     * 獲取標(biāo)簽中的內(nèi)容,${domain} --> domain
     *
     * @param text
     * @return
     */
    private String getTagText(String text) {
        String tagFlag = getTagFlag(text);
        return tagFlag.substring(2, tagFlag.length() - 1);
    }

    /**
     * 判斷文本中是否含有標(biāo)簽
     *
     * @param text
     * @return
     */
    private boolean hasTag(String text) {
        if (!StringUtil.hasLength(text)) {
            return Boolean.FALSE;
        }
        return text.indexOf(TAG_PREFIX) > 0 && text.indexOf(TAG_POSTFIX) > 0;
    }

    /**
     * 生成模板
     *
     * @param context 模板值定義
     * @param target  目標(biāo)生成文件
     */
    public void merge(GnContext context, File target) throws IOException {
        if (reader == null) {
            throw new IllegalArgumentException("讀取模板失敗");
        }
        if (context == null) {
            throw new IllegalArgumentException("獲取GnContext失敗");
        }
        if (target == null) {
            throw new IllegalArgumentException("獲取輸出流失敗");
        }
        String temp;
        FileWriter writer = new FileWriter(target, true);
        while ((temp = reader.readLine()) != null) {
            if (hasTag(temp)) {
                //解析出所有的標(biāo)簽
                List<String> tagTextList = findTagTextList(temp);
                if (!tagTextList.isEmpty()) {
                    for (String text : tagTextList) {
                        String value = context.get(text);
                        if (StringUtil.hasLength(value)){
                            temp = temp.replace(TAG_PREFIX + text + TAG_POSTFIX, value);
                        }
                    }
                }
            }
            writer.write(temp + "\n");
            writer.flush();
        }
        writer.close();
    }

    /**
     * 獲取文本中的標(biāo)簽
     *
     * @param lineText
     * @return
     */
    private List<String> findTagTextList(String lineText) {
        List<String> tagTextList = new ArrayList<>();
        if (StringUtil.hasLength(lineText) && hasTag(lineText)) {
            String tmp = lineText;
            while (hasTag(tmp)) {
                String tagText = findTagText(tmp);
                if (!tagTextList.contains(tagText)) {
                    tagTextList.add(tagText);
                }
                int begin = tmp.indexOf(tagText);
                tmp = tmp.substring(begin + tagText.length()+1);
            }
        }
        return tagTextList;
    }

    /**
     * 獲取文本中的單個(gè)標(biāo)簽
     *
     * @param text
     * @return
     */
    private String findTagText(String text) {
        if (!StringUtil.hasLength(text)) {
            return null;
        }
        return getTagText(text);
    }

}

  • 一下為測(cè)試使用模板 :
/**
 * Created by GNon 2016/9/8.
 */
@Service
@Transactional
public class ${domain}ServiceImpl implements I${domain}Service {

    @Autowired
    private ${domain}Dao dao;

    @Override
    public void save(${domain} ${lowerDomain}) {
        dao.save(${lowerDomain});
    }

    @Override
    public void update(${domain} ${lowerDomain}) {
        dao.update(${lowerDomain});
    }

    @Override
    public void delete(Serializable id) {
        dao.delete(id);
    }

    @Override
    public ${domain} findById(Serializable id) {
        return dao.findById(id);
    }

    @Override
    public List<${domain}> findAll() {
        return dao.findAll();
    }

    @Override
    public PageData findListByPage(PageData pageData) {
        return dao.findListByPage(pageData);
    }
}
  • 以下是通過(guò)上述代碼實(shí)現(xiàn)的簡(jiǎn)單生成器
/**
 * 代碼生成器
 * Created by GN on 2016/11/28.
 */
public class GnCreator {

    /**
     * 實(shí)體
     */
    private List<String> domains = new ArrayList<>();
    /**
     * 模板基礎(chǔ)路徑
     */
    private String baseTemplatePath = "E:\\WorkSpace\\demo\\src\\main\\resources\\";
    /**
     * 生成文件保存基本路徑
     */
    private String baseSavePath = "E:\\WorkSpace\\demosrc\\main\\java\\com\\gn\\demo\\";
    /**
     * 模板
     */
    private List<String> templates = new ArrayList<>();

    private final String DAOIMPL = "Dao.java";
    private final String SERVICE = "Service.java";
    private final String SERVICEIMPL = "ServiceImpl.java";

    public GnCreator() {
        //初始化生成器信息
        //初始化實(shí)體集合
        String[] domainList = {"User"}; //如果實(shí)體很多谴仙,可以通過(guò)注解掃描的方式去獲取迂求,不用一個(gè)一個(gè)的去寫
        List<String> asList = Arrays.asList(domainList);
        domains.addAll(asList);
        //初始化模板
        templates.add(DAOIMPL);
        templates.add(SERVICE);
        templates.add(SERVICEIMPL);
    }

    public void create() throws IOException {
        System.out.println("代碼生成器開始執(zhí)行>>>>>>>>>>>>>>>>>>>>");
        for (String domain : domains) {
            System.out.println("開始生成實(shí)體【"+domain+"】代碼...............");
            //模板值定義
            GnContext gnContext = new GnContext();
            gnContext.put("domain",domain);
            gnContext.put("lowerDomain",domain.toLowerCase());
            //根據(jù)模板生成代碼
            for (String tp : templates) {
                String templatePath = baseTemplatePath+tp;
                Template template = GnUtil.getTemplate(templatePath);
                //根據(jù)不同的模板保存到不同的目錄
                String targetFilePath = "";
                String targetFileName = "";
                if (tp.equals(DAOIMPL)){
                    targetFilePath = baseSavePath+"dao\\impl\\";
                    targetFileName = domain+DAOIMPL;
                }else if (tp.equals(SERVICE)){
                    targetFilePath = baseSavePath+"service\\";
                    targetFileName = "I"+domain+SERVICE;
                }else if (tp.equals(SERVICEIMPL)){
                    targetFilePath = baseSavePath + "service\\impl\\";
                    targetFileName = domain+SERVICEIMPL;
                }
                //判斷目錄是否存在,如果不存在則創(chuàng)建
                File file = new File(targetFilePath);
                if (!file.exists()){
                    file.mkdirs();
                }
                File targetFile = new File(targetFilePath+targetFileName);
                template.merge(gnContext,targetFile);
            }
            System.out.println("生成實(shí)體【"+domain+"】代碼完成...............");
        }
        System.out.println("代碼生成器執(zhí)行完畢>>>>>>>>>>>>>>>>>>>>>>>>");
    }

}

  • 以上為所有代碼晃跺,僅為適用自己的需求揩局,如果能幫助到其他人更好,說(shuō)下簡(jiǎn)單思路:
    代碼主要實(shí)現(xiàn)功能是獲取模板中的 ${domain} ,然后通過(guò)替換的方式把傳入的 GnContext 所對(duì)應(yīng)的值掀虎,最終實(shí)現(xiàn)代碼生成凌盯。替換一處我用的是直接查詢替換,如果你愿意也可以用正則表達(dá)式去處理烹玉,這樣也許會(huì)簡(jiǎn)潔很多驰怎。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市二打,隨后出現(xiàn)的幾起案子县忌,更是在濱河造成了極大的恐慌,老刑警劉巖继效,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件症杏,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡瑞信,警方通過(guò)查閱死者的電腦和手機(jī)厉颤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)凡简,“玉大人逼友,你說(shuō)我怎么就攤上這事〕由” “怎么了翁逞?”我有些...
    開封第一講書人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)溉仑。 經(jīng)常有香客問(wèn)我挖函,道長(zhǎng),這世上最難降的妖魔是什么浊竟? 我笑而不...
    開封第一講書人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任怨喘,我火速辦了婚禮,結(jié)果婚禮上振定,老公的妹妹穿的比我還像新娘必怜。我一直安慰自己,他們只是感情好后频,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開白布梳庆。 她就那樣靜靜地躺著暖途,像睡著了一般。 火紅的嫁衣襯著肌膚如雪膏执。 梳的紋絲不亂的頭發(fā)上驻售,一...
    開封第一講書人閱讀 51,554評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音更米,去河邊找鬼欺栗。 笑死,一個(gè)胖子當(dāng)著我的面吹牛征峦,可吹牛的內(nèi)容都是我干的迟几。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼栏笆,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼类腮!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起蛉加,我...
    開封第一講書人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤存哲,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后七婴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡察滑,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年打厘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贺辰。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡户盯,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出饲化,到底是詐尸還是另有隱情莽鸭,我是刑警寧澤,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布吃靠,位于F島的核電站硫眨,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏巢块。R本人自食惡果不足惜礁阁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望族奢。 院中可真熱鬧姥闭,春花似錦、人聲如沸越走。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至铜跑,卻和暖如春门怪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背疼进。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工薪缆, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人伞广。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓拣帽,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親嚼锄。 傳聞我的和親對(duì)象是個(gè)殘疾皇子减拭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1 場(chǎng)景問(wèn)題# 1.1 繼續(xù)導(dǎo)出數(shù)據(jù)的應(yīng)用框架## 在討論工廠方法模式的時(shí)候,提到了一個(gè)導(dǎo)出數(shù)據(jù)的應(yīng)用框架区丑。 對(duì)于...
    七寸知架構(gòu)閱讀 5,739評(píng)論 1 64
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,133評(píng)論 25 707
  • 在規(guī)模較小的公司里拧粪,大部分的項(xiàng)目規(guī)模不是特別大,技術(shù)實(shí)現(xiàn)難度不是很高沧侥,關(guān)注點(diǎn)更多是在業(yè)務(wù)功能的開發(fā)及保證業(yè)務(wù)流程的...
    思與學(xué)閱讀 8,642評(píng)論 1 30
  • 2 月 21 日可霎,微軟中國(guó)在微信上發(fā)布了一款小程序 ——「微軟小蜜」預(yù)覽版。其主要特色是:通過(guò)文字識(shí)別出圖片上的文...
    霹靂小青龍閱讀 1,598評(píng)論 0 2