407 lines
14 KiB
Java

package com.github.yulichang.metadata;
import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.sql.SqlScriptUtils;
import lombok.*;
import org.apache.ibatis.mapping.ResultMapping;
import org.apache.ibatis.reflection.Reflector;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.type.*;
import java.lang.reflect.Field;
import java.util.Map;
/**
* 为自定义resultType提供resultMap
* <p>
* copy {@link com.baomidou.mybatisplus.core.metadata.TableFieldInfo}
*/
@Getter
@ToString
@EqualsAndHashCode
@SuppressWarnings("serial")
public class TableFieldInfo implements Constants {
/**
* 属性
*
* @since 3.3.1
*/
private final Field field;
/**
* 字段名
*/
private final String column;
/**
* 属性名
*/
private final String property;
/**
* 属性表达式#{property}, 可以指定jdbcType, typeHandler等
*/
private final String el;
/**
* jdbcType, typeHandler等部分
*/
private final String mapping;
/**
* 属性类型
*/
private final Class<?> propertyType;
/**
* 是否是基本数据类型
*
* @since 3.4.0 @2020-6-19
*/
private final boolean isPrimitive;
/**
* 属性是否是 CharSequence 类型
*/
private final boolean isCharSequence;
/**
* 字段验证策略之 insert
* Refer to {@link TableField#insertStrategy()}
*
* @since added v_3.1.2 @2019-5-7
*/
private final FieldStrategy insertStrategy;
/**
* 字段验证策略之 update
* Refer to {@link TableField#updateStrategy()}
*
* @since added v_3.1.2 @2019-5-7
*/
private final FieldStrategy updateStrategy;
/**
* 字段验证策略之 where
* Refer to {@link TableField#whereStrategy()}
*
* @since added v_3.1.2 @2019-5-7
*/
private final FieldStrategy whereStrategy;
/**
* 是否是乐观锁字段
*/
private final boolean version;
/**
* 是否进行 select 查询
* <p>大字段可设置为 false 不加入 select 查询范围</p>
*/
private boolean select = true;
/**
* 是否是逻辑删除字段
*/
private boolean logicDelete = false;
/**
* 逻辑删除值
*/
private String logicDeleteValue;
/**
* 逻辑未删除值
*/
private String logicNotDeleteValue;
/**
* 字段 update set 部分注入
*/
private String update;
/**
* where 字段比较条件
*/
private String condition = SqlCondition.EQUAL;
/**
* 字段填充策略
*/
private FieldFill fieldFill = FieldFill.DEFAULT;
/**
* 表字段是否启用了插入填充
*
* @since 3.3.0
*/
private boolean withInsertFill;
/**
* 表字段是否启用了更新填充
*
* @since 3.3.0
*/
private boolean withUpdateFill;
/**
* 缓存 sql select
*/
@Setter(AccessLevel.NONE)
private String sqlSelect;
/**
* JDBC类型
*
* @since 3.1.2
*/
private JdbcType jdbcType;
/**
* 类型处理器
*
* @since 3.1.2
*/
private Class<? extends TypeHandler<?>> typeHandler;
/**
* 是否存在OrderBy注解
*/
private boolean isOrderBy;
/**
* 排序类型
*/
private String orderByType;
/**
* 排序顺序
*/
private short orderBySort;
/**
* 全新的 存在 TableField 注解时使用的构造函数
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public TableFieldInfo(GlobalConfig.DbConfig dbConfig, TableInfo tableInfo, Field field, TableField tableField,
Reflector reflector, boolean existTableLogic,boolean isOrderBy) {
this(dbConfig,tableInfo,field,tableField,reflector,existTableLogic);
this.isOrderBy = isOrderBy;
if(isOrderBy){
initOrderBy(field);
}
}
/**
* 全新的 存在 TableField 注解时使用的构造函数
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public TableFieldInfo(GlobalConfig.DbConfig dbConfig, TableInfo tableInfo, Field field, TableField tableField,
Reflector reflector, boolean existTableLogic) {
field.setAccessible(true);
this.field = field;
this.version = field.getAnnotation(Version.class) != null;
this.property = field.getName();
this.propertyType = reflector.getGetterType(this.property);
this.isPrimitive = this.propertyType.isPrimitive();
this.isCharSequence = StringUtils.isCharSequence(this.propertyType);
this.fieldFill = tableField.fill();
this.withInsertFill = this.fieldFill == FieldFill.INSERT || this.fieldFill == FieldFill.INSERT_UPDATE;
this.withUpdateFill = this.fieldFill == FieldFill.UPDATE || this.fieldFill == FieldFill.INSERT_UPDATE;
this.update = tableField.update();
JdbcType jdbcType = tableField.jdbcType();
final Class<? extends TypeHandler> typeHandler = tableField.typeHandler();
final String numericScale = tableField.numericScale();
String el = this.property;
if (JdbcType.UNDEFINED != jdbcType) {
this.jdbcType = jdbcType;
el += (COMMA + SqlScriptUtils.mappingJdbcType(jdbcType));
}
if (UnknownTypeHandler.class != typeHandler) {
this.typeHandler = (Class<? extends TypeHandler<?>>) typeHandler;
if (tableField.javaType()) {
String javaType = null;
TypeAliasRegistry registry = tableInfo.getConfiguration().getTypeAliasRegistry();
Map<String, Class<?>> typeAliases = registry.getTypeAliases();
for (Map.Entry<String, Class<?>> entry : typeAliases.entrySet()) {
if (entry.getValue().equals(propertyType)) {
javaType = entry.getKey();
break;
}
}
if (javaType == null) {
javaType = propertyType.getName();
registry.registerAlias(javaType, propertyType);
}
el += (COMMA + "javaType=" + javaType);
}
el += (COMMA + SqlScriptUtils.mappingTypeHandler(this.typeHandler));
}
if (StringUtils.isNotBlank(numericScale)) {
el += (COMMA + SqlScriptUtils.mappingNumericScale(Integer.valueOf(numericScale)));
}
this.el = el;
int index = el.indexOf(COMMA);
this.mapping = index > 0 ? el.substring(++index) : null;
this.initLogicDelete(dbConfig, field, existTableLogic);
String column = tableField.value();
if (StringUtils.isBlank(column)) {
column = this.property;
if (tableInfo.isUnderCamel()) {
/* 开启字段下划线申明 */
column = StringUtils.camelToUnderline(column);
}
if (dbConfig.isCapitalMode()) {
/* 开启字段全大写申明 */
column = column.toUpperCase();
}
}
String columnFormat = dbConfig.getColumnFormat();
if (StringUtils.isNotBlank(columnFormat) && tableField.keepGlobalFormat()) {
column = String.format(columnFormat, column);
}
this.column = column;
this.sqlSelect = column;
if (tableInfo.getResultMap() == null && !tableInfo.isAutoInitResultMap() &&
TableInfoHelper.checkRelated(tableInfo.isUnderCamel(), this.property, this.column)) {
/* 未设置 resultMap 也未开启自动构建 resultMap, 字段规则又不符合 mybatis 的自动封装规则 */
String propertyFormat = dbConfig.getPropertyFormat();
String asProperty = this.property;
if (StringUtils.isNotBlank(propertyFormat)) {
asProperty = String.format(propertyFormat, this.property);
}
this.sqlSelect += (AS + asProperty);
}
this.insertStrategy = this.chooseFieldStrategy(tableField.insertStrategy(), dbConfig.getInsertStrategy());
this.updateStrategy = this.chooseFieldStrategy(tableField.updateStrategy(), dbConfig.getUpdateStrategy());
this.whereStrategy = this.chooseFieldStrategy(tableField.whereStrategy(), dbConfig.getSelectStrategy());
if (StringUtils.isNotBlank(tableField.condition())) {
// 细粒度条件控制
this.condition = tableField.condition();
}
// 字段是否注入查询
this.select = tableField.select();
}
/**
* 优先使用单个字段注解,否则使用全局配置
*/
private FieldStrategy chooseFieldStrategy(FieldStrategy fromAnnotation, FieldStrategy fromDbConfig) {
return fromAnnotation == FieldStrategy.DEFAULT ? fromDbConfig : fromAnnotation;
}
/**
* 不存在 TableField 注解时, 使用的构造函数
*/
public TableFieldInfo(GlobalConfig.DbConfig dbConfig, TableInfo tableInfo, Field field, Reflector reflector,
boolean existTableLogic,boolean isOrderBy) {
this(dbConfig,tableInfo,field,reflector,existTableLogic);
this.isOrderBy = isOrderBy;
if(isOrderBy){
initOrderBy(field);
}
}
/**
* 不存在 TableField 注解时, 使用的构造函数
*/
public TableFieldInfo(GlobalConfig.DbConfig dbConfig, TableInfo tableInfo, Field field, Reflector reflector,
boolean existTableLogic) {
field.setAccessible(true);
this.field = field;
this.version = field.getAnnotation(Version.class) != null;
this.property = field.getName();
this.propertyType = reflector.getGetterType(this.property);
this.isPrimitive = this.propertyType.isPrimitive();
this.isCharSequence = StringUtils.isCharSequence(this.propertyType);
this.el = this.property;
this.mapping = null;
this.insertStrategy = dbConfig.getInsertStrategy();
this.updateStrategy = dbConfig.getUpdateStrategy();
this.whereStrategy = dbConfig.getSelectStrategy();
this.initLogicDelete(dbConfig, field, existTableLogic);
String column = this.property;
if (tableInfo.isUnderCamel()) {
/* 开启字段下划线申明 */
column = StringUtils.camelToUnderline(column);
}
if (dbConfig.isCapitalMode()) {
/* 开启字段全大写申明 */
column = column.toUpperCase();
}
String columnFormat = dbConfig.getColumnFormat();
if (StringUtils.isNotBlank(columnFormat)) {
column = String.format(columnFormat, column);
}
this.column = column;
this.sqlSelect = column;
if (tableInfo.getResultMap() == null && !tableInfo.isAutoInitResultMap() &&
TableInfoHelper.checkRelated(tableInfo.isUnderCamel(), this.property, this.column)) {
/* 未设置 resultMap 也未开启自动构建 resultMap, 字段规则又不符合 mybatis 的自动封装规则 */
String propertyFormat = dbConfig.getPropertyFormat();
String asProperty = this.property;
if (StringUtils.isNotBlank(propertyFormat)) {
asProperty = String.format(propertyFormat, this.property);
}
this.sqlSelect += (AS + asProperty);
}
}
/**
* 排序初始化
* @param field 字段
*/
private void initOrderBy(Field field){
OrderBy orderBy = field.getAnnotation(OrderBy.class);
if (null != orderBy) {
this.isOrderBy = true;
this.orderBySort = orderBy.sort();
this.orderByType = orderBy.isDesc()?"desc":"asc";
}else{
this.isOrderBy = false;
}
}
/**
* 逻辑删除初始化
*
* @param dbConfig 数据库全局配置
* @param field 字段属性对象
*/
private void initLogicDelete(GlobalConfig.DbConfig dbConfig, Field field, boolean existTableLogic) {
/* 获取注解属性,逻辑处理字段 */
TableLogic tableLogic = field.getAnnotation(TableLogic.class);
if (null != tableLogic) {
if (StringUtils.isNotBlank(tableLogic.value())) {
this.logicNotDeleteValue = tableLogic.value();
} else {
this.logicNotDeleteValue = dbConfig.getLogicNotDeleteValue();
}
if (StringUtils.isNotBlank(tableLogic.delval())) {
this.logicDeleteValue = tableLogic.delval();
} else {
this.logicDeleteValue = dbConfig.getLogicDeleteValue();
}
this.logicDelete = true;
} else if (!existTableLogic) {
String deleteField = dbConfig.getLogicDeleteField();
if (StringUtils.isNotBlank(deleteField) && this.property.equals(deleteField)) {
this.logicNotDeleteValue = dbConfig.getLogicNotDeleteValue();
this.logicDeleteValue = dbConfig.getLogicDeleteValue();
this.logicDelete = true;
}
}
}
/**
* 获取 ResultMapping
*
* @param configuration MybatisConfiguration
* @return ResultMapping
*/
public ResultMapping getResultMapping(final Configuration configuration) {
ResultMapping.Builder builder = new ResultMapping.Builder(configuration, property,
StringUtils.getTargetColumn(column), propertyType);
TypeHandlerRegistry registry = configuration.getTypeHandlerRegistry();
if (jdbcType != null && jdbcType != JdbcType.UNDEFINED) {
builder.jdbcType(jdbcType);
}
if (typeHandler != null && typeHandler != UnknownTypeHandler.class) {
TypeHandler<?> typeHandler = registry.getMappingTypeHandler(this.typeHandler);
if (typeHandler == null) {
typeHandler = registry.getInstance(propertyType, this.typeHandler);
// todo 这会有影响 registry.register(typeHandler);
}
builder.typeHandler(typeHandler);
}
return builder.build();
}
}