freemarker依賴:
<!-- https://mvnrepository.com/artifact/org.freemarker/freemarker -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>
實體類Table.java:
package per.san.generate.domain;
import per.san.common.CommonConstant;
import per.san.common.utils.StringUtils;
import java.util.Date;
import java.util.List;
/**
* description: 表數據
*
* @author sanchar
* @date 12/12/2018 13:26
* lastUpdateBy: sanchar
* lastUpdateDate: 12/12/2018
*/
public class Table {
/**
* 表的名稱
*/
private String tableName;
/**
* 數據庫引擎
*/
private String engine;
/**
* 表的備註
*/
private String comments;
/**
* 創建時間
*/
private Date createTime;
/**
* 類名(第一個字母大寫),如:sys_user => SysUser
*/
private String className;
/**
* 是否存在日期類型列
* 0:不存在 1:存在
*/
private Integer existDate;
/**
* 表的主鍵
*/
private Column pk;
/**
* 表的列名
*/
private List<Column> columns;
public String getTableName() {
return tableName;
}
public void setTableName(String tableName) {
this.tableName = tableName;
}
public String getEngine() {
return engine;
}
public void setEngine(String engine) {
this.engine = engine;
}
public String getComments() {
return comments;
}
public void setComments(String comments) {
this.comments = comments;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public String getClassName() {
return StringUtils.replaceUnderLineAndUpperCase(this.tableName);
}
public Integer getExistDate() {
if(this.columns != null){
for (Column column : this.columns) {
if(CommonConstant.DATE.equalsIgnoreCase(column.getAttrType())) {
return 1;
}
}
}
return 0;
}
public Column getPk() {
return pk;
}
public void setPk(Column pk) {
this.pk = pk;
}
public List<Column> getColumns() {
return columns;
}
public void setColumns(List<Column> columns) {
this.columns = columns;
}
}
實體類Column.java:
package per.san.generate.domain;
import per.san.common.SqlToJavaTypeEnum;
import per.san.common.utils.StringUtils;
/**
* description: 列的屬性
*
* @author sanchar
* @date 12/12/2018 13:24
* lastUpdateBy: sanchar
* lastUpdateDate: 12/12/2018
*/
public class Column {
/**
* 列名
*/
private String columnName;
/**
* 列名類型
*/
private String dataType;
/**
* 列名備註
*/
private String comments;
/**
* 主鍵
*/
private String columnKey;
/**
* 屬性名稱(第一個字母小寫),如:user_name => userName
*/
private String attrName;
/**
* 屬性類型
*/
private String attrType;
/**
* auto_increment
*/
private String extra;
public String getColumnName() {
return columnName;
}
public void setColumnName(String columnName) {
this.columnName = columnName;
}
public String getDataType() {
return dataType;
}
public void setDataType(String dataType) {
this.dataType = dataType;
}
public String getComments() {
return comments;
}
public void setComments(String comments) {
this.comments = comments;
}
public String getColumnKey() {
return columnKey;
}
public void setColumnKey(String columnKey) {
this.columnKey = columnKey;
}
public String getAttrName() {
return StringUtils.replaceUnderLineAndUpperCase(this.columnName);
}
public String getAttrType() {
if(this.dataType != null)
return SqlToJavaTypeEnum.valueOf(this.dataType.toUpperCase()).getJavaType();
return null;
}
public void setAttrType(String attrType) {
this.attrType = attrType;
}
public String getExtra() {
return extra;
}
public void setExtra(String extra) {
this.extra = extra;
}
}
查詢數據表相關數據屬性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="per.san.generate.mapper.MySQLGenerateMapper">
<resultMap id="tableResultMap" type="per.san.generate.domain.Table">
<result property="tableName" column="table_name"/>
<result property="engine" column="engine"/>
<result property="comments" column="table_comment"/>
<result property="createTime" column="create_time"/>
<association property="pk" javaType="per.san.generate.domain.Column">
<result property="columnName" column="pk_column_name"/>
<result property="dataType" column="pk_data_type"/>
<result property="comments" column="pk_column_comment"/>
<result property="columnKey" column="pk_column_key"/>
<result property="extra" column="pk_extra"/>
</association>
<collection property="columns" ofType="per.san.generate.domain.Column">
<result property="columnName" column="column_name"/>
<result property="dataType" column="data_type"/>
<result property="comments" column="column_comment"/>
<result property="columnKey" column="column_key"/>
<result property="extra" column="extra"/>
</collection>
</resultMap>
<sql id="tableBaseSql">
ts.table_name, ts.engine, ts.table_comment, ts.create_time
</sql>
<sql id="columnBaseSql">
pk.column_name as pk_column_name, pk.data_type as pk_data_type,
pk.column_comment as pk_column_comment, pk.column_key as pk_column_key, pk.extra as pk_extra,
cs.column_name, cs.data_type, cs.column_comment, cs.column_key, cs.extra
</sql>
<select id="queryList" resultMap="tableResultMap">
select
<include refid="tableBaseSql"/>,
<include refid="columnBaseSql"/>
from (select ist.* from information_schema.tables ist
<where>
<if test="tableName != null and tableName.trim() != ''">
and ist.table_name like concat('%', #{tableName}, '%')
</if>
<if test="engine != null and engine.trim() != ''">
and ist.engine = #{engine}
</if>
<if test="comments != null and comments.trim() != ''">
and ist.table_comment like concat('%', #{comments}, '%')
</if>
ist.table_schema = (select database())
</where>
) as ts left join information_schema.columns cs on cs.table_name = ts.table_name
<where>
cs.table_schema = (select database())
</where>
order by ts.create_time desc
</select>
<select id="queryTable" resultMap="tableResultMap">
select
<include refid="tableBaseSql"/>,
<include refid="columnBaseSql"/>
from (select ist.* from information_schema.tables ist
where ist.table_name = #{tableName}
and ist.table_schema = (select database()) limit 1
) as ts, information_schema.columns pk
left join information_schema.columns cs on cs.table_name = #{tableName}
<where>
and cs.table_schema = (select database())
and pk.table_schema = (select database())
and pk.table_name = #{tableName}
and pk.column_key = 'PRI'
and cs.column_key <> 'PRI'
</where>
</select>
<select id="queryColumns" resultType="java.util.Map">
select column_name, data_type, column_comment,
column_key, extra
from information_schema.columns
where table_name = #{tableName}
and table_schema = (select database())
order by ordinal_position
</select>
</mapper>
service實現層查詢數據調工具類生成代碼:
@Override
public Table queryTable(String tableName) {
Table table = mySQLGenerateMapper.queryTable(tableName);
try {
CodeGenerateUtils.generate(table);
} catch (Exception e) {
e.printStackTrace();
}
return table;
}
FreeMarkerTemplateUtils工具類:
package per.san.common.utils;
import freemarker.cache.ClassTemplateLoader;
import freemarker.cache.NullCacheStorage;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;
import java.io.IOException;
/**
* description: 模板加載
*
* @author sanchar
* @date 12/10/2018 17:10
* lastUpdateBy: sanchar
* lastUpdateDate: 12/10/2018
*/
public class FreeMarkerTemplateUtils {
private FreeMarkerTemplateUtils(){}
private static final Configuration CONFIGURATION = new Configuration(Configuration.VERSION_2_3_22);
static{
//這裏比較重要,用來指定加載模板所在的路徑
CONFIGURATION.setTemplateLoader(new ClassTemplateLoader(FreeMarkerTemplateUtils.class, "/generate/templates"));
CONFIGURATION.setDefaultEncoding("UTF-8");
CONFIGURATION.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
CONFIGURATION.setCacheStorage(NullCacheStorage.INSTANCE);
}
public static Template getTemplate(String templateName) throws IOException {
try {
return CONFIGURATION.getTemplate(templateName);
} catch (IOException e) {
throw e;
}
}
public static void clearCache() {
CONFIGURATION.clearTemplateCache();
}
}
CodeGenerateUtils工具類:
package per.san.common.utils;
import freemarker.template.Template;
import per.san.common.CommonConstant;
import per.san.generate.domain.Table;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* description: 代碼生成器
*
* @author sanchar
* @date 12/10/2018 17:10
* lastUpdateBy: sanchar
* lastUpdateDate: 12/10/2018
*/
public class CodeGenerateUtils {
private static final String AUTHOR = "sanchar";
private static Date CURRENT_DATE;
private static String TARGET_PATH;
private static String PACKAGE_PATH;
private static String MAPPER_XML_PATH;
static {
CURRENT_DATE = new Date();
TARGET_PATH = System.getProperty("user.dir") + "\\src\\main\\";
PACKAGE_PATH = "per\\san\\demo\\";
MAPPER_XML_PATH = "mapper\\demo\\";
}
public static void generate(Table table){
generateModelFile(table);
generateMapperXmlFile(table);
generateMapperFile(table);
generateServiceImplFile(table);
generateServiceFile(table);
generateControllerFile(table);
}
private static void generateModelFile(Table table){
String suffix = ".java";
String path = TARGET_PATH + "java\\" + PACKAGE_PATH + "domain\\" + table.getClassName() + suffix;
String templateName = "Model.ftl";
generateFile(table, path, PACKAGE_PATH, templateName);
}
private static void generateMapperXmlFile(Table table){
String suffix = "Mapper.xml";
String path = TARGET_PATH + "resources\\" + MAPPER_XML_PATH + table.getClassName() + suffix;
String templateName = "MapperXml.ftl";
generateFile(table, path, PACKAGE_PATH, templateName);
}
private static void generateMapperFile(Table table){
String suffix = "Mapper.java";
String path = TARGET_PATH + "java\\" + PACKAGE_PATH + "mapper\\" + table.getClassName() + suffix;
String templateName = "Mapper.ftl";
generateFile(table, path, PACKAGE_PATH, templateName);
}
private static void generateServiceImplFile(Table table){
String suffix = "ServiceImpl.java";
String path = TARGET_PATH + "java\\" + PACKAGE_PATH + "service\\impl\\" + table.getClassName() + suffix;
String templateName = "ServiceImpl.ftl";
generateFile(table, path, PACKAGE_PATH, templateName);
}
private static void generateServiceFile(Table table){
String suffix = "Service.java";
String path = TARGET_PATH + "java\\" + PACKAGE_PATH + "service\\I" + table.getClassName() + suffix;
String templateName = "Service.ftl";
generateFile(table, path, PACKAGE_PATH, templateName);
}
private static void generateControllerFile(Table table){
String suffix = "Controller.java";
String path = TARGET_PATH + "java\\" + PACKAGE_PATH + "controller\\" + table.getClassName() + suffix;
String templateName = "Controller.ftl";
generateFile(table, path, PACKAGE_PATH, templateName);
}
private static void generateFile(Table table, String path, String packagePath, String templateName){
File file = new File(path);
Map<String,Object> dataMap = new HashMap<>(2);
dataMap.put("table",table);
String packageName = packagePath.substring(0, packagePath.length()-1);
if(packageName.contains(CommonConstant.SLASH)){
packageName = packageName.replace(CommonConstant.SLASH, ".");
}
if(packageName.contains(CommonConstant.BACK_SLASH)){
packageName = packageName.replace(CommonConstant.BACK_SLASH, ".");
}
dataMap.put("packageName",packageName);
try {
generateFileByTemplate(templateName,file,dataMap);
} catch (Exception e) {
e.printStackTrace();
}
}
private static void generateFileByTemplate(final String templateName, File file, Map<String, Object> dataMap) throws Exception {
Template template = FreeMarkerTemplateUtils.getTemplate(templateName);
FileOutputStream fos = new FileOutputStream(file);
dataMap.put("author", AUTHOR);
dataMap.put("date", CURRENT_DATE);
Writer out = new BufferedWriter(new OutputStreamWriter(fos, "utf-8"), 10240);
template.process(dataMap, out);
}
}
模板文件Model.ftl:
package ${packageName}.domain;
import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;
<#if table.existDate == 1>
import java.util.Date;
</#if>
/**
* description: ${table.comments}
*
* @author ${author}
* @date ${date?string('yyyy-MM-dd hh:mm')}
* lastUpdateBy: ${author}
* lastUpdateDate: ${date?string('yyyy-MM-dd hh:mm')}
*/
@Table(name="${table.tableName}")
public class ${table.className} {
/**
*${table.pk.comments!}
*/
@Id
private ${table.pk.attrType} ${table.pk.attrName?uncap_first};
<#if table.columns?exists>
<#list table.columns as column>
/**
*${column.comments!}
*/
@Column(name = "${column.columnName}",columnDefinition = "${column.dataType?upper_case}")
private ${column.attrType} ${column.attrName?uncap_first};
</#list>
</#if>
public ${table.pk.attrType} get${table.pk.attrName}() {
return this.${table.pk.attrName?uncap_first};
}
public void set${table.pk.attrName}(${table.pk.attrType} ${table.pk.attrName?uncap_first}) {
this.${table.pk.attrName?uncap_first} = ${table.pk.attrName?uncap_first};
}
<#if table.columns?exists>
<#list table.columns as column>
public ${column.attrType} get${column.attrName}() {
return this.${column.attrName?uncap_first};
}
public void set${column.attrName}(${column.attrType} ${column.attrName?uncap_first}) {
this.${column.attrName?uncap_first} = ${column.attrName?uncap_first};
}
</#list>
</#if>
}
MapperXml.ftl:
<?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="${packageName}.mapper.${table.className}Mapper" >
<delete id="deleteBatch">
delete from ${table.tableName}
<where>
${table.pk.columnName} in
<foreach collection="ids" item="id" open="(" close=")" separator=",">
${r'#{id}'}
</foreach>
</where>
</delete>
</mapper>
Mapper.ftl:
package ${packageName}.mapper;
import org.apache.ibatis.annotations.Param;
import ${packageName}.domain.${table.className};
import tk.mybatis.mapper.common.BaseMapper;
import java.util.List;
/**
* description: ${table.comments}
*
* @author ${author}
* @date ${date?string('yyyy-MM-dd hh:mm')}
* lastUpdateBy: ${author}
* lastUpdateDate: ${date?string('yyyy-MM-dd hh:mm')}
*/
public interface ${table.className}Mapper extends BaseMapper<${table.className}> {
/**
* description: 批量刪除
* @param ids 刪除數據的id數組
* @return 刪除成功的條數
*/
Integer deleteBatch(@Param("ids") List<Long> ids);
}
ServiceImpl.ftl:
package ${packageName}.service.impl;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import per.san.common.utils.page.PageHelper;
import per.san.common.utils.page.PageRequest;
import ${packageName}.domain.${table.className};
import ${packageName}.mapper.${table.className}Mapper;
import ${packageName}.service.I${table.className}Service;
import java.util.List;
/**
* description: ${table.comments}
*
* @author ${author}
* @date ${date?string('yyyy-MM-dd hh:mm')}
* lastUpdateBy: ${author}
* lastUpdateDate: ${date?string('yyyy-MM-dd hh:mm')}
*/
@Service
public class ${table.className}ServiceImpl implements I${table.className}Service {
@Autowired
${table.className}Mapper ${table.className?uncap_first}Mapper;
@Override
public Integer add(${table.className} ${table.className?uncap_first}) {
return ${table.className?uncap_first}Mapper.insertSelective(${table.className?uncap_first});
}
@Override
public Integer deleteByPrimaryKey(Long id) {
return ${table.className?uncap_first}Mapper.deleteByPrimaryKey(id);
}
@Override
public Integer deleteBatch(List<Long> ids) {
return ${table.className?uncap_first}Mapper.deleteBatch(ids);
}
@Override
public Integer update(${table.className} ${table.className?uncap_first}) {
return ${table.className?uncap_first}Mapper.updateByPrimaryKeySelective(${table.className?uncap_first});
}
@Override
public PageInfo<${table.className}> pageQuery(PageRequest pageRequest, ${table.className} ${table.className?uncap_first}) {
return PageHelper.doPage(pageRequest, () -> ${table.className?uncap_first}Mapper.select(${table.className?uncap_first}));
}
@Override
public List<${table.className}> queryList(${table.className} ${table.className?uncap_first}) {
return ${table.className?uncap_first}Mapper.select(${table.className?uncap_first});
}
}
Service.ftl:
package ${packageName}.service;
import com.github.pagehelper.PageInfo;
import per.san.common.utils.page.PageRequest;
import ${packageName}.domain.${table.className};
import java.util.List;
/**
* description: ${table.comments}
*
* @author ${author}
* @date ${date?string('yyyy-MM-dd hh:mm')}
* lastUpdateBy: ${author}
* lastUpdateDate: ${date?string('yyyy-MM-dd hh:mm')}
*/
public interface I${table.className}Service {
/**
* description: 新增
* @param ${table.className?uncap_first} 新增的信息
* @return 新增成功的條數
*/
Integer add(${table.className} ${table.className?uncap_first});
/**
* description: 根據主鍵id刪除
* @param id 刪除數據的id
* @return 刪除成功的條數
*/
Integer deleteByPrimaryKey(Long id);
/**
* description: 批量刪除
* @param ids 刪除數據的id數組
* @return 刪除成功的條數
*/
Integer deleteBatch(List<Long> ids);
/**
* description: 更新
* @param ${table.className?uncap_first} 更新的信息
* @return 更新成功的條數
*/
Integer update(${table.className} ${table.className?uncap_first});
/**
* description: 分頁查詢
* @param pageRequest 分頁查詢參數
* @param ${table.className?uncap_first} 分頁查詢條件
* @return 分頁數據
*/
PageInfo<${table.className}> pageQuery(PageRequest pageRequest, ${table.className} ${table.className?uncap_first});
/**
* description: 查詢List
* @param ${table.className?uncap_first} 查詢條件
* @return 數據List
*/
List<${table.className}> queryList(${table.className} ${table.className?uncap_first});
}
Controller.ftl:
package ${packageName}.controller;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import per.san.common.utils.page.PageRequest;
import ${packageName}.domain.${table.className};
import ${packageName}.service.I${table.className}Service;
<#if table.existDate == 1>
import java.util.Date;
</#if>
import java.util.List;
/**
* description: ${table.comments}
*
* @author ${author}
* @date ${date?string('yyyy-MM-dd hh:mm')}
* lastUpdateBy: ${author}
* lastUpdateDate: ${date?string('yyyy-MM-dd hh:mm')}
*/
@RestController
@RequestMapping("/v1/${table.tableName?replace("_","/")}")
public class ${table.className}Controller {
@Autowired
I${table.className}Service i${table.className}Service;
@PostMapping
public ResponseEntity<Integer> add(@RequestBody ${table.className} ${table.className?uncap_first}) {
return new ResponseEntity<>(i${table.className}Service.add(${table.className?uncap_first}), HttpStatus.OK);
}
@DeleteMapping("/{id}")
public ResponseEntity<Integer> delete(@PathVariable("id") Long id) {
return new ResponseEntity<>(i${table.className}Service.deleteByPrimaryKey(id), HttpStatus.OK);
}
@DeleteMapping("/batch")
public ResponseEntity<Integer> deleteBatch(@RequestBody List<Long> ids) {
return new ResponseEntity<>(i${table.className}Service.deleteBatch(ids), HttpStatus.OK);
}
@PutMapping
public ResponseEntity<Integer> update(@RequestBody ${table.className} ${table.className?uncap_first}) {
return new ResponseEntity<>(i${table.className}Service.update(${table.className?uncap_first}), HttpStatus.OK);
}
@GetMapping("/page")
public ResponseEntity<PageInfo<${table.className}>> pageQuery(
PageRequest pageRequest,
<#if table.columns?exists>
<#list table.columns as column>
@RequestParam(required = false) ${column.attrType} ${column.attrName?uncap_first}<#if column_has_next>,</#if>
</#list>
</#if>) {
${table.className} ${table.className?uncap_first} = new ${table.className}();
<#if table.columns?exists>
<#list table.columns as column>
${table.className?uncap_first}.set${column.attrName}(${column.attrName?uncap_first});
</#list>
</#if>
return new ResponseEntity<>(i${table.className}Service.pageQuery(pageRequest, ${table.className?uncap_first}), HttpStatus.OK);
}
@GetMapping
public ResponseEntity<List<${table.className}>> queryList(
<#if table.columns?exists>
<#list table.columns as column>
@RequestParam(required = false) ${column.attrType} ${column.attrName?uncap_first}<#if column_has_next>,</#if>
</#list>
</#if>) {
${table.className} ${table.className?uncap_first} = new ${table.className}();
<#if table.columns?exists>
<#list table.columns as column>
${table.className?uncap_first}.set${column.attrName}(${column.attrName?uncap_first});
</#list>
</#if>
return new ResponseEntity<>(i${table.className}Service.queryList(${table.className?uncap_first}), HttpStatus.OK);
}
}