UpdateWrapper<CetdSystemParam> update=new UpdateWrapper<>();
update.eq("Param_Type", 0);
update.set("Param_Value", millSecond);
try {
cetdSystemParamMapper.update(null, update);
} catch (Exception e) {
log.error(ServerConstants.LOGGER_PREFIX + "[设置banner图片切换的时间,单位:毫秒异常!millSecond:" + millSecond);
}
update.eq("Param_Type", 0); update.set("Param_Value", millSecond);这两行代码,硬编码简直让人难受!一旦数据库改了字段,必须把逻辑层全部肉眼检查一遍,简直是灾难!
为了解决这个,我第一个想到的是:手动写常量,给每一个实体类加上全部的数据库字段名常量,例如:
public static final String PARAM_ID="Param_ID";
public static final String PARAM_NAME="Param_Name";
但是,仍然要手改。于是,我选择从模板入手:既然那些java实体类都是按模板来的,我应该可以通过修改模板来实现我想要的效果----给每个实体类添加对应表的全部原始字段名,作为该类的公开静态常量。
核心解决方案,改了模板,加入了这几段代码(beetl语言),使实体类里加入数据库字段常量:
<% /** -----------BEGIN 字段循环遍历,写入数据库原始字段作为常量 by:Chuck----------- **/ %>
/***** * 数据库原始字段 *******/
<% for(field in table.fields){ %>
<%
var a = field.name;
var result = strutil.toUpperCase (a);
%>
public static final String ${result}="${field.name}";
<% }
%>
<% /** -----------END 字段循环遍历,写入数据库原始字段作为常量 by:Chuck----------- **/ %>
==================================================================================================
pom.xml:
<!-- 代码生成器依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
</dependency>
<dependency>
<groupId>com.ibeetl</groupId>
<artifactId>beetl</artifactId>
</dependency>
EntityGenerator.java
核心代码:
// 配置模板
TemplateConfig templateConfig = new TemplateConfig();
// 使用自定义模板,不想要生成就设置为null,如果不设置null会使用默认模板
templateConfig.setEntity("templates/lombok_swagger2_entity.java");
templateConfig.setService(null);
templateConfig.setServiceImpl(null);
templateConfig.setController(null);
templateConfig.setMapper(null);
templateConfig.setXml(null);
mpg.setTemplate(templateConfig);
=============================================================
package com.linklink.cetd.admin;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.ITypeConvert;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.TemplateConfig;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.config.rules.IColumnType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.BeetlTemplateEngine;
import org.junit.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.HashMap;
import java.util.Map;
/*
数据层内容生成
*/
@SpringBootTest
public class EntityGenerator {
// 生成输出目录,定位到工程的java目录下
//D:\chuck\ideaProjects\cetd\cetd_applications\AdminApplication\AdminMain\src\main\java
private static String outputDir = "D:\\chuck\\ideaProjects\\cetd\\cetd_applications\\AdminApplication\\AdminMain\\src\\main\\java";
// 生成类的作者
private static String author = "chuck";
// 数据源相关配置
private static String url = "jdbc:mysql://xxxx:20000/yanguan_cetd?autoReconnect=true&characterEncoding=UTF-8&serverTimezone=UTC";
private static String driverName = "com.mysql.cj.jdbc.Driver";
private static String userName = "xxxx";
private static String userPwd = "xxxx";
// DAO的包路径
private static String daoPackage = "com.linklink.cetd.admin.dao";
// 待生成的表名,注意是覆盖更新
private static String[] tableNames;
static {
tableNames = new String[]{
"cetd_banner",
"cetd_account",
"cetd_system_param",
"cetd_item",
"cetd_item_model",
"cetd_item_category",
"cetd_hot_item",
"cetd_message",
"cetd_usr_msg"
};
}
@Test
public void entityGenerator() {
AutoGenerator mpg = new AutoGenerator();
mpg.setTemplateEngine(new BeetlTemplateEngine());
// 配置模板
TemplateConfig templateConfig = new TemplateConfig();
// 使用自定义模板,不想要生成就设置为null,如果不设置null会使用默认模板
templateConfig.setEntity("templates/lombok_swagger2_entity.java");
templateConfig.setService(null);
templateConfig.setServiceImpl(null);
templateConfig.setController(null);
templateConfig.setMapper(null);
templateConfig.setXml(null);
mpg.setTemplate(templateConfig);
// 全局配置
GlobalConfig gc = new GlobalConfig();
gc.setOutputDir(outputDir);
gc.setFileOverride(true);
gc.setSwagger2(true);//注意这里,我用了swagger2
gc.setActiveRecord(true);
gc.setEnableCache(false);
gc.setBaseResultMap(true);
gc.setBaseColumnList(false);
gc.setAuthor(author);
mpg.setGlobalConfig(gc);
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl(url);
// dsc.setSchemaName("public");
dsc.setDriverName(driverName);
dsc.setUsername(userName);
dsc.setPassword(userPwd);
//避免把tinyint变为boolean
dsc.setTypeConvert(new MySqlTypeConvertCustom());
mpg.setDataSource(dsc);
// 策略配置
StrategyConfig strategy = new StrategyConfig();
//strategy.setTablePrefix(new String[]{"_"});// 此处可以修改为您的表前缀
strategy.setNaming(NamingStrategy.underline_to_camel);// 表名生成策略
strategy.setInclude(tableNames);
strategy.setEntityLombokModel(true);//开启了lombok
mpg.setStrategy(strategy);
// 包配置
PackageConfig pc = new PackageConfig();
pc.setParent(null);
pc.setEntity(daoPackage + ".entity");
pc.setMapper(daoPackage + ".mapper");
pc.setXml(daoPackage + ".mapper.xml");
mpg.setPackageInfo(pc);
// 注入自定义配置,可以在 VM 中使用 cfg.abc 设置的值
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
Map<String, Object> map = new HashMap<>();
map.put("abc", this.getConfig().getGlobalConfig().getAuthor() + "-mp");
this.setMap(map);
}
};
mpg.setCfg(cfg);
// 执行生成
mpg.execute();
// 打印注入设置
System.err.println(mpg.getCfg().getMap().get("abc"));
}
/**
* 自定义类型转换
*/
class MySqlTypeConvertCustom extends MySqlTypeConvert implements ITypeConvert {
@Override
public IColumnType processTypeConvert(GlobalConfig globalConfig, String fieldType) {
String t = fieldType.toLowerCase();
if (t.contains("tinyint")) {
return DbColumnType.INTEGER;
}
if (t.contains("int")) {
return DbColumnType.INTEGER;
}
if (t.contains("datetime")) {
return DbColumnType.DATE;
}
if (t.contains("timestamp")) {
return DbColumnType.DATE;
}
return super.processTypeConvert(globalConfig, fieldType);
}
}
}
entity.java.btl(普通模板)
package ${package.Entity};
<% for(pkg in table.importPackages){ %>
import ${pkg};
<% } %>
<% if(swagger2){ %>
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
<% } %>
<% if(entityLombokModel){ %>
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
<% } %>
/**
* <p>
* ${table.comment!}
* </p>
*
* @author ${author}
* @since ${date}
*/
<% if(entityLombokModel){ %>
@Data
<% if(isNotEmpty(superEntityClass)){ %>
@EqualsAndHashCode(callSuper = true)
<% }else{ %>
@EqualsAndHashCode(callSuper = false)
<% } %>
@Accessors(chain = true)
<% } %>
<% if(table.convert){ %>
@TableName("${table.name}")
<% } %>
<% if(swagger2){ %>
@ApiModel(value="${entity}对象", description="${table.comment!''}")
<% } %>
<% if(isNotEmpty(superEntityClass)){ %>
public class ${entity} extends ${superEntityClass}<% if(activeRecord){ %><${entity}><%}%>{
<% }else if(activeRecord){ %>
public class ${entity} extends Model<${entity}> {
<% }else{ %>
public class ${entity} implements Serializable {
<% } %>
<% if(entitySerialVersionUID){ %>
private static final long serialVersionUID = 1L;
<% } %>
<% /** -----------BEGIN 字段循环遍历,写入数据库原始字段作为常量 by:Chuck----------- **/ %>
/*****
* 数据库原始字段
*******/
<% for(field in table.fields){ %>
<%
var a = field.name;
var result = strutil.toUpperCase (a);
%>
public static final String ${result}="${field.name}";
<% } %>
<% /** -----------END 字段循环遍历,写入数据库原始字段作为常量 by:Chuck----------- **/ %>
<% /** -----------BEGIN 字段循环遍历----------- **/ %>
<% for(field in table.fields){ %>
<%
if(field.keyFlag){
var keyPropertyName = field.propertyName;
}
%>
<% if(isNotEmpty(field.comment)){ %>
<% if(swagger2){ %>
@ApiModelProperty( value = "${field.comment}" , required = true)
<% }else{ %>
/**
* ${field.comment}
*/
<% } %>
<% } %>
<% if(field.keyFlag){ %>
<%
/*主键*/
%>
<% if(field.keyIdentityFlag){ %>
@TableId(value = "${field.name}", type = IdType.AUTO)
<% }else if(isNotEmpty(idType)){ %>
@TableId(value = "${field.name}", type = IdType.${idType})
<% }else if(field.convert){ %>
@TableId("${field.name}")
<% } %>
<%
/*普通字段*/
%>
<% }else if(isNotEmpty(field.fill)){ %>
<% if(field.convert){ %>
@TableField(value = "${field.name}", fill = FieldFill.${field.fill})
<% }else{ %>
@TableField(fill = FieldFill.${field.fill})
<% } %>
<% }else if(field.convert){ %>
@TableField("${field.name}")
<% } %>
<%
/*乐观锁注解*/
%>
<% if(versionFieldName!'' == field.name){ %>
@Version
<% } %>
<%
/*逻辑删除注解*/
%>
<% if(logicDeleteFieldName!'' == field.name){ %>
@TableLogic
<% } %>
private ${field.propertyType} ${field.propertyName};
<% } %>
<% /** -----------END 字段循环遍历----------- **/ %>
<% if(!entityLombokModel){ %>
<% for(field in table.fields){ %>
<%
var getprefix ='';
if(field.propertyType=='boolean'){
getprefix='is';
}else{
getprefix='get';
}
%>
public ${field.propertyType} ${getprefix}${field.capitalName}() {
return ${field.propertyName};
}
<% if(entityBuilderModel){ %>
public ${entity} set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
<% }else{ %>
public void set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
<% } %>
this.${field.propertyName} = ${field.propertyName};
<% if(entityBuilderModel){ %>
return this;
<% } %>
}
<% } %>
<% } %>
<% if(entityColumnConstant){ %>
<% for(field in table.fields){ %>
public static final String ${strutil.toUpperCase(field.name)} = "${field.name}";
<% } %>
<% } %>
<% if(activeRecord){ %>
@Override
protected Serializable pkVal() {
<% if(isNotEmpty(keyPropertyName)){ %>
return this.${keyPropertyName};
<% }else{ %>
return null;
<% } %>
}
<% } %>
<% if(!entityLombokModel){ %>
@Override
public String toString() {
return "${entity}{" +
<% for(field in table.fields){ %>
<% if(fieldLP.index==0){ %>
"${field.propertyName}=" + ${field.propertyName} +
<% }else{ %>
", ${field.propertyName}=" + ${field.propertyName} +
<% } %>
<% } %>
"}";
}
<% } %>
}
=====================================================
lombok_swagger2_entity.java.btl(使用了lombok和swagger2的模板)
package ${package.Entity};
<% for(pkg in table.importPackages){ %>
import ${pkg};
<% } %>
<% if(swagger2){ %>
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
<% } %>
<% if(entityLombokModel){ %>
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
<% } %>
/**
* <p>
* ${table.comment!}
* </p>
*
* @author ${author}
* @since ${date}
*/
<% if(entityLombokModel){ %>
@Data
<% } %>
<% if(table.convert){ %>
@TableName("${table.name}")
<% } %>
<% if(swagger2){ %>
@ApiModel(value="${entity}对象", description="${table.comment!''}")
<% } %>
<% if(isNotEmpty(superEntityClass)){ %>
public class ${entity} extends ${superEntityClass}<% if(activeRecord){ %><${entity}><%}%>{
<% }else if(activeRecord){ %>
public class ${entity} extends Model<${entity}> {
<% }else{ %>
public class ${entity} implements Serializable {
<% } %>
<% if(entitySerialVersionUID){ %>
private static final long serialVersionUID = 1L;
<% } %>
<% /** -----------BEGIN 字段循环遍历,写入数据库原始字段作为常量 by:Chuck----------- **/ %>
/*****
* 数据库原始字段
*******/
<% for(field in table.fields){ %>
<%
var a = field.name;
var result = strutil.toUpperCase (a);
%>
public static final String ${result}="${field.name}";
<% } %>
<% /** -----------END 字段循环遍历,写入数据库原始字段作为常量 by:Chuck----------- **/ %>
<% /** -----------BEGIN 字段循环遍历----------- **/ %>
<% for(field in table.fields){ %>
<%
if(field.keyFlag){
var keyPropertyName = field.propertyName;
}
%>
<% if(isNotEmpty(field.comment)){ %>
<% if(swagger2){ %>
@ApiModelProperty( value = "${field.comment}" , required = true)
<% }else{ %>
/**
* ${field.comment}
*/
<% } %>
<% } %>
<% if(field.keyFlag){ %>
<%
/*主键*/
%>
<% if(field.keyIdentityFlag) { %>
@TableId(value = "${field.name}", type = IdType.AUTO)
<% }else if(isNotEmpty(idType)){ %>
@TableId(value = "${field.name}", type = IdType.${idType})
<% }else if(field.convert){ %>
@TableId("${field.name}")
<% } %>
<%
/*普通字段*/
%>
<% } %>
<%
/*乐观锁注解*/
%>
<% if(versionFieldName!'' == field.name){ %>
@Version
<% } %>
<%
/*逻辑删除注解*/
%>
<% if(logicDeleteFieldName!'' == field.name){ %>
@TableLogic
<% } %>
private ${field.propertyType} ${field.propertyName};
<% } %>
<% /** -----------END 字段循环遍历----------- **/ %>
<% if(!entityLombokModel){ %>
<% for(field in table.fields){ %>
<%
var getprefix ='';
if(field.propertyType=='boolean'){
getprefix='is';
}else{
getprefix='get';
}
%>
public ${field.propertyType} ${getprefix}${field.capitalName}() {
return ${field.propertyName};
}
<% if(entityBuilderModel){ %>
public ${entity} set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
<% }else{ %>
public void set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
<% } %>
this.${field.propertyName} = ${field.propertyName};
<% if(entityBuilderModel){ %>
return this;
<% } %>
}
<% } %>
<% } %>
<% if(entityColumnConstant){ %>
<% for(field in table.fields){ %>
public static final String ${strutil.toUpperCase(field.name)} = "${field.name}";
<% } %>
<% } %>
<% if(activeRecord){ %>
@Override
protected Serializable pkVal() {
<% if(isNotEmpty(keyPropertyName)){ %>
return this.${keyPropertyName};
<% }else{ %>
return null;
<% } %>
}
<% } %>
<% if(!entityLombokModel){ %>
@Override
public String toString() {
return "${entity}{" +
<% for(field in table.fields){ %>
<% if(fieldLP.index==0){ %>
"${field.propertyName}=" + ${field.propertyName} +
<% }else{ %>
", ${field.propertyName}=" + ${field.propertyName} +
<% } %>
<% } %>
"}";
}
<% } %>
}
生成的实体类(我用的是带lombok和swagger的模板,不需要则用另外一套模板):
package com.linklink.cetd.admin.dao.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableField;
import java.io.Serializable;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* <p>
* 系统参数
* </p>
*
* @author chuck
* @since 2020-04-04
*/
@Data
@ApiModel(value="CetdSystemParam对象", description="系统参数")
public class CetdSystemParam extends Model<CetdSystemParam> {
private static final long serialVersionUID = 1L;
/*****
* 数据库原始字段
*******/
public static final String PARAM_ID="Param_ID";
public static final String PARAM_NAME="Param_Name";
public static final String PARAM_VALUE="Param_Value";
public static final String PARAM_TYPE="Param_Type";
public static final String PARAM_DESC="Param_Desc";
public static final String CTIME="CTime";
@ApiModelProperty( value = "参数ID" , required = true)
@TableId(value = "Param_ID", type = IdType.AUTO)
private Integer paramId;
@ApiModelProperty( value = "参数名" , required = true)
private String paramName;
@ApiModelProperty( value = "参数值" , required = true)
private String paramValue;
@ApiModelProperty( value = "参数类型 0-banenr切换时间(毫秒) " , required = true)
private Integer paramType;
private String paramDesc;
@ApiModelProperty( value = "创建时间" , required = true)
private Date CTime;
@Override
protected Serializable pkVal() {
return null;
}
}
告别字段硬编码。因为每个实体类对应数据库的字段名都是常量了,自动生成的:
UpdateWrapper<CetdSystemParam> update=new UpdateWrapper<>();
update.eq(CetdSystemParam.PARAM_TYPE, 0);
update.set(CetdSystemParam.PARAM_VALUE , millSecond);
try {
cetdSystemParamMapper.update(null, update);
} catch (Exception e) {
log.error(ServerConstants.LOGGER_PREFIX + "[设置banner图片切换的时间,单位:毫秒异常!millSecond:" + millSecond);
}