原博地址https://laboo.top/2018/11/26/a-db/#morejava
本文介紹如何用Java編寫高度自定義的代碼生成器mysql
MyBatis 是一款優秀的持久層框架,它支持定製化 SQL、存儲過程以及高級映射。MyBatis 避免了幾乎全部的 JDBC 代碼和手動設置參數以及獲取結果集。MyBatis 可使用簡單的 XML 或註解來配置和映射原生信息。
上面這一段話來自Mybatis官網
的介紹, 初用Mybatis時感受這個框架相比於JDBC優雅多了, 用起來也如官網說的很是簡單。可是用了一段時間以後, 弊端就慢慢凸顯出來了git
使用Mybatis時不得不爲每一個表建立一個Entity.java
、Mapper.xml(Mapper能夠融合入Dao中)
、Dao.java
,Service.java
層次很清晰, 可是太多重複性的工做了, 費時間且易於出錯github
而且當數據庫發生一點改動的時候... 苦不堪言spring
後來出現了自動生成代碼的插件, 可是老是不盡人意, 不能爲所欲爲地控制, 畢竟每一個人的需求都不同sql
本文就來介紹如何簡單的編寫一個本身的代碼生成器數據庫
mybatis-generatorapache
實現的思路很簡單, 首先查詢數據庫的表結構, 獲得列名, 列類型...
等信息mybatis
建立文件模版, 將這些信息插入模版中, 最後打包模版進壓縮包導出架構
代碼實現 一共五個Java類
首先來看兩個實體類
TableDO 存放表名, 對於的類名, 以及列信息
完整類代碼 TableDO.java
public class TableDO { private String tableName; private List<ColumnDO> columns; private String className; private String suffix; // get()... set()... }
ColumnDO 存放列名, 數據庫字段類型, 以及對應Java中的屬性名和類型
完整類代碼 ColumnDO.java
public class ColumnDO { private String columnName; private String dataType; private String attrName; private String attrLowerName; private String attrType; // get()... set()... }
在GeneratorMapper 中, 咱們經過表名查詢表自動的信息
完整類代碼 GeneratorMapper.java
@Mapper public interface GeneratorMapper { @Select("select column_name columnName, data_type dataType from information_schema.columns where table_name = #{tableName} and table_schema = (select database()) order by ordinal_position") List<ColumnDO> listColumns(String tableName); }
在GeneratorUtils 中進行類信息與模版之間的轉換
完整類代碼 GeneratorUtils.java
將表信息放入Velocity
模版的上下文中
Map<String, Object> map = new HashMap<>(); map.put("tableName", table.getTableName()); map.put("className", table.getClassName()); map.put("pathName", getPackageName().substring(getPackageName().lastIndexOf(".") + 1)); map.put("columns", table.getColumns()); map.put("package", getPackageName()); map.put("suffix", table.getSuffix()); Properties prop = new Properties(); prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); Velocity.init(prop); VelocityContext context = new VelocityContext(map);
添加模版
List<String> templates = new ArrayList<>(); templates.add("mybatis/Model.java.vm"); templates.add("mybatis/Query.java.vm"); templates.add("mybatis/Dao.java.vm"); templates.add("mybatis/Mapper.xml.vm"); templates.add("mybatis/Service.java.vm");
編譯模版
StringWriter sw = new StringWriter(); Template tpl = Velocity.getTemplate(template, "UTF-8"); tpl.merge(context, sw);
Utils類完成了生成代碼的主要工做, 可是代碼也是比較簡單的
在Service 中注入Mapper 查詢列信息, 並用Utils生成代碼, 而後導出壓縮包
完整類代碼 GeneratorService.java
@Service public class GeneratorService { @Resource private GeneratorMapper generatorMapper; @Resource private Environment environment; public void generateZip(String[] tableNames, String zipPath) throws IOException { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ZipOutputStream zip = new ZipOutputStream(outputStream); for (String tableName : tableNames) { TableDO table = new TableDO(); table.setTableName(tableName); table.setColumns(generatorMapper.listColumns(tableName)); GeneratorUtils.generatorCode(table, zip,getConfig()); } IOUtils.closeQuietly(zip); FileOutputStream file = new FileOutputStream(zipPath); file.write(outputStream.toByteArray()); file.close(); } // getConfig ... }
本身寫代碼生成器的好處就是, 能夠根據需求定製本身的模版, 下面是個人幾個模版能夠供參考
生成的代碼是在commons-mybatis架構下使用的
package ${package}.database.dao; import ${package}.database.model.${className}${suffix}; import org.apache.ibatis.annotations.Mapper; import org.laziji.commons.mybatis.dao.${suffix}Dao; @Mapper public interface ${className}Dao extends ${suffix}Dao<${className}${suffix}> { }
在resources
下建立application-${name}.yml
文件, ${name}
隨意, 例如: application-example.yml
, 可建立多個
配置文件內容以下, 填入數據庫配置, 以及生成代碼的包名, 源文件路徑
spring: datasource: url: jdbc:mysql://xxx.xxx.xxx.xxx:3306/xxxx?characterEncoding=utf-8 username: xxxxxx password: xxxxxx generator: package: com.xxx.xxx resources: mapper
在test文件下建立測試類
@ActiveProfiles("example")
中填入剛纔配置文件名的name
tableNames
須要生成的表, 能夠多個zipPath
代碼導出路徑運行測試方法便可
package pg.laziji.generator; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit4.SpringRunner; import pg.laziji.generator.mybatis.GeneratorService; import javax.annotation.Resource; import java.io.IOException; @ActiveProfiles("example") @RunWith(SpringRunner.class) @SpringBootTest public class ExampleTest { @Resource private GeneratorService generatorService; @Test public void test() throws IOException { String[] tableNames = new String[]{"example_table1", "example_table2"}; String zipPath = "/home/code.zip"; generatorService.generateZip(tableNames,zipPath); } }
歡迎關注個人博客公衆號
![]()