用Freemarker製作程式碼生成器生成mybatis.xml和java程式碼
阿新 • • 發佈:2019-02-12
一、外來鍵物件簡單封裝
@Setter
@Getter
public class AssociationObject {
private String property;
private String columnPrefix;
private String javaType;
}
二、型別的判斷
用來判斷是否是java中的型別,若是java中的型別,則為不可能為是外來鍵,若是自定義型別,則就該欄位就是關聯的外來鍵。mybatis.xml生成檔案中可以根據是否是外來鍵生成關聯查詢。
public class JudgeType { public static boolean judgeType(String type) { String javaType = ""; if (type.contains(".")) { //型別的擷取 int lastIndexOf = type.lastIndexOf("."); javaType = type.substring(lastIndexOf + 1); } else { javaType = type; } switch (javaType) { case "int": return true; case "Integer": return true; case "long": return true; case "Long": return true; case "double": return true; case "Double": return true; case "String": return true; case "BigDecimal": return true; case "Boolean": return true; case "boolean": return true; case "Date": return true; default: return false; } } }
三、型別轉換
將java中的型別轉換為資料中的型別,在執行create table的時候要用到。
/** * @version 建立時間:2017-1-22 下午7:25:25 * @Description 描述:型別轉換器,把mysql中的型別轉為java中的型別 */ public class TypeConverter { /** * @param type * java中的型別 * @return mySql中的資料型別 * @Description 描述:把傳進來的java型別,型別轉換為資料庫中的型別 */ public static String javaType2MySqlType(Entry<String, String> entry) { String javaType = ""; if (entry.getValue().contains(".")) { // 型別的擷取 int lastIndexOf = entry.getValue().lastIndexOf("."); javaType = entry.getValue().substring(lastIndexOf + 1); } else { javaType = entry.getValue(); } switch (javaType) { case "String": return entry.getKey() + " VARCHAR(255) ,"; case "byte[]": return entry.getKey() + " BLOB ,"; case "int": return entry.getKey() + " INTEGER ,"; case "Integer": return entry.getKey() + " INTEGER ,"; case "Boolean": return entry.getKey() + " BIT ,"; case "boolean": return entry.getKey() + " BIT ,"; case "Long": return entry.getKey() + " BIGINT ,"; case "long": return entry.getKey() + " BIGINT ,"; case "float": return entry.getKey() + " FLOAT ,"; case "Float": return entry.getKey() + " FLOAT ,"; case "double": return entry.getKey() + " DOUBLE ,"; case "Double": return entry.getKey() + " DOUBLE ,"; case "BigDecimal": return entry.getKey() + " DECIMAL ,"; case "Date": return entry.getKey() + " DATETIME,"; default: return entry.getKey() + "_id Long,"; } } }
三、實體類相關資訊封裝
在freemarker模板方法中行成mybatis.xml時要用到。
四、程式碼生成器MyGenerator具體實現@Setter @Getter public class ClassInfo { private String basePackage; // 基本包 private String bigClassName; // 大寫類名 private String smallClassName;// 首字母小寫的類名 private LinkedHashMap<String, String> fieldMap = new LinkedHashMap<>(); private List<String> genericFieldList = new ArrayList<>(); private LinkedHashMap<String, String> importFieldMap = new LinkedHashMap<>(); private List<AssociationObject> association = new ArrayList<>(); private String insert; private String delete; private String update; private String selectByPrimaryKey; private String selectAll; private String queryForCount; private String queryListData; private String limit; public ClassInfo(Class<?> clazz) throws Exception { String pkgName = clazz.getPackage().getName(); this.basePackage = pkgName.substring(0, pkgName.lastIndexOf(".")); this.bigClassName = clazz.getSimpleName(); this.smallClassName = this.bigClassName.substring(0, 1).toLowerCase() + this.bigClassName.substring(1); this.getObjectFiled(clazz); } public void getObjectFiled(Class<?> clazz) throws Exception { // 建立父類物件 Object currentObject = clazz.getDeclaredConstructor().newInstance(); if (currentObject instanceof BaseDomain) { Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { // java中的修飾碼 如public 1 private 2 protect 4 static 8 if (field.getModifiers() < 8) { // 集合型別的不新增 if (!field.getType().getName().endsWith("List") && !field.getType().getName().endsWith("Map")) { this.fieldMap.put(field.getName(), field.getType().getName()); } } } // 遞迴呼叫父類中的方法 getObjectFiled(clazz.getSuperclass()); } } }
詳情可以參考ftl入門到放棄。
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import freemarker.template.Configuration;
import freemarker.template.Template;
/**
* @version 建立時間:2017-2-22 下午11:21:27
* @Description 描述:Mybatis程式碼生成器
*/
public class MyGenerator {
private static final int FEILDL_ENGTH = 1;// 統一定義擷取字串的長度為多少字母
public static void main(String[] args) throws Exception {
ClassInfo info = new ClassInfo(BlogType.class);
// 建立表
createTable(info);
// 生成xml檔案
createMyBatisXML(info, "Mapper.xml", "src/main/java/{0}/mapper/{1}Mapper.xml");
// mapper介面
createMapper(info, "Mapper.java", "src/main/java/{0}/mapper/{1}Mapper.java");
// 生成QueryOBject
createQueryObject(info, "QueryObject.java", "src/main/java/{0}/query/{1}QueryObject.java");
// 生成Service介面
createService(info, "IService.java", "src/main/java/{0}/service/I{1}Service.java");
// 生成Service實現類
createServiceImpl(info, "ServiceImpl.java", "src/main/java/{0}/service/impl/{1}ServiceImpl.java");
}
@SuppressWarnings("deprecation")
private static Configuration config = new Configuration();
static {
try {
config.setDirectoryForTemplateLoading(new File("templates"));
} catch (IOException e) {
e.printStackTrace();
}
}
public static void createQueryObject(ClassInfo info, String templateFile, String targetFile) throws Exception {
createFile(info, templateFile, targetFile);
System.out.println("生成" + info.getBigClassName() + "QueryObject");
}
public static void createMapper(ClassInfo info, String templateFile, String targetFile) throws Exception {
createFile(info, templateFile, targetFile);
System.out.println("生成" + info.getBigClassName() + "Mapper介面");
}
public static void createService(ClassInfo info, String templateFile, String targetFile) throws Exception {
createFile(info, templateFile, targetFile);
System.out.println("生成I" + info.getBigClassName() + "Service介面");
}
public static void createServiceImpl(ClassInfo info, String templateFile, String targetFile) throws Exception {
createFile(info, templateFile, targetFile);
System.out.println("生成" + info.getBigClassName() + "ServiceImpl實現");
}
public static void createController(ClassInfo info, String templateFile, String targetFile) throws Exception {
createFile(info, templateFile, targetFile);
System.out.println("生成" + info.getBigClassName() + "Controller檔案");
}
// 資料庫表的建立
public static void createTable(ClassInfo info) throws SQLException {
StringBuilder sql = new StringBuilder();
sql.append("CREATE TABLE ").append(info.getBigClassName());
LinkedHashMap<String, String> propertys = info.getFieldMap();
ListIterator<Map.Entry<String, String>> list = new ArrayList<Map.Entry<String, String>>(propertys.entrySet())
.listIterator(propertys.size());
sql.append(" ( ");
while (list.hasPrevious()) {
Map.Entry<String, String> entry = list.previous();
if ("id".equals(entry.getKey())) {
// 主鍵拼接
sql.append("id " + "BIGINT PRIMARY KEY auto_increment ,");
} else {
// 非主鍵拼接
sql.append(TypeConverter.javaType2MySqlType(entry));
}
}
sql.append(" ); ");
sql.deleteCharAt(sql.lastIndexOf(","));
// 建立連線
Connection con = JDBCUtil.getConnection();
PreparedStatement ps = con.prepareStatement(sql.toString());
boolean result = ps.execute();
if (result) {
throw new RuntimeException("建立表" + info.getBigClassName() + "異常!!!");
} else {
System.out.println("建立表" + info.getBigClassName() + "成功!");
}
}
// 其他java檔案的建立
private static void createFile(ClassInfo info, String templateFile, String targetFile) throws Exception {
// System.out.println(MessageFormat.format("你好{0},明天去{1}", "小強","打球"));
Template template = config.getTemplate(templateFile);
targetFile = MessageFormat.format(targetFile, info.getBasePackage().replace(".", "/"), info.getBigClassName());
System.out.println(templateFile);
System.out.println(targetFile);
File file = new File(targetFile);
// 如果檔案存在則報錯,不會覆蓋以前的檔案
if (file.exists()) {
throw new RuntimeException(file.getName() + "已經存在!");
}
File parentFile = file.getParentFile();
// 建立檔案目錄
if (!parentFile.exists()) {
parentFile.mkdirs();
}
template.process(info, new FileWriter(file));
}
// Mybatis檔案的建立
private static void createMyBatisXML(ClassInfo info, String templateFile, String targetFile) throws Exception {
LinkedHashMap<String, String> propertys = info.getFieldMap();
LinkedHashMap<String, String> importFieldMap = info.getImportFieldMap();
List<String> genericFieldList = info.getGenericFieldList();
List<AssociationObject> association = info.getAssociation();
StringBuilder insert1 = new StringBuilder().append("insert into " + info.getBigClassName() + " (");
StringBuilder insert2 = new StringBuilder().append(" values( ");
StringBuilder delete = new StringBuilder().append("delete from " + info.getBigClassName() + " where id =#{id}");
StringBuilder update = new StringBuilder().append("update " + info.getBigClassName() + " set ");
StringBuilder selectselectByPrimaryKey = new StringBuilder().append("select ");
ListIterator<Map.Entry<String, String>> list = new ArrayList<Map.Entry<String, String>>(propertys.entrySet())
.listIterator(propertys.size());
while (list.hasPrevious()) {
String key = list.previous().getKey();
System.out.println(key);
String value = propertys.get(key);
if (JudgeType.judgeType(value)) {
// 插入時不需要主鍵
if (!key.equals("id")) {
genericFieldList.add(key);
insert1.append(" " + key + " ,");
insert2.append(" #{" + key + "} ,");
update.append(" " + key + "=#{" + key + "}, ");
}
selectselectByPrimaryKey
.append(info.getSmallClassName().subSequence(0, MyGenerator.FEILDL_ENGTH) + "." + key + ", ");
} else {
// 外來鍵關聯的相關屬性
AssociationObject associationObject = new AssociationObject();
associationObject.setColumnPrefix(key.substring(0, MyGenerator.FEILDL_ENGTH) + "_");
associationObject.setProperty(key);
associationObject.setJavaType(value);
association.add(associationObject);
insert1.append(" " + key + "_id ,");
insert2.append(" #{" + key + ".id} ,");
update.append(" " + key + "_id=#{" + key + ".id}, ");
int index = value.lastIndexOf(".");
value = value.substring(index + 1);
importFieldMap.put(key, value);
}
}
int index = insert1.lastIndexOf(",");
String str1 = insert1.substring(0, index) + " )";
index = insert2.lastIndexOf(",");
String str2 = insert2.substring(0, index) + " )";
// 增加
info.setInsert(str1 + str2);
System.out.println("增加操作 " + str1 + str2);
// 刪除
info.setDelete(delete.toString());
System.out.println("刪除操作 " + delete.toString());
index = update.lastIndexOf(",");
String subUpdate = update.substring(0, index);
subUpdate = subUpdate + " where id=#{id}";
// 更改操作
info.setUpdate(subUpdate);
System.out.println("更改操作 " + subUpdate);
// 判斷是否有外來鍵
if (importFieldMap.size() <= 0) {
index = selectselectByPrimaryKey.lastIndexOf(",");
String str = selectselectByPrimaryKey.substring(0, index);
// 條數的查詢
String queryForCount = "select count(" + info.getSmallClassName().substring(0, MyGenerator.FEILDL_ENGTH)
+ ".id" + ") from " + info.getBigClassName() + " "
+ info.getSmallClassName().substring(0, MyGenerator.FEILDL_ENGTH);
info.setQueryForCount(queryForCount);
System.out.println("查詢條數 " + queryForCount);
// 查詢結果集
info.setQueryListData(str + " from " + info.getSmallClassName() + " "
+ info.getSmallClassName().substring(0, MyGenerator.FEILDL_ENGTH));
System.out.println("查詢所有 " + str + " from " + info.getSmallClassName() + " "
+ info.getSmallClassName().substring(0, MyGenerator.FEILDL_ENGTH));
// 分頁相關
info.setLimit("limit #{currentPage},#{pageSize}");
str = str + " from " + info.getSmallClassName() + " where "
+ info.getSmallClassName().substring(0, MyGenerator.FEILDL_ENGTH) + ".id=#{id}";
// 根據主鍵的查詢
info.setSelectByPrimaryKey(str);
System.out.println("主鍵查詢 " + str);
} else {
Set<Entry<String, String>> entrySet = importFieldMap.entrySet();
for (Entry<String, String> entry : entrySet) {
selectselectByPrimaryKey.append(entry.getKey().substring(0, MyGenerator.FEILDL_ENGTH) + ".id as "
+ entry.getKey().substring(0, MyGenerator.FEILDL_ENGTH) + "_id ,");
}
index = selectselectByPrimaryKey.lastIndexOf(",");
String str = selectselectByPrimaryKey.substring(0, index);
str = str + " from " + info.getBigClassName() + " "
+ info.getSmallClassName().substring(0, MyGenerator.FEILDL_ENGTH);
for (Entry<String, String> entry : entrySet) {
str = str + " left join " + entry.getValue() + " "
+ entry.getKey().substring(0, MyGenerator.FEILDL_ENGTH) + " on " + "("
+ info.getSmallClassName().substring(0, MyGenerator.FEILDL_ENGTH) + "." + entry.getKey()
+ "_id=" + entry.getKey().substring(0, MyGenerator.FEILDL_ENGTH) + ".id)";
}
String queryForCount = "select count(" + info.getSmallClassName().substring(0, MyGenerator.FEILDL_ENGTH)
+ ".id" + ") from " + info.getBigClassName() + " "
+ info.getSmallClassName().substring(0, MyGenerator.FEILDL_ENGTH);
info.setQueryForCount(queryForCount);
System.out.println("查詢條數 " + queryForCount);
// 查詢結果集
info.setQueryListData(str);
System.out.println("查詢所有 " + str);
// 分頁相關
info.setLimit("limit #{start},#{pageSize}");
str = str + " where " + info.getSmallClassName().substring(0, MyGenerator.FEILDL_ENGTH) + ".id=#{id}";
// 根據主鍵的查詢
info.setSelectByPrimaryKey(str);
System.out.println("主鍵查詢 " + str);
}
Template template = config.getTemplate(templateFile);
targetFile = MessageFormat.format(targetFile, info.getBasePackage().replace(".", "/"), info.getBigClassName());
File file = new File(targetFile);
File parentFile = file.getParentFile();
// 建立檔案目錄
if (!parentFile.exists()) {
parentFile.mkdirs();
}
// 生成xml檔案
template.process(info, new FileWriter(file));
}
}
五、模板示意圖
IService.java檔案模板:
package ${basePackage}.service;
import java.util.List;
import ${basePackage}.page.PageResult;
import ${basePackage}.domain.${bigClassName};
import ${basePackage}.query.${bigClassName}QueryObject;
public interface I${bigClassName}Service {
void insert(${bigClassName} ${smallClassName});
void delete(${bigClassName} ${smallClassName});
${bigClassName} select(${bigClassName} ${smallClassName});
void update(${bigClassName} ${smallClassName});
PageResult query(${bigClassName}QueryObject qo);
List<${bigClassName}> queryForList(${bigClassName}QueryObject qo);
}
Mapper.java介面模板:
package ${basePackage}.mapper;
import java.util.List;
import ${basePackage}.domain.${bigClassName};
import ${basePackage}.query.${bigClassName}QueryObject;
public interface ${bigClassName}Mapper {
void insert(${bigClassName} ${smallClassName});
void delete(${bigClassName} ${smallClassName});
void update(${bigClassName} ${smallClassName});
${bigClassName} select(${bigClassName} ${smallClassName});
int queryTotalCount(${bigClassName}QueryObject qo);
List<${bigClassName}> queryListData(${bigClassName}QueryObject qo);
}
Mapper.xml模板:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="${basePackage}.mapper.${bigClassName}Mapper">
<resultMap id="${smallClassName}ResultMap" type="${basePackage}.domain.${bigClassName}">
<id column="id" property="id" jdbcType="BIGINT" />
<#list genericFieldList as genericField>
<result column="${genericField}" property="${genericField}" />
</#list>
<#list association as item>
<association property="${item.property}" columnPrefix="${item.columnPrefix}"
javaType="${item.javaType}">
<!-- 物件的關聯 -->
<id property="id" column="id"></id>
</association>
</#list>
</resultMap>
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
${insert}
</insert>
<delete id="delete">
${delete}
</delete>
<update id="update">
${update}
</update>
<select id="select" resultMap="${smallClassName}ResultMap">
${selectByPrimaryKey}
</select>
<select id="queryTotalCount" resultType="int">
${queryForCount}
</select>
<select id="queryListData" resultMap="${smallClassName}ResultMap">
${queryListData}
<if test="pageSize>=0">
${limit}
</if>
</select>
</mapper>
QueryObject.java模板程式碼:
package ${basePackage}.query;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public class ${bigClassName}QueryObject extends QueryObject {
}
ServiceImpl.java模板程式碼:
package ${basePackage}.service.impl;
import java.util.List;
import ${basePackage}.page.PageResult;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import ${basePackage}.domain.${bigClassName};
import ${basePackage}.mapper.${bigClassName}Mapper;
import ${basePackage}.query.${bigClassName}QueryObject;
import ${basePackage}.service.I${bigClassName}Service;
@Service
public class ${bigClassName}ServiceImpl implements I${bigClassName}Service {
@Autowired
private ${bigClassName}Mapper ${smallClassName}Mapper;
@Override
public void insert(${bigClassName} ${smallClassName}) {
${smallClassName}Mapper.insert(${smallClassName});
}
@Override
public void delete(${bigClassName} ${smallClassName}){
${smallClassName}Mapper.delete(${smallClassName});
}
@Override
public void update(${bigClassName} ${smallClassName}) {
this.${smallClassName}Mapper.update(${smallClassName});
}
@Override
public ${bigClassName} select(${bigClassName} ${smallClassName}) {
return this.${smallClassName}Mapper.select(${smallClassName});
}
@Override
public PageResult query(${bigClassName}QueryObject qo) {
int count = ${smallClassName}Mapper.queryTotalCount(qo);
if (count > 0) {
List<${bigClassName}> list = ${smallClassName}Mapper.queryListData(qo);
return new PageResult(qo.getCurrentPage(), qo.getPageSize(), count, list);
}
return PageResult.empty(qo.getPageSize());
}
@Override
public List<${bigClassName}> queryForList(${bigClassName}QueryObject qo) {
return ${smallClassName}Mapper.queryListData(qo);
}
}