1. 程式人生 > >用Freemarker製作程式碼生成器生成mybatis.xml和java程式碼

用Freemarker製作程式碼生成器生成mybatis.xml和java程式碼

一、外來鍵物件簡單封裝

@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時要用到。

@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());
		}
	}
}
四、程式碼生成器MyGenerator具體實現

           詳情可以參考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);
	}
}