前言:
此項目主要解決在項目搭建初期,創建項目時很多代碼手動創建太過繁瑣,耗費不必要的開發時間。通過此代碼生成工具可以自動生成相關代碼,當然不侷限於controller層、service層、entity層、mapper層的代碼生成!因為本項目中自定義代碼生成規則的配置比較簡單,只需自定義模板並創建工廠實例即可。同時可自定義代碼的生成路徑,未設置則默認生成在本項目下(可更直觀查看生成的結構效果,文末有效果圖)。
項目結構
一: 導入pom文件相關依賴
<dependency>
<groupid>org.springframework.boot/<groupid>
<artifactid>spring-boot-starter/<artifactid>
<dependency>
<groupid>org.projectlombok/<groupid>
<artifactid>lombok/<artifactid>
<optional>true/<optional>
<dependency>
<groupid>org.springframework.boot/<groupid>
<artifactid>spring-boot-starter-test/<artifactid>
<scope>test/<scope>
<dependency>
<groupid>org.mybatis.spring.boot/<groupid>
<artifactid>mybatis-spring-boot-starter/<artifactid>
<version>1.3.2/<version>
<dependency>
<groupid>com.ibeetl/<groupid>
<artifactid>beetl-framework-starter/<artifactid>
<version>1.1.68.RELEASE/<version>
<dependency>
<groupid>org.antlr/<groupid>
<artifactid>antlr4-runtime/<artifactid>
<version>4.7.1/<version>
<dependency>
<groupid>mysql/<groupid>
<artifactid>mysql-connector-java/<artifactid>
<dependency>
<groupid>org.springframework.boot/<groupid>
<artifactid>spring-boot-starter-web/<artifactid>
二: 編寫beetl配置類
/**
* @author: brbai
* @create: 2019-10-16 17:12:45
* @description:
*/
@Configuration
@Slf4j
@Data
public class BeetlConfiguration {
@Value("${beetl.template-path}")
private String templatePath;
@Value("${beetl.delimiter-statement-start}")
private String delimiterStatementStart;
@Value("${beetl.delimiter-statement-end}")
private String delimiterStatementEnd;
@Bean(name = "beetlConfig")
public BeetlGroupUtilConfiguration beetlGroupUtilConfiguration() {
BeetlGroupUtilConfiguration beetlGroupUtilConfiguration = new BeetlGroupUtilConfiguration();
// Beetl的配置
Properties properties = new Properties();
properties.setProperty("statementStart",delimiterStatementStart);
properties.setProperty("statementEnd",delimiterStatementEnd);
properties.setProperty("DELIMITER_STATEMENT_START", delimiterStatementStart);
properties.setProperty("DELIMITER_STATEMENT_END", delimiterStatementEnd);
beetlGroupUtilConfiguration.setConfigProperties(properties);
ClasspathResourceLoader resourceLoader = new ClasspathResourceLoader(templatePath);
beetlGroupUtilConfiguration.setResourceLoader(resourceLoader);
// 調用Beetl的初始化方法
beetlGroupUtilConfiguration.init();
return beetlGroupUtilConfiguration;
}
}
三: 配置properties文件
application.properties文件:
server.port=8090
server.servlet.context-path=/
spring.datasource.url=jdbc:mysql://localhost:3306/building_materials?useUnicode=true&characterEncoding=UTF-8&nullCatalogMeansCurrent=true&tinyInt1isBit=false
spring.datasource.username=root
spring.datasource.password=bhy702
# beetl模板引擎的加載路徑。以resources為根路徑,此時表示加載resources/template文件夾中的模板文件
beetl.template-path = template
# beetl模板引擎語法開始標記
beetl.delimiter-statement-start = @
# beetl模板引擎語法結束標記。為空時在有開始標記@的行末結束
beetl.delimiter-statement-end =
# 代碼文件的保存路徑,註釋後默認保存在本項目中
#project.base-path = F:\\\\360MoveData\\\\Users\\\\n551\\\\Desktop
為了便於查看代碼生成效果,默認代碼生成在此項目內,同時提供自定義代碼生成位置。自定義代碼生成位置只需配置application.properties中的project.base-path
四: 設計代碼模板(代碼模板沒限制,想怎麼設計都行)
下面以Entity.tpl代碼模板文件為例:
package ${props.params.packageName};
import lombok.Data;
@for(column in props.columnList){
@if(column.type=='Date'){
import java.util.Date;
@break;
@}}
\\@Data
public class ${props.className}{
@for(column in props.columnList){
private ${column.type} ${column.lowerPropertyName};
@}
}
五: 根據代碼模板確定所需參數數據,添加代碼模板的工廠實例。
為了便於開發,我封裝了一個模板所需的參數類TplProperties
TplProperties參數類:
/**
* @author: brbai
* @create: 2019-12-26 11:13:42
* @description: 模板參數
*/
@Data
public class TplProperties {
private String basePath;
private String rootPackage;
private String tableName;
private List<column> columnList;/<column>
private Map<string> params = new HashMap();;/<string>
/**
* 表名格式轉換
* xxx_yyy->XxxYyy
*/
private String className;
/**
* 表名格式轉換
* xxx_yyy->xxxYyy
*/
private String propertyName;
public TplProperties(String basePath, String rootPackage, String tableName, List<column> columnList) {/<column>
this.basePath = basePath;
this.rootPackage = rootPackage;
this.tableName = tableName;
this.columnList = columnList;
}
public TplProperties(String rootPackage, String tableName, List<column> columnList) {/<column>
this.rootPackage = rootPackage;
this.tableName = tableName;
this.columnList = columnList;
}
public String getClassName() {
return StringUtil.mapTableNameToClassName(tableName);
}
public String getPropertyName() {
return StringUtil.mapTableNameToPropertyName(tableName);
}
public void setParam(String key,Object value) {
this.params.put(key,value);
}
public String getBasePath() {
if(basePath == null){
//未在properties文件中設置代碼生成路徑時,代碼默認生成在此項目下
return System.getProperty("user.dir") + "/src";
}
return basePath;
}
}
工廠實例:
/**
* @author: brbai
* @create: 2019-12-14 19:12:59
* @description:
*/
public class Entity implements Code {
@Override
public void create(GroupTemplate gt, TplProperties properties, String tplPath) throws IOException {
String packageName = properties.getRootPackage()+ ".entity";
properties.setParam("packageName",packageName);
Template t = gt.getTemplate(tplPath);
t.binding("props", properties);
GenerateUtil.createFile(t,properties.getBasePath()+"/main/java/"
+ packageName.replace(".", "/") + "/" + properties.getClassName() + ".java");
}
}
六: 識別數據庫類型,讀取數據庫表結構
/**
* @Description: 獲取數據庫表結構
* @Param: [sqlSessionFactory]
* @return: java.util.Map<java.lang.string>>/<java.lang.string>
*/
public static Map<string>> getDatabaseAttribute(SqlSession sqlSession) throws SQLException {/<string>
Map<string>> databaseAttribute = new HashMap<>();/<string>
Connection connection = sqlSession.getConnection();
//獲得數據庫信息
DatabaseMetaData metaData = connection.getMetaData();
String databaseName = metaData.getDatabaseProductName();
if ("MySQL".equals(databaseName)) {
//獲得數據庫表
ResultSet resultSet = metaData.getTables(null, null, null, new String[]{"TABLE"});
while (resultSet.next()) {
String tableName = resultSet.getString(3);
String sql = "SELECT * FROM " + tableName;
PreparedStatement preparedStatement = connection.prepareStatement(sql);
ResultSet set = preparedStatement.executeQuery();
//獲得表信息
ResultSetMetaData md = set.getMetaData();
//獲得表字段數
int columnCount = md.getColumnCount();
Map<string> attributes = new LinkedHashMap<>();/<string>
for (int i = 1; i <= columnCount; i++) {
//字段名
String columnName = md.getColumnName(i);
//字段屬性
String columnType = md.getColumnTypeName(i);
attributes.put(columnName, columnType);
}
databaseAttribute.put(tableName,attributes);
}
}else if("Oracle".equals(databaseName)){
//DEVTEST是oracle的用戶名。此Oracle代碼還沒怎麼測試。
ResultSet rs = metaData.getTables("null", "DEVTEST", "%", new String[]{"TABLE"});
while (rs.next()) {
String tableName = rs.getString("TABLE_NAME");
ResultSet columns = metaData
.getColumns(null, "DEVTEST", tableName, "%");
Map<string> attributes = new LinkedHashMap<>();/<string>
while (columns.next()) {
attributes.put(columns.getString("COLUMN_NAME"), columns.getString("TYPE_NAME"));
}
databaseAttribute.put(tableName, attributes);
}
}
return databaseAttribute;
}
七: 數據清洗,設置生成代碼的包名,獲取工廠實例生成代碼文件
/**
* @author: brbai
* @create: 2019-11-20 14:12:12
* @description: test
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class CodeTest {
@Autowired
private SqlSessionFactory sqlSessionFactory;
@Autowired
private BeetlGroupUtilConfiguration beetlConfig;
@Autowired
private CodeFactory codeFactory;
@Value("${project.base-path:#{null}}")
private String basePath;
@Test
public void codeGeneratorTest() throws SQLException{
//生成代碼的項目包名
String rootPackage = "aaa.bbb.ccc";
GroupTemplate gt = beetlConfig.getGroupTemplate();
//獲取數據庫表結構
SqlSession sqlSession = sqlSessionFactory.openSession();
Map<string>> databaseAttribute = DBUtil.getDatabaseAttribute(sqlSession);/<string>
String databaseName = sqlSession.getConnection().getMetaData().getDatabaseProductName();
databaseAttribute.forEach((tableName,columnMap)->{
List<column> columnList = new ArrayList<>();/<column>
columnMap.forEach((name,type)->{
String javaType = null;
//數據庫行字段類型以及字段名格式轉換,並存入模板參數集合
if("MySQL".equals(databaseName)){
javaType = DBUtil.sqlTypeToJavaType(type);
}else if("Oracle".equals(databaseName)){
javaType = DBUtil.oracleSqlTypeToJavaType(type);
}
columnList.add(new Column(name, javaType, StringUtil.mapUnderscoreToCamelCase(name), StringUtil.mapTableNameToClassName(name)));
});
//構建參數
TplProperties properties = null;
if(basePath != null){
properties = new TplProperties(basePath,rootPackage,tableName,columnList);
}else{
properties = new TplProperties(rootPackage,tableName,columnList);
}
try {
//代碼生成
codeFactory.getCodeInstance("CONTROLLER").create(gt,properties,"/Controller.tpl");
codeFactory.getCodeInstance("SERVICE").create(gt,properties,"/Service.tpl");
codeFactory.getCodeInstance("ENTITY").create(gt,properties,"/Entity.tpl");
codeFactory.getCodeInstance("MAPPER").create(gt,properties,"/Mapper.tpl");
codeFactory.getCodeInstance("MAPPER_XML").create(gt,properties,"/MapperXml.tpl");
} catch (IOException e) {
e.printStackTrace();
}
});
}
}
運行codeGeneratorTest()方法
效果圖如下:
未配置代碼生成路徑時:
配置了代碼生成路徑時:
閱讀更多 架構師公社 的文章