EasyCode實現資料庫到Swagger全自動化
簡介
EasyCode是基於IntelliJ IDEA開發的程式碼生成外掛,通過自定義生成模板可以完成定製化的 Mapper Service Controller 生成,結合資料庫 Comment還可以實現從資料庫到 Swagger 的一鍵配置,非常的強大與方便,專案地址:EasyCode--碼雲 這裡推薦大家使用
安裝
和一般的Idea外掛安裝方式一樣,點選 File -> Setting -> Plugins 搜尋 EasyCode 點選 Install 安裝即可,安裝之後需要重啟,當然如果是Idea最新的2019.3版本支援外掛熱安裝就不需要重啟了。
連線資料庫
安裝之後需要使用Idea連線資料庫,在Idea的右側有個DataBase選項卡,點選之後選擇對應的資料庫。這邊我使用的是 Mysql 資料庫
配置好連線名稱,連線路徑,賬號密碼和資料庫測試連線,測試通過後點選OK,就可以成功的連線到資料庫,這裡Idea的資料庫圖形化介面做的也挺好的。
配置EasyCode的模板
1. 配置作者名稱
同樣是 File -> Settings -> other Settings 選擇 EasyCode 或者直接搜尋 EasyCode 進行編輯,首先鍵入作者名稱,這樣在生成的類上面就會加上你的名字,時間等資訊。
2. Type Manager 對映型別管理
此頁面是用來建立資料庫欄位型別與Java變數型別關係的,其中已經預先定義好了很多對應關係,但對於 tinyint((\d+))? unsigned (無符號的byte)型別卻沒有進行預定義,如果不進行手動配置,在進行逆向生成的時候會將其對映成 Java Object 型別,所以需要我們進行手動的新增關聯關係
3. Template Setting 模板設定
這個頁面就是我們主要需要配置的頁面了,我們可以自己新建一個模板組,也可以直接在原來模板檔案的基礎上進行修改。這裡我已經對原有的模板進行了自定義的修改,保留了 entity.java mapper.java mapper.xml service.java controller.java 去掉了原有的 dao serviceImpl.具體的模板內容如下,需要的朋友可以直接複製修改。
當然也可以點選配置作者名稱頁面的匯入模板按鈕,輸入對應的 Token 進行一鍵替換由於token只能保持6個小時,所以我就不在這裡貼上了。
entity.java
實體類模板改動如下
- 刪除了原本的 Getter/Setter 採用 lombok 的 @Data 註解替換之
- 類新增 @ApiModel("$tableInfo.comment") 註解,讀取 Mysql 中表的註釋作為類在Swagger中的解釋
- 欄位新增 @ApiModelProperty("$column.comment") 註解,讀取 Mysql 中欄位的註釋作為對應引數在Swagger中的註釋
##引入巨集定義
$!define
##使用巨集定義設定回撥(儲存位置與檔案字尾)
#save("/entity", ".java")
##使用巨集定義設定包字尾
#setPackageSuffix("entity")
##使用全域性變數實現預設包匯入
$!autoImport
import java.io.Serializable;
import io.swagger.annotations.*;
import lombok.Data;
##使用巨集定義實現類註釋資訊
#tableComment("實體類")
@Data
@ApiModel("$tableInfo.comment")
public class $!{tableInfo.name} implements Serializable {
private static final long serialVersionUID = $!tool.serial();
#foreach($column in $tableInfo.fullColumn)
#if(${column.comment})/**
* ${column.comment}
*/#end
@ApiModelProperty("$column.comment")
private $!{tool.getClsNameByFullName($column.type)} $!{column.name};
#end
}
mapper.java
Mapper介面改動如下
- 新增 @Mapper @Repository 註解
##定義初始變數
#set($tableName = $tool.append($tableInfo.name, "Mapper"))
##設定回撥
$!callback.setFileName($tool.append($tableName, ".java"))
$!callback.setSavePath($tool.append($tableInfo.savePath, "/mapper"))
##拿到主鍵
#if(!$tableInfo.pkColumn.isEmpty())
#set($pk = $tableInfo.pkColumn.get(0))
#end
#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}mapper;
import $!{tableInfo.savePackageName}.entity.$!{tableInfo.name};
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* $!{tableInfo.comment}($!{tableInfo.name})表資料庫訪問層
*
* @author $!author
* @since $!time.currTime()
*/
@Mapper
@Repository
public interface $!{tableName} {
/**
* 通過ID查詢單條資料
*
* @param $!pk.name 主鍵
* @return 例項物件
*/
$!{tableInfo.name} queryById($!pk.shortType $!pk.name);
/**
* 查詢指定行資料
*
* @param offset 查詢起始位置
* @param limit 查詢條數
* @return 物件列表
*/
List<$!{tableInfo.name}> queryAllByLimit(@Param("offset") int offset, @Param("limit") int limit);
/**
* 通過實體作為篩選條件查詢
*
* @param $!tool.firstLowerCase($!{tableInfo.name}) 例項物件
* @return 物件列表
*/
List<$!{tableInfo.name}> queryAll($!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name}));
/**
* 新增資料
*
* @param $!tool.firstLowerCase($!{tableInfo.name}) 例項物件
* @return 影響行數
*/
int insert($!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name}));
/**
* 修改資料
*
* @param $!tool.firstLowerCase($!{tableInfo.name}) 例項物件
* @return 影響行數
*/
int update($!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name}));
/**
* 通過主鍵刪除資料
*
* @param $!pk.name 主鍵
* @return 影響行數
*/
int deleteById($!pk.shortType $!pk.name);
}
mapper.xml
##引入mybatis支援
$!mybatisSupport
##設定儲存名稱與儲存位置
$!callback.setFileName($tool.append($!{tableInfo.name}, "Mapper.xml"))
$!callback.setSavePath($tool.append($modulePath, "/src/main/resources/mapper"))
##拿到主鍵
#if(!$tableInfo.pkColumn.isEmpty())
#set($pk = $tableInfo.pkColumn.get(0))
#end
<?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="$!{tableInfo.savePackageName}.mapper.$!{tableInfo.name}Mapper">
<resultMap type="$!{tableInfo.savePackageName}.entity.$!{tableInfo.name}" id="$!{tableInfo.name}Map">
#foreach($column in $tableInfo.fullColumn)
<result property="$!column.name" column="$!column.obj.name" jdbcType="$!column.ext.jdbcType"/>
#end
</resultMap>
<!--查詢單個-->
<select id="queryById" resultMap="$!{tableInfo.name}Map">
select
#allSqlColumn()
from $!{tableInfo.obj.parent.name}.$!tableInfo.obj.name
where $!pk.obj.name = #{$!pk.name}
</select>
<!--查詢指定行資料-->
<select id="queryAllByLimit" resultMap="$!{tableInfo.name}Map">
select
#allSqlColumn()
from $!{tableInfo.obj.parent.name}.$!tableInfo.obj.name
limit #{offset}, #{limit}
</select>
<!--通過實體作為篩選條件查詢-->
<select id="queryAll" resultMap="$!{tableInfo.name}Map">
select
#allSqlColumn()
from $!{tableInfo.obj.parent.name}.$!tableInfo.obj.name
<where>
#foreach($column in $tableInfo.fullColumn)
<if test="$!column.name != null#if($column.type.equals("java.lang.String")) and $!column.name != ''#end">
and $!column.obj.name = #{$!column.name}
</if>
#end
</where>
</select>
<!--新增所有列-->
<insert id="insert" keyProperty="$!pk.name" useGeneratedKeys="true">
insert into $!{tableInfo.obj.parent.name}.$!{tableInfo.obj.name}(#foreach($column in $tableInfo.otherColumn)$!column.obj.name#if($velocityHasNext), #end#end)
values (#foreach($column in $tableInfo.otherColumn)#{$!{column.name}}#if($velocityHasNext), #end#end)
</insert>
<!--通過主鍵修改資料-->
<update id="update">
update $!{tableInfo.obj.parent.name}.$!{tableInfo.obj.name}
<set>
#foreach($column in $tableInfo.otherColumn)
<if test="$!column.name != null#if($column.type.equals("java.lang.String")) and $!column.name != ''#end">
$!column.obj.name = #{$!column.name},
</if>
#end
</set>
where $!pk.obj.name = #{$!pk.name}
</update>
<!--通過主鍵刪除-->
<delete id="deleteById">
delete from $!{tableInfo.obj.parent.name}.$!{tableInfo.obj.name} where $!pk.obj.name = #{$!pk.name}
</delete>
</mapper>
service.java
服務方法改動如下,這裡我省略了 service 介面,而直接生成實現類。如果習慣於介面+實現類的使用方法可以保留介面和實現類,將@Servcie註解新增到介面上, Controller中繼續注入介面
##定義初始變數
#set($tableName = $tool.append($tableInfo.name, "Service"))
##設定回撥
$!callback.setFileName($tool.append($tableName, ".java"))
$!callback.setSavePath($tool.append($tableInfo.savePath, "/service"))
##拿到主鍵
#if(!$tableInfo.pkColumn.isEmpty())
#set($pk = $tableInfo.pkColumn.get(0))
#end
#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}service;
import $!{tableInfo.savePackageName}.entity.$!{tableInfo.name};
import $!{tableInfo.savePackageName}.mapper.$!{tableInfo.name}Mapper;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
/**
* $!{tableInfo.comment}($!{tableInfo.name})表服務實現類
*
* @author $!author
* @since $!time.currTime()
*/
@Service("$!tool.firstLowerCase($!{tableInfo.name})Service")
public class $!{tableName} {
@Autowired
private $!{tableInfo.name}Mapper $!tool.firstLowerCase($!{tableInfo.name})Mapper;
/**
* 通過ID查詢單條資料
*
* @param $!pk.name 主鍵
* @return 例項物件
*/
public $!{tableInfo.name} queryById($!pk.shortType $!pk.name) {
return this.$!{tool.firstLowerCase($!{tableInfo.name})}Mapper.queryById($!pk.name);
}
/**
* 查詢多條資料
*
* @param offset 查詢起始位置
* @param limit 查詢條數
* @return 物件列表
*/
public List<$!{tableInfo.name}> queryAllByLimit(int offset, int limit) {
return this.$!{tool.firstLowerCase($!{tableInfo.name})}Mapper.queryAllByLimit(offset, limit);
}
/**
* 新增資料
*
* @param $!tool.firstLowerCase($!{tableInfo.name}) 例項物件
* @return 例項物件
*/
public $!{tableInfo.name} insert($!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name})) {
this.$!{tool.firstLowerCase($!{tableInfo.name})}Mapper.insert($!tool.firstLowerCase($!{tableInfo.name}));
return $!tool.firstLowerCase($!{tableInfo.name});
}
/**
* 修改資料
*
* @param $!tool.firstLowerCase($!{tableInfo.name}) 例項物件
* @return 例項物件
*/
public $!{tableInfo.name} update($!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name})) {
this.$!{tool.firstLowerCase($!{tableInfo.name})}Mapper.update($!tool.firstLowerCase($!{tableInfo.name}));
return this.queryById($!{tool.firstLowerCase($!{tableInfo.name})}.get$!tool.firstUpperCase($pk.name)());
}
/**
* 通過主鍵刪除資料
*
* @param $!pk.name 主鍵
* @return 是否成功
*/
public boolean deleteById($!pk.shortType $!pk.name) {
return this.$!{tool.firstLowerCase($!{tableInfo.name})}Mapper.deleteById($!pk.name) > 0;
}
}
controller.java
控制層主要做了如下改動,
- 類上新增 @Api(tags = "$!{tableInfo.comment}($!{tableInfo.name})") 以在 Swagger 中顯示錶註釋
- selectOne 方法新增 @ApiOperation(value = "根據id查詢 $!{tableInfo.comment}")
- 修改介面為 RestFul 格式呼叫,並新增對應的註解
##定義初始變數
#set($tableName = $tool.append($tableInfo.name, "Controller"))
##設定回撥
$!callback.setFileName($tool.append($tableName, ".java"))
$!callback.setSavePath($tool.append($tableInfo.savePath, "/controller"))
##拿到主鍵
#if(!$tableInfo.pkColumn.isEmpty())
#set($pk = $tableInfo.pkColumn.get(0))
#end
#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}controller;
import $!{tableInfo.savePackageName}.entity.$!{tableInfo.name};
import $!{tableInfo.savePackageName}.service.$!{tableInfo.name}Service;
import org.springframework.web.bind.annotation.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
/**
* $!{tableInfo.comment}($!{tableInfo.name})表控制層
*
* @author $!author
* @since $!time.currTime()
*/
@Api(tags = "$!{tableInfo.comment}($!{tableInfo.name})")
@RestController
@RequestMapping("$!tool.firstLowerCase($tableInfo.name)")
public class $!{tableName} {
/**
* 服務物件
*/
@Autowired
private $!{tableInfo.name}Service $!tool.firstLowerCase($tableInfo.name)Service;
/**
* 通過主鍵查詢單條資料
*
* @param id 主鍵
* @return 單條資料
*/
@ApiOperation(value = "根據id查詢 $!{tableInfo.comment}")
@GetMapping("selectOne/{id}")
public $!{tableInfo.name} selectOne(@ApiParam(value = "$!pk.comment ID") @PathVariable("id") $!pk.shortType id) {
return this.$!{tool.firstLowerCase($tableInfo.name)}Service.queryById(id);
}
}
說明
說明文件:
屬性
$author 設定中的作者 java.lang.String
$encode 設定的編碼 java.lang.String
$modulePath 選中的module路徑 java.lang.String
$projectPath 專案絕對路徑 java.lang.String
物件
$tableInfo 表物件
obj 表原始物件 com.intellij.database.model.DasTable
name 表名(轉換後的首字母大寫)java.lang.String
comment 表註釋 java.lang.String
fullColumn 所有列 java.util.List<ColumnInfo>
pkColumn 主鍵列 java.util.List<ColumnInfo>
otherColumn 其他列 java.util.List<ColumnInfo>,除主鍵以外的列
savePackageName 儲存的包名 java.lang.String
savePath 儲存路徑 java.lang.String
saveModelName 儲存的model名稱 java.lang.String
columnInfo 列物件
obj 列原始物件 com.intellij.database.model.DasColumn
name 列名(首字母小寫) java.lang.String
comment 列註釋 java.lang.String
type 列型別(型別全名) java.lang.String
shortType 列型別(短型別) java.lang.String
custom 是否附加列 java.lang.Boolean
ext 附加欄位(Map型別) java.lang.Map<java.lang.String, java.lang.Object>
$tableInfoList java.util.List<TableInfo>所有選中的表
$importList 所有需要匯入的包集合 java.util.Set<java.lang.String>
回撥
&callback setFileName(String) 設定檔案儲存名字
setSavePath(String) 設定檔案儲存路徑,預設使用選中路徑
工具
$tool
firstUpperCase(String name) 首字母大寫方法
firstLowerCase(String name) 首字母小寫方法
getClsNameByFullName(String fullName) 通過包全名獲取類名
getJavaName(String name) 將下劃線分割字串轉駝峰命名(屬性名)
getClassName(String name) 將下劃線分割字串轉駝峰命名(類名)
append(Object... objs) 多個數據進行拼接
newHashSet(Object... objs) 建立一個HashSet物件
newArrayList(Object... objs) 建立一個ArrayList物件
newLinkedHashMap() 建立一個LinkedHashMap()物件
newHashMap() 建立一個HashMap()物件
getField(Object obj, String fieldName) 獲取物件的屬性值,可以訪問任意修飾符修飾的屬性.配合debug方法使用.
call(Object... objs) 空白執行方法,用於呼叫某些方法時消除返回值
debug(Object obj) 調式方法,用於查詢物件結構.可檢視物件所有屬性與public方法
serial() 隨機獲取序列化的UID
service(String serviceName, Object... param)遠端服務呼叫
parseJson(String) 將字串轉Map物件
toJson(Object, Boolean) 將物件轉json物件,Boolean:是否格式化json,不填時為不格式化。
$time
currTime(String format) 獲取當前時間,指定時間格式(預設:yyyy-MM-dd HH:mm:ss)
$generateService
run(String, Map<String,Object>) 程式碼生成服務,引數1:模板名稱,引數2:附加引數。
4. 一鍵生成
點選Idea右邊的DataBase選項卡,選擇剛剛連線的資料庫,選好對應的表格,點選右鍵選擇 EasyCode -> Generate Code, 如果出現下面的提示,就複製型別後面的欄位,到第2步進行配置
配置完成後重新點選 Generate Code 會出現如下的配置框,選好路徑後點擊OK,就會生成對應的程式碼。
之後啟動專案,訪問Swagger路徑就可以看到對應的配置已經完全自動化生成。這樣我們只需要在建立表的時候對欄位進行註釋,就可以實現 Entity中和前後端互動時的自動化註釋。非常方便
我是 Keats @後青春期的Keats ,一個熱愛技術的程式設計師,鑑於技術有限,如果本文有什麼紕漏或者兄臺還有其他更好的建議/實現方式,歡迎留言評論,謝謝您