摘要:目錄建造者模式應(yīng)用。其實(shí)不用也可以,因?yàn)椴皇呛軓?fù)雜,只是為了復(fù)習(xí)一下所學(xué)過的設(shè)計模式知識目錄工廠模式應(yīng)用。
為了提高開發(fā)效率,通常會想辦法把一些模式固定的重復(fù)性的勞動抽取出來,以后再使用的時候,拿來主義就可以了。這樣既可以提高開發(fā)效率,又降低了出錯的風(fēng)險。
這一思想在我們的日常工作中可以說隨處可見,我們完成一項(xiàng)復(fù)雜的工程,并不需要面面俱到什么都自己寫,我們完全可以利用第三方的jar包讓我們達(dá)到事半功倍的效果,比如經(jīng)常使用的apche的commons-lang3包。再比如java中的繼承、我們自己封裝的工具類等等。 另外一方面,對于源碼文件,如果公司有成熟的框架,我們的開發(fā)都是遵循著框架制定的約定來進(jìn)行開發(fā)的,我們在創(chuàng)建某一個業(yè)務(wù)的控制層、業(yè)務(wù)層、持久層的時候,實(shí)際上有相當(dāng)一部分的工作是重復(fù)的。
那么對于源碼文件的編寫我們能否偷偷懶呢?答案肯定是可以的,我們可以利用模板引擎技術(shù),將不變的部分寫在模板文件中,將可變的部分作為變量傳遞到模板引擎的上下文中,最終生成我們想要的源碼文件。
模板引擎的產(chǎn)品有很多,比如前端模板artTemplate、后端模板Velocity、FreeMarker等 本文以Velocity為例,總結(jié)一下它在實(shí)戰(zhàn)中的應(yīng)用
1.基礎(chǔ)知識搭建過程涉及到的基礎(chǔ)知識包括:Maven、Velocity、工廠模式、建造者模式、單元測試
對于基礎(chǔ)不熟悉的同學(xué),建議看一下下面的兩篇文章
Velocity基礎(chǔ)
Velocity語法摘要
代碼生成功能,在我設(shè)計的后臺框架中,作為一個獨(dú)立的模塊存在,使用Maven構(gòu)建。
builder目錄:建造者模式應(yīng)用。由于代表表結(jié)構(gòu)的Table實(shí)體稍顯復(fù)雜,因此使用了建造者模式構(gòu)建Table對象。其實(shí)不用也可以,因?yàn)門able不是很復(fù)雜,只是為了復(fù)習(xí)一下所學(xué)過的設(shè)計模式知識
factory目錄:工廠模式應(yīng)用。在構(gòu)建源碼文件的時候,由于涉及到了Controller、Service、Dao、Domain這幾種類型的文件,因此針對不同類型的文件,要使用其對應(yīng)的處理類,因此使用了工廠模式
handler目錄:生成源文件的核心代碼
model目錄:在生成domain的時候,由于字段需要從數(shù)據(jù)庫中的表中讀取,因此構(gòu)造了與表對應(yīng)的實(shí)體類方便處理
utils目錄:工具類
Generator.java:程序主文件,調(diào)用入口
test目錄:單元測試
. ├── generator.iml ├── pom.xml └── src ├── main │?? ├── java │?? │?? └── com │?? │?? └── wt │?? │?? └── master │?? │?? └── generator │?? │?? ├── Generator.java │?? │?? ├── builder │?? │?? │?? ├── MySqlTableBuilder.java │?? │?? │?? └── TableBuilder.java │?? │?? ├── factory │?? │?? │?? └── GeneratorFactory.java │?? │?? ├── handler │?? │?? │?? ├── BaseGenerator.java │?? │?? │?? ├── ControllerGeneratorHandler.java │?? │?? │?? ├── DomainGeneratorHandler.java │?? │?? │?? ├── MapperGeneratorHandler.java │?? │?? │?? └── ServiceGeneratorHandler.java │?? │?? ├── model │?? │?? │?? └── Table.java │?? │?? └── util │?? │?? ├── JdbcUtils.java │?? │?? ├── SpringContextUtils.java │?? │?? ├── TableColumnUtils.java │?? │?? └── TableInfoUtils.java │?? └── resources │?? ├── config │?? │?? ├── applicationContext.xml │?? │?? └── db.properties │?? └── template │?? ├── controller.java.vm │?? ├── dao.java.vm │?? ├── domain.java.vm │?? ├── service.java.vm │?? └── serviceimpl.java.vm └── test └── com.wt.master.generator └── GeneratorTest.java2.2引入依賴
3.核心代碼 3.1模板文件的定義j2ee com.wt.master 1.0-SNAPSHOT ../version/ 4.0.0 generator org.apache.velocity velocity 1.7 junit junit 4.12 test com.wt.master core 1.0-SNAPSHOT com.mchange c3p0 0.9.5.4
以controller層生成模板為例
將不變的部分直接寫到.vm文件中
將模板文件中,有可能發(fā)生變化的部分,抽取為變量,變量的值從VelocityContext中獲取
在Velocity架構(gòu)中,有一個上下文的定義,通過上下文,程序?qū)⒆兞糠湃肷舷挛膶ο笾?。而模板從上下文中獲取對應(yīng)變量的值,獲取的方式是${變量名},關(guān)于Velocity模板文件中的語法,參見上文提到的兩篇文章
package ${packagePath}.controller; import ${packagePath}.domain.${moduleName}; import ${packagePath}.service.${moduleName}Service; import com.wt.master.core.base.BaseController; import com.wt.master.core.helper.QueryHelper; import com.wt.master.core.request.HttpResultEntity; import io.swagger.annotations.Api; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; import java.util.List; import java.util.Map; /** * ${moduleNameCN}控制器 * * @author * @date */ @Api(value = "${moduleNameCN}控制器", tags = "${moduleName}Controller", description = "${moduleNameCN}控制器" ) @RestController @RequestMapping("/${moduleName}" ) @Slf4j public class ${moduleName}Controller extends BaseController<${moduleName}, ${moduleName}Service> { @Autowired private ${moduleName}Service ${lowerModuleName}Service; @Override protected ${moduleName}Service getService() { return ${lowerModuleName}Service; } }3.2工廠類定義
根據(jù)源碼文件類型的不同,定義了不同的處理類,通過工廠模式返回對應(yīng)的處理類
package com.wt.master.generator.factory; import com.wt.master.generator.Generator; import com.wt.master.generator.handler.*; /** * 生成器工廠 * * @author [email protected] * @date Jun 18, 2019 at 4:02:23 PM */ public class GeneratorFactory { public static BaseGenerator create(Generator.GenerateItem item) { BaseGenerator baseGenerator = null; switch (item) { case service: baseGenerator = new ServiceGeneratorHandler(); break; case controller: baseGenerator = new ControllerGeneratorHandler(); break; case mapper: baseGenerator = new MapperGeneratorHandler(); break; case domain: baseGenerator = new DomainGeneratorHandler(); break; default: baseGenerator = new ControllerGeneratorHandler(); } return baseGenerator; } }3.3源碼生成處理類定義
以controller處理類為例
定義抽象類,作為基類
定義了抽象方法generate,生成源碼文件的處理方法
定義了抽象方法getFilePath,獲取生成文件的路徑
方法的實(shí)現(xiàn)由具體的實(shí)現(xiàn)類來實(shí)現(xiàn)
package com.wt.master.generator.handler; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.runtime.RuntimeConstants; import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader; import java.io.File; import java.io.FileNotFoundException; import java.io.PrintWriter; /** * 生成器抽象 * * @author [email protected] * @date May 12, 2019 at 10:44:53 AM */ public abstract class BaseGenerator { /** * 生成代碼 * * @param tableName 表名 * @param moduleName 模塊英文名 * @param moduleNameCN 模塊中文名 * @param packagePath 包路徑 * @return */ public abstract BaseGenerator generate(String tableName, String moduleName, String moduleNameCN, String packagePath); /** * 生成文件路徑 * @param packagePath * @return */ public abstract String getFilePath(String packagePath,String moduleName); /** * 獲取 模板 * * @param templateName 模板文件名稱 * @return */ Template getTemplate(String templateName) { VelocityEngine ve = new VelocityEngine(); ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath" ); ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName()); ve.setProperty("input.encoding","utf-8"); ve.setProperty("output.encoding","utf-8"); ve.init(); Template t = ve.getTemplate("/template/" + templateName); return t; } protected void merge(Template template, VelocityContext ctx, String path) { File file = new File(path); if(!file.exists()){ new File(file.getParent()).mkdirs(); }else{ System.out.println("替換文件"+file.getAbsolutePath()); } PrintWriter writer = null; try { writer = new PrintWriter(path); template.merge(ctx, writer); writer.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } finally { writer.close(); } } /** * 獲得根目錄 * @return */ protected String getRootPath(){ String rootPath = ""; try { File file = new File(BaseGenerator.class.getResource("/").getFile()); rootPath = file.getParent(); rootPath = java.net.URLDecoder.decode(rootPath.substring(0, rootPath.indexOf("target") - 1), "utf-8"); return rootPath+"/src/main/java"; } catch (Exception e) { e.printStackTrace(); } return rootPath; } /** * 轉(zhuǎn)換包路徑為文件路徑 * @param packagePath * @return */ protected String convertPackagePathToFilePath(String packagePath){ StringBuilder path = new StringBuilder(); path.append("/" ); path.append(packagePath.replace(".", "/" )); path.append("/"); return path.toString(); } }3.4工具類的定義
該類主要是獲取表的信息及對應(yīng)的字段信息
package com.wt.master.generator.util; import com.wt.master.generator.model.Table; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.util.CollectionUtils; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 表操作類 * * @author [email protected] * @date Apr 23, 2019 at 11:36:30 PM */ public class TableInfoUtils { public static final String JDBC_TEMPLATE = "jdbcTemplate"; public static Table getTableColumnList(String tableName) { JdbcTemplate jdbcTemplate = (JdbcTemplate) SpringContextUtils.getBean(JDBC_TEMPLATE); List3.5應(yīng)用入口
代用create方法來生成源碼文件
package com.wt.master.generator; import com.wt.master.generator.builder.MySqlTableBuilder; import com.wt.master.generator.builder.TableBuilder; import com.wt.master.generator.factory.GeneratorFactory; import com.wt.master.generator.handler.BaseGenerator; import com.wt.master.generator.model.Table; import com.wt.master.generator.util.TableInfoUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.util.Assert; import java.util.List; /** * 代碼生成工具 * * @author [email protected] * @date Apr 23, 2019 at 10:41:51 PM */ public class Generator { /** * 生成代碼入口 * * @param tableName 表名 * @param moduleName 模塊英文名 * @param moduleNameCN 模塊中文名 * @param packagePath 打包路徑 * @param item 生成項(xiàng)目 */ public static void create(String tableName, String moduleName, String moduleNameCN, String packagePath, GenerateItem... item) { if (StringUtils.isBlank(tableName) || StringUtils.isBlank(moduleName) || StringUtils.isBlank(moduleNameCN) || StringUtils.isBlank(packagePath)) { throw new IllegalArgumentException("參數(shù)非法!" ); } for (GenerateItem generateItem : item) { BaseGenerator baseGenerator = GeneratorFactory.create(generateItem); baseGenerator.generate(tableName, moduleName, moduleNameCN, packagePath); } } public enum GenerateItem { controller, service, mapper, domain } }4.單元測試
package com.wt.master.generator; import org.junit.Test; import org.junit.Before; import org.junit.After; /** * Generator Tester. * * @author* @version 1.0 * @since Jun 18, 2019*/ public class GeneratorTest { @Test public void testCreate() throws Exception { //TODO: Test goes here... Generator.create("SecurityRoleT", "SecurityRole", "角色管理", "com.wt.common.security", Generator.GenerateItem.controller, Generator.GenerateItem.service, Generator.GenerateItem.mapper, Generator.GenerateItem.domain); } }
源碼github地址
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/77841.html
摘要:我拿網(wǎng)易郵箱賬號舉例子,那么我們?nèi)绾尾拍茏屇愕泥]箱賬號可以利用第三方發(fā)送郵件這里的第三方就是我們即將編寫的程序。 一 前言 測試所使用的環(huán)境 測試使用的環(huán)境是企業(yè)主流的SSM 框架即 SpringMVC+Spring+Mybatis。為了節(jié)省時間,我直接使用的是我上次的SSM項(xiàng)目中整合Echarts開發(fā)該項(xiàng)目已經(jīng)搭建完成的SSM環(huán)境。 標(biāo)題說的四種姿勢指的是哪四種姿勢? 發(fā)送text...
摘要:官網(wǎng)源碼推薦從開始手寫一個框架更多請?jiān)诩夹g(shù)棧微信公眾號后臺回復(fù)關(guān)鍵字。是一個開放源代碼的對象關(guān)系映射框架,它對進(jìn)行了非常輕量級的對象封裝,它將與數(shù)據(jù)庫表建立映射關(guān)系,是一個全自動的框架。 Java 程序員方向太多,且不說移動開發(fā)、大數(shù)據(jù)、區(qū)塊鏈、人工智能這些,大部分 Java 程序員都是 Java Web/后端開發(fā)。那作為一名 Java Web 開發(fā)程序員必須需要熟悉哪些框架呢? 今天...
摘要:是一個基于的模板引擎。模板中未被定義的變量將被認(rèn)為是一個字符串。公眾號回復(fù)全棧,領(lǐng)取前端,,產(chǎn)品經(jīng)理,微信小程序,等資源合集大放送。公眾號回復(fù)面試,領(lǐng)取面試實(shí)戰(zhàn)學(xué)習(xí)資源。 Velocity是一個基于java的模板引擎(template engine)。它允許任何人僅僅簡單的使用模板語言(template language)來引用由java代碼定義的對象。 當(dāng)Velocity應(yīng)用于web...
摘要:你只需要花分鐘,就能擁有一個屬于自己的私人博客了,并且可以對整個項(xiàng)目有一個完成的概念和感覺。指令和相似,表達(dá)式和保持一致,易學(xué)易用。 本文適合剛學(xué)習(xí)完 Java 語言基礎(chǔ)的人群,跟著本文可了解和運(yùn)行 Tale 項(xiàng)目。示例均在 Windows 操作系統(tǒng)下演示 showImg(https://segmentfault.com/img/bVbwsbo?w=1578&h=868); 本文作者:...
閱讀 2848·2021-11-19 09:40
閱讀 3707·2021-11-15 18:10
閱讀 3289·2021-11-11 16:55
閱讀 1245·2021-09-28 09:36
閱讀 1662·2021-09-22 15:52
閱讀 3375·2019-08-30 14:06
閱讀 1170·2019-08-29 13:29
閱讀 2317·2019-08-26 17:04