由於每次開發後臺管理模塊的時候,發現都是做的事情都是一樣的,做的邏輯都是一樣的,只是業務不一樣而已,並且在創建文件很浪費的時間。
1.為什麼會有代碼生成器的誕生?
發現現在很多開源的框架和公司內部框架都會有自帶的代碼生成器功能,為什麼它會出現在我們的框架的一部分呢?簡單的說,它是為了程式設計師偷懶的一個工具,也可以說,它也是一種敏捷開發的體現。它不會在乎項目的業務是什麼,它關注如何創建文件和一些自動寫好的方法,解決了重複勞動的難題,釋放無聊的CRUD功能的編寫。
2.說一說代碼生成器的原理
首先我們先說一說代碼生成器的原理是什麼,我們根據一個表名通過SQL查詢資料庫,獲取一張表的屬性(列名,數據類型,長度.....) ,然後通過IO流修改模板的數據。
3.根據表名如何手寫 SQL 獲取表結構信息
在這裡我按照mysql的資料庫來舉例子,在MYSQL中,一個庫,一張表也算是一條數據存儲在某張表裡面,那麼我們可以理解某張表的一個列就是一條數據,N個列,就有N行數據.
在MYSQL中,在資料庫information_schema中的表COLUMNS就是存儲所有表的屬性,
下面是COLUMNS的表信息
根據上面的列名和描述,我們可以通 SQL 查詢出 Java Entity 對應要的數據:
SELECT TABLE_SCHEMA AS tableSchema, TABLE_NAME AS tableName, COLUMN_NAME AS columnName, ORDINAL_POSITION AS ordinalPosition, IS_NULLABLE AS notNullFlag, DATA_TYPE AS dataType, CHARACTER_MAXIMUM_LENGTH AS columnLength, COLUMN_KEY AS cloumnKey, COLUMN_COMMENT AS cloumnComent FROM information_schema.columns WHERE table_schema = '' //對應的資料庫名 AND table_name = '' //對應數據表名
舉例說明一下,我先創建一張用戶表 tb_sys_user,下面是 DDL 信息:
CREATE TABLE `tb_sys_user` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用戶id', `username` varchar(20) NOT NULL COMMENT '登錄名', `name` varchar(50) NOT NULL COMMENT '真實姓名', `password` varchar(32) NOT NULL COMMENT '密碼', `sex` varchar(2) NOT NULL DEFAULT '1' COMMENT '性別,1男2女', `staff_no` varchar(20) DEFAULT NULL COMMENT '編號', `email` varchar(50) DEFAULT NULL COMMENT '郵箱', `mobile_phone` varchar(20) DEFAULT NULL COMMENT '手機號碼', `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否禁用,0是,1否', `create_time` datetime NOT NULL COMMENT '創建時間', `update_time` datetime NOT NULL COMMENT '修改時間', `department_id` int(11) DEFAULT NULL COMMENT '部門id', PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8 COMMENT='系統用戶表'
然後我使用上面的 SQL 查詢:
上面查詢出來就是我們想要的 Java Entity 信息。接下來就要根據查詢信息組裝一個 Java Entity。
4. 教你如何自動生成 Java Bean 實體
簡單說一下 Java Bean,Java Bean 必須準守 Java Bean API 規範,它有比較特別的特徵:
提供一個默認無參的構造函數需要被序列化並且實現了 Serializable 接口可能有一系列可讀寫屬性可能有一系列的 getter 或 setter 方法Javabean 屬性格式 getPropertyName()、setPropertyName()
那麼我們定義的一個通用的模板。
package 包路徑import java.io.Serializable;public class 類名 implements java.io.Serializable{ private 數據類型 欄位名; public 類名 () { } public void set首字符大寫的欄位名(數據類型 欄位名){ this.欄位名 = 欄位名; } public 數據類型 get首字符大寫的欄位名(){ RETURN 欄位名; }}
根據上面的模板的,我們通過文件流讀出來,使用字符串的關鍵字替換的方法 String.replace() 方法替換模板的關鍵字,然後再通過指定文件名寫到對應的文件路徑下,這樣自動生成 Java Bean 就出來的,簡單的來說,就是通過 IO 讀對應的 Java Bean 的文件和字符串替換方法。
5. 如何自動生成 Entity、Dao、Service、Controller 和 CRUD 的方法
平時創建一個模板的代碼要建立 Entity、Dao、Service、Controller 對應的文件和添加 CRUD 的方法。那麼我們為了代碼的一致性,減少不必要的錯誤,我們可以先建立一個 BaseDao,把通用的 CRUD 方法寫好,然後我們新建一個對應的業務 Dao,繼承父類 BaseDao,CRUD 的方法就不用寫了,接下來就是對應的模板。下面我舉例說一下:
BaseDao
package org.john.fastcore.base.dao;import java.util.List;import java.util.Map;import org.apache.ibatis.annotations.Param;import org.john.fastcore.base.bean.Page;/** * 基類DAO * * @author JohnDeng 2017年11月9日上午10:31:10 * @param <T> */public interface BaseDao<T, ID> { public T findById(@Param("id") ID id); public List<T> findAll(); public T get(T entity); public List<T> getList(T entity); public List<T> getListByPage(Page<T> page); public int insert(T entity); public int update(T entity); public int deleteById(@Param("id") ID id); public int deleteBatchById(List<T> list); public int insertBatch(List<T> list); public int updateBatch(List<T> list); public List<Map<String, Object>> getListMap(Map<String, Object> param); public List<Map<String, Object>> getListMap(T entity); public int getTotalCount(Page<T> page); public int delete(T entity); public int deleteBatch(List<T> list);}
對應的模板 DAO:
package ${packgePath};import ${extendsBaseDaoPath};import ${entityPackgePath}.${className};import org.apache.ibatis.annotations.Mapper;/** * ${classDescription} * @author ${author} * @datatime ${datatime} */@Mapperpublic interface ${className}Dao extends BaseDao<${className},${primaryKey}>{}
可以看到,我們就只要替換模板的關鍵字就再通過 IO 流寫到指定的文件路徑,創建一個新的 .java 文件,看上去高大上的代碼生成器,其實原理很簡單,對應的 Service、Controller 都是同樣的道理,我就不舉例子,源碼:spring-boot-code-generator。
6. 說一說代碼生成器的原理
上面也說到,原理其實很簡單,使用了 Java 的 IO 流讀文件、字符串的替換,然後使用了把字符串轉成文件流寫到指定路徑,這是整個流程。其中想做成統一的 CRUD 方法,我們還會使用到 Java 泛型,發射等技術。