数据绑定注解
在实际开发中会遇到code转name的情况,一般情况下的写法就是先把数据查出来,然后再把数据中code对应的名称查出来,最后组装成需要的数据返回给前端展示,这种情况是没与问题的。但是无形之中增加了一些不必要代码显的有些臃肿,如果是在访问量比较高的接口还会影响一些性能。今天就记录一下利用缓存cache,反射写的一个数据绑定的注解,无需关注code转name的过程,仅需写出主要代码就可以了,剩下的用注解操作。非常方便,快捷。废话不多说,直接上案例:


可以看到,数据绑定相同条件下第二次请求直接走缓存不查库,可以提高效率。
接下来上代码:
注解定义:
package com.example.test1.databind.aspect.annotation;
import com.example.test1.databind.property.BaseFastDataBindProperty;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Author xx
* @Date 2024/6/28 9:11
* @Description: 字段数据快速绑定
* @Version 1.0
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FastDataBindFiled {
/**
* 指定数据绑定配置类
*/
Class<? extends BaseFastDataBindProperty> config();
/**
* 对应数据库表查询字段
*/
String conditionColumn() default "";
/**
* 条件字段例:要查字zt = 3的名称 这里传入zt
*/
String conditionProperty() default "";
/**
* 获取结果值的表字段
*/
String valueColumn() default "";
/**
* sql中拼接 and的语句
*/
String andCondition() default "";
}
package com.example.test1.databind.aspect.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Author xx
* @Date 2024/6/28 9:08
* @Description: 快速数据绑定方法切入
* @Version 1.0
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FastDataBindResult {
/**
* 深度查询次数默认1
*/
int deepQueryTimes() default 1;
}
注解生效的切面类:
package com.example.test1.databind.aspect;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.test1.databind.aspect.annotation.FastDataBindFiled;
import com.example.test1.databind.aspect.annotation.FastDataBindResult;
import com.example.test1.databind.bind.FastDataBind;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
/**
* @Author xx
* @Date 2024/6/28 9:02
* @Description: 快速数据绑定切面类
* @Version 1.0
*/
@Aspect
@Component
public class DataBindAspect {
@Around(value = "@annotation(fastDataBindResult)")
public Object handle(ProceedingJoinPoint joinPoint, FastDataBindResult fastDataBindResult) {
Object result = null;
try {
result = joinPoint.proceed();
//探测次数
for (int i = 0; i < fastDataBindResult.deepQueryTimes(); i++) {
result = handleDataBindResult(result);
}
} catch (Throwable e) {
throw new RuntimeException(e.getMessage(), e);
}
return result;
}
@Around(value = "@annotation(fastDataBindFiled)")
public Object handle(ProceedingJoinPoint joinPoint, FastDataBindFiled fastDataBindFiled) {
return handleDataBindResult(joinPoint);
}
private Object handleDataBindResult(Object data) {
Object dataBindData;
if (data instanceof Page) {
Page<?> page = (Page<?>) data;
dataBindData = page.getRecords();
} else {
dataBindData = data;
}
FastDataBind.dataBind(dataBindData);
return data;
}
}
具体实现逻辑
package com.example.test1.databind.bind;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.TableName;
import com.example.test1.databind.aspect.annotation.FastDataBindFiled;
import com.example.test1.databind.property.BaseFastDataBindProperty;
import com.example.test1.databind.property.FastDataBindProperty;
import com.example.test1.databind.sql.SelectSqlBuilder;
import com.example.test1.util.SpElUtils;
import com.google.common.base.Joiner;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.expression.EvaluationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
import javax.annotation.PostConstruct;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import static cn.hutool.core.text.CharPool.COLON;
import static com.baomidou.mybatisplus.core.enums.SqlKeyword.AND;
import static com.baomidou.mybatisplus.core.toolkit.StringPool.DASH;
import static com.baomidou.mybatisplus.core.toolkit.StringPool.SINGLE_QUOTE;
/**
* @Author xx
* @Date 2024/6/28 10:17
* @Description: 快速数据绑定
* @Version 1.0
*/
@Slf4j
@Component
public class FastDataBind {
/**
* map<类,类中数据绑定的字段>
*/
private static final Map<Class<?>, Field[]> CLASS_DATABIND_FIELD_MAP = new ConcurrentHashMap<>(256);
private static final Joiner COLON_JOINER = Joiner.on(COLON);
public static final String LOGIN_TENANT_SHARED_TYPE = "loginTenantId";
public static final String LOGIN_USER_SHARED_TYPE = "loginUserId";
/**
* 本地缓存,重启服务时会清空
*/
private static final Cache<String, DataBindCollector> CACHE = CacheBuilder.newBuilder()
//过期时间
.expireAfterAccess(10L, TimeUnit.SECONDS)
//缓存容量大小
.initialCapacity(128)
.build();
/**
* 数据绑定
*
* @param data 目标属性带有{@link com.example.test1.databind.aspect.annotation.FastDataBindFiled}注解,将做数据绑定
*/
public static void dataBind(Object data) {
if (data == null) {
return;
}
Map<String, List<DataBindCollector>> collGroup;
StopWatch stopWatch = new StopWatch();
stopWatch.start();
Field[] fields;
if (data instanceof Collection) {
Collection<?> list = (Collection<?>) data;
if (CollUtil.isEmpty(list)) {
return;
}
//查找出带有数据绑定注解的字段
fields = list.stream().findFirst().map(FastDataBind::detectFields).orElse(null);
if(fields == null){
return;
}
//构建并为收集器做分组
collGroup = list.parallelStream()
.flatMap(tmp -> buildCollectors(tmp).stream())
.collect(Collectors.toList())
.stream()
.collect(Collectors.groupingBy(DataBindCollector::groupKey));
} else {
fields = detectFields(data);
collGroup = buildCollectors(data).stream()
.collect(Collectors.groupingBy(DataBindCollector::groupKey));
}
if (CollUtil.isEmpty(collGroup)) {
return;
}
//根据分组数据做查询绑定
dataBindGroup(collGroup);
stopWatch.stop();
log.info("======================数据绑定共耗时:{} ms===========================", stopWatch.getTotalTimeMillis());
}
/**
* 根据数据绑定收集器进行数据绑定
*/
private static void dataBindGroup(Map<String, List<DataBindCollector>> collGroup) {
for (Map.Entry<String, List<DataBindCollector>> entry : collGroup.entrySet()) {
String key = entry.getKey();
List<DataBindCollector> valueList = entry.getValue();
//保存已缓存的数据绑定收集器
Map<String, DataBindCollector> tempCache = new HashMap<>(64);
//记录and拼接条件
String[] andSql = {""};
List<String> inValues = valueList.stream()
.filter(tmp -> {
String unionKey = tmp.unionKey();
//判断是否有缓存,有则从缓存中取
DataBindCollector cache = CACHE.getIfPresent(unionKey);
if (cache != null) {
tempCache.put(unionKey, cache);
return false;
}
boolean result = tmp.getConditionValue() != null;
if (result) {
andSql[0] = tmp.andCondition;
}
return result;
}).map(collector -> parseForString(collector.getConditionValue()))
.distinct()
.collect(Collectors.toList());
//从数据库查询值
Map<String, Map<String, Object>> columnDataMap = queryDataMap(key,inValues,andSql[0]);
if (CollUtil.isEmpty(columnDataMap) && CollUtil.isEmpty(tempCache)) {
continue;
}
for (DataBindCollector collector : valueList) {
// 如果有缓存,优先从缓存获取
String unionKey = collector.unionKey();
String conditionValue = String.valueOf(collector.getConditionValue());
// 从缓存中获取结果值
if (tempCache.containsKey(unionKey)) {
DataBindCollector cache = tempCache.get(unionKey);
// 设置查询出来的结果值到收集器
collector.setValue(cache.getValue());
}
// 从数据库查询获取结果值
else if (columnDataMap.containsKey(conditionValue)) {
Map<String, Object> dataMap = columnDataMap.get(conditionValue);
// 设置查询出来的结果值到收集器
String upperCaseValueColumn = collector.getValueColumn().toUpperCase();
String lowerCaseValueColumn = collector.getValueColumn().toLowerCase();
Object value = Optional.ofNullable(dataMap.get(upperCaseValueColumn))
.orElse(dataMap.get(lowerCaseValueColumn));
collector.setValue(value);
} else {
continue;
}
// 放入到有过期时间的缓存当中去
CACHE.put(unionKey, collector);
// 为对象进行结果值的数据绑定
collector.dataBind();
}
}
}
private static Map<String, Map<String, Object>> queryDataMap(String key, List<String> inValues, String andSql) {
if(CollUtil.isEmpty(inValues)){
return Collections.emptyMap();
}
// 分组的key组成公式:表名 + 查询的数据库表字段。详见内部类DataBindCollector的groupKey方法
String[] tableColumnPair = key.split(String.valueOf(COLON));
// 构建批量查询SQL
SelectSqlBuilder selectSqlBuilder = new SelectSqlBuilder(tableColumnPair[0])
.in(tableColumnPair[1], inValues);
if (StrUtil.isNotBlank(andSql)) {
selectSqlBuilder.lastSql(AND + andSql);
}
String sql = selectSqlBuilder.build();
// 执行之前,进行SQL后置处理:例如数据权限的过滤处理
// sql = SimpleSqlHandlerChain.handle(sql);
log.info("[数据绑定查询sql为:] - {}", sql);
// 表条件字段和行数据的映射
return fastDataBindMapper().queryForList(sql)
.stream()
.collect(Collectors.toMap(map -> {
String upperCaseKey = tableColumnPair[1].toUpperCase();
String lowerCaseKey = tableColumnPair[1].toLowerCase();
return String.valueOf(Optional.ofNullable(map.get(upperCaseKey)).orElse(map.get(lowerCaseKey)));
}, m -> m, (oM, nM) -> oM));
}
/**
* 查找需要数据绑定的字段
* 查找以下三类字段:
* 1:值为空且有数据绑定注解的注解
* 2:值不为空,且为集合类
* 3:值不为空且为bean
*
* @param data 目标对象
* @return 返回需要数据绑定的字段
*/
public static Field[] detectFields(Object data) {
Class<?> objClass = data.getClass();
//先找缓存
if (CLASS_DATABIND_FIELD_MAP.containsKey(objClass)) {
return CLASS_DATABIND_FIELD_MAP.get(objClass);
}
Field[] fields = Arrays.stream(ReflectUtil.getFields(objClass))
.filter(tmp -> {
tmp.setAccessible(true);
try {
Object value = tmp.get(data);
//值为空且有数据绑定的注解
boolean hasAnnotation = (value == null && hasAnnotation(tmp));
//值不为空且为集合类
boolean isColl = value != null && Arrays.asList(tmp.getType().getInterfaces()).contains(Collection.class);
return hasAnnotation || isColl;
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage(), e);
}
}).toArray(Field[]::new);
if (ArrayUtil.isEmpty(fields)) {
return null;
}
//放入集合中
CLASS_DATABIND_FIELD_MAP.put(objClass, fields);
return fields;
}
private static boolean hasAnnotation(Field field) {
return field.isAnnotationPresent(FastDataBindFiled.class);
}
private static List<DataBindCollector> buildCollectors(Object data) {
if (data == null) {
return Collections.emptyList();
}
//获取可能需要数据绑定的字段
Field[] fields = detectFields(data);
if (fields == null) {
return Collections.emptyList();
}
List<DataBindCollector> dataBindCollectors = new ArrayList<>();
for (Field field : fields) {
try {
field.setAccessible(true);
//过滤调没有数据绑定的注解或置为空的过滤掉
Object value = field.get(data);
if (Arrays.asList(field.getType().getInterfaces()).contains(Collection.class)) {
if (value == null) {
continue;
}
Collection<?> dataValueColl = (Collection<?>) value;
if (CollUtil.isEmpty(dataValueColl)) {
continue;
}
Field[] dataValueFields = detectFields(dataValueColl.stream().iterator().hasNext());
if (ArrayUtil.isNotEmpty(dataValueFields)) {
dataBindCollectors.addAll(dataValueColl.stream()
.flatMap(tmp -> buildCollectors(tmp).stream())
.collect(Collectors.toList()));
}
} else if (value == null) {
FastDataBindProperty fastDataBindProperty = getFastDataBindProperty(field);
DataBindCollector bindCollector = new DataBindCollector(fastDataBindProperty, field, data, null, null);
if (bindCollector.conditionValue != null) {
dataBindCollectors.add(bindCollector);
}
} else {
Field[] detectFields = detectFields(data);
if (ArrayUtil.isNotEmpty(detectFields)) {
dataBindCollectors.addAll(buildCollectors(detectFields));
}
}
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
return dataBindCollectors;
}
/**
* 解析字段值为符合mysql的字符串形式
*
* @param val 字段值
* @return 符合mysql的字符串形式
*/
private static String parseForString(Object val) {
if (val == null || val instanceof Number || val instanceof Boolean) {
return String.valueOf(val);
}
if (val instanceof String) {
String varStr = val.toString();
if (varStr.startsWith(SINGLE_QUOTE) && varStr.endsWith(SINGLE_QUOTE)) {
return val.toString();
}
}
return "'" + val + "'";
}
/**
* 获取字段上数据绑定配置数据
*/
private static FastDataBindProperty getFastDataBindProperty(Field field) {
FastDataBindProperty property = null;
if (field.isAnnotationPresent(FastDataBindFiled.class)) {
FastDataBindFiled dataBindFiled = field.getDeclaredAnnotation(FastDataBindFiled.class);
Optional<FastDataBindProperty> fastDataBindPropertyOpt = fastDataBindPropertyFactory(dataBindFiled.config());
if (fastDataBindPropertyOpt.isPresent()) {
property = fastDataBindPropertyOpt.get();
}
String valueColumn = dataBindFiled.valueColumn();
if (StringUtils.isNotBlank(valueColumn)) {
Optional.ofNullable(property).ifPresent(p -> p.setValueColumn(valueColumn));
}
String conditionProperty = dataBindFiled.conditionProperty();
if (StringUtils.isNotBlank(conditionProperty)) {
Optional.ofNullable(property).ifPresent(p -> p.setConditionProperty(conditionProperty));
}
String conditionColumn = dataBindFiled.conditionColumn();
if (StringUtils.isNotBlank(conditionColumn)) {
Optional.ofNullable(property).ifPresent(p -> p.setConditionColumn(conditionColumn));
}
Optional.ofNullable(property)
.ifPresent(p ->
p.setAndCondition(
Optional.ofNullable(dataBindFiled.andCondition())
.orElse(p.getAndCondition())
)
);
}
return property;
}
/**
* 数据绑定配置属性
*/
private static Optional<FastDataBindProperty> fastDataBindPropertyFactory(Class<? extends BaseFastDataBindProperty> config) {
FastDataBindProperty property = ReflectUtil.newInstance(config);
return Optional.ofNullable(property);
}
@Data
@Accessors(chain = true)
public static class DataBindCollector {
/**
* 数据库表名
*/
private String tableName;
/**
* 条件查询表字段
*/
private String conditionColumn;
/**
* 条件查询的值的来源字段
*/
private String conditionProperty;
/**
* 条件查询的值
*/
private Object conditionValue;
/**
* 结果值对应的表字段
*/
private String valueColumn;
/**
* and 语句条件
*/
private String andCondition = "";
/**
* 绑定结果值的字段
*/
private Field field;
/**
* 从数据库中查询出来的结果值
*/
private Object value;
/**
* 来源对象
*/
private volatile Object source;
private boolean isSkip = false;
public DataBindCollector() {
}
private DataBindCollector(DataBindObject source) {
this.source = source;
this.tableName = source.getTableName();
this.field = DataBindObject.CONDITION_FIELD;
this.conditionColumn = source.getConditionColumn();
this.conditionValue = source.getConditionValue();
this.valueColumn = source.getValueColumn();
this.conditionProperty = DataBindObject.CONDITION_PROPERTY;
this.andCondition = source.getAndCondition();
}
public DataBindCollector(FastDataBindProperty baseFastDataBindProperty, Field field, Object source, Long tenantId, Long userId) {
this.source = source;
this.tableName = analysisTableName(baseFastDataBindProperty, source);
this.field = field;
this.andCondition = baseFastDataBindProperty.getAndCondition();
this.conditionColumn = baseFastDataBindProperty.getConditionColumn();
this.valueColumn = baseFastDataBindProperty.getValueColumn();
this.conditionProperty = baseFastDataBindProperty.getConditionProperty();
// 构建SpEL
EvaluationContext context = SpElUtils.getEvaluationContext(source);
// context.setVariable(LOGIN_TENANT_SHARED_TYPE, tenantId);
// context.setVariable(LOGIN_USER_SHARED_TYPE, userId);
try {
this.andCondition = SpElUtils.getValue(andCondition, String.class, context);
} catch (Exception ignored) {
}
try {
this.conditionColumn = SpElUtils.getValue(conditionColumn, String.class, context);
} catch (Exception ignored) {
}
try {
this.valueColumn = SpElUtils.getValue(valueColumn, String.class, context);
} catch (Exception ignored) {
}
try {
this.conditionProperty = SpElUtils.getValue(conditionProperty, String.class, context);
} catch (Exception ignored) {
}
this.conditionValue = com.example.test1.util.ReflectUtil.invokeGetter(source, conditionProperty);
}
/**
* 根据ORM实体类获取表名
*
* @param baseFastDataBindProperty ORM实体类
* @param data 数据源
* @return 数据库表名
*/
private static String analysisTableName(FastDataBindProperty baseFastDataBindProperty, Object data) {
String tableName;
try {
tableName = SpElUtils.getValue(baseFastDataBindProperty.getTableName(), data, String.class);
} catch (Exception e) {
tableName = baseFastDataBindProperty.getTableName();
}
if (StringUtils.isBlank(tableName)) {
tableName = baseFastDataBindProperty.getTableName();
}
if (StrUtil.isBlank(tableName)) {
Class<?> type = baseFastDataBindProperty.getEntityClass();
// Assert.state(type != null && !NullObject.class.equals(type), "无法找到表名相关配置!");
TableName tableNameAnnotation = type.getDeclaredAnnotation(TableName.class);
if (tableNameAnnotation == null) {
tableName = StrUtil.toUnderlineCase(type.getSimpleName());
} else {
tableName = tableNameAnnotation.value();
}
}
return tableName;
}
@Override
public String toString() {
return "DataBindCollector{" +
"tableName='" + tableName + '\'' +
", conditionColumn='" + conditionColumn + '\'' +
", conditionProperty='" + conditionProperty + '\'' +
", conditionValue=" + conditionValue +
", valueColumn='" + valueColumn + '\'' +
", andCondition='" + andCondition + '\'' +
", value=" + value +
", source=" + source +
'}';
}
/**
* 绑定结果值到对应的字段
*/
public void dataBind() {
com.example.test1.util.ReflectUtil.invokeSetter(source, field.getName(), value);
}
/**
* 分组key:便于对收集器做分组,进行批量的查询操作
*
* @return 数据库表名 + 查询的条件表字段
*/
public String groupKey() {
return COLON_JOINER.join(tableName, conditionColumn, andCondition);
}
/**
* 唯一key:每个数据的绑定字段对应的唯一标识,便于做缓存
*
* @return 数据库表名 + 查询的条件表字段 + 查询的条件表字段的值 + 结果值对应的表字段 + and条件语句
*/
public String unionKey() {
return COLON_JOINER.join(tableName, conditionColumn, conditionValue, valueColumn, andCondition);
}
public Object getValue() {
return value;
}
public Object getValue(String valueColumn) {
return com.example.test1.util.ReflectUtil.invokeGetter(source, valueColumn);
}
}
/**
* 用于转载数据绑定条件的类
*/
@Data
public static class DataBindObject {
/**
* 条件值
*/
private Object conditionValue;
/**
* 结果值
*/
private Object resultValue;
private String tableName;
private String conditionColumn;
/**
* 结果值对应的表字段
*/
private String valueColumn;
/**
* and 语句条件
*/
private String andCondition = "";
/**
* 数据来源对象
*/
private Object sourceData;
private static final String CONDITION_PROPERTY = "conditionValue";
private static final String VALUE_PROPERTY = "resultValue";
private static final Field CONDITION_FIELD;
static {
try {
CONDITION_FIELD = DataBindObject.class.getDeclaredField(VALUE_PROPERTY);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
}
public DataBindObject(Object conditionValue, String tableName, String conditionColumn, String valueColumn, String andCondition) {
this.conditionValue = conditionValue;
this.tableName = tableName;
this.conditionColumn = conditionColumn;
this.valueColumn = valueColumn;
this.andCondition = andCondition;
}
public DataBindObject(Object conditionValue, String tableName, String conditionColumn, String valueColumn) {
this.conditionValue = conditionValue;
this.tableName = tableName;
this.conditionColumn = conditionColumn;
this.valueColumn = valueColumn;
}
public DataBindObject(Object sourceData, Object conditionValue, String tableName, String conditionColumn, String valueColumn) {
this.sourceData = sourceData;
this.conditionValue = conditionValue;
this.tableName = tableName;
this.conditionColumn = conditionColumn;
this.valueColumn = valueColumn;
}
public DataBindObject(Object sourceData, Object conditionValue, String tableName, String conditionColumn, String valueColumn, String andCondition) {
this.sourceData = sourceData;
this.conditionValue = conditionValue;
this.tableName = tableName;
this.conditionColumn = conditionColumn;
this.valueColumn = valueColumn;
this.andCondition = andCondition;
}
public <T> T getSourceData() {
return (T) sourceData;
}
public void setSourceData(Object sourceData) {
this.sourceData = sourceData;
}
}
private static FastDataBind fastDataBind;
private final JdbcTemplate jdbcTemplate;
public static JdbcTemplate fastDataBindMapper() {
return fastDataBind.jdbcTemplate;
}
@PostConstruct
public void init() {
fastDataBind = this;
}
public FastDataBind(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
}
sql处理类:
package com.example.test1.databind.sql;
/**
* @description: sql常量
* @author: Xiao
* @date: 2024/7/8 13:36
* @Version: 1.0
*/
public class SqlConstants {
public static final String SELECT = "select ";
public static final String WILDCARD_CHARACTER = "*";
public static final String WHERE = " where ";
public static final String LEFT_JOIN = " left join ";
public static final String ON = " on ";
public static final String IN = " in ";
public static final String FROM = " from ";
public static final String LIKE = " like ";
public static final String AND = " and ";
public static final String OR = " or ";
public static final String PERCENT = "%";
public static final String BLANK = " ";
public static final String AS = " AS ";
public static final String SPACE = "";
public static final String POINT = ".";
public static final String COMMA = ",";
public static final String EQ = "=";
public static final String NE = "!=";
public static final String GT = ">";
public static final String GE = ">=";
public static final String LT = "<";
public static final String LE = "<=";
public static final String LEFT_BRACKET = "(";
public static final String RIGHT_BRACKET = ")";
public static final String SINGLE_QUOTES = "'";
public static final String GROUP_BY = " group by ";
public static final String ORDER_BY_DESC = "order by desc ";
public static final String ORDER_BY_ASC = "order by asc";
public static final String DESC = "desc";
public static final String ASC = "asc";
public static final String NOT_IN = " not in ";
public static final String BETWEEN = " between ";
}
package com.example.test1.databind.sql;
/**
* @description: 构建结果
* @author: Xiao
* @date: 2024/7/8 12:38
* @Version: 1.0
*/
public interface SqlBuilder<T> {
/**
* 构建结果
* @return
*/
String build();
}
package com.example.test1.databind.sql;
import com.example.test1.databind.sql.where.Where;
import com.example.test1.databind.sql.where.impl.WhereImpl;
import com.google.common.base.Joiner;
import org.apache.commons.lang3.StringUtils;
import java.util.Collection;
/**
* @description: 简单sql构建器
* @author: Xiao
* @date: 2024/7/8 12:25
* @Version: 1.0
*/
public class SelectSqlBuilder implements Where<SelectSqlBuilder>,SqlBuilder<SelectSqlBuilder>{
private static final String SELECT_SQL = "select %s from %s %s %s %s %s";
private static final String FROM_SQL = "left join %s as %s on %s ";
private static final String LIMIT_SQL = " limit %d,%d";
private static final String ORDER_BY_SQL = " order by %s %s";
private String multiTable;
private boolean ifMultiTableQuery = false;
private final String tableName;
private String alias = "";
private String selectColumns = " * ";
private String limitSql = "";
private String orderBySql = "";
private String lastSql = "";
private Joiner joiner = Joiner.on(" ");
private final Where<WhereImpl> where = new WhereImpl();
public SelectSqlBuilder(String tableName){
this.tableName = tableName;
}
public SelectSqlBuilder(String tableName,String alias){
this(tableName);
this.alias = alias;
}
public SelectSqlBuilder lastSql(String lastSql){
this.lastSql = lastSql;
return this;
}
public SelectSqlBuilder select(String... columns){
selectColumns = String.join(SqlConstants.COMMA,columns);
return this;
}
public SelectSqlBuilder leftJoin(String tableName,String alias,String on){
this.multiTable = String.format(FROM_SQL,tableName,alias,on);
ifMultiTableQuery = true;
return this;
}
public SelectSqlBuilder limit(long offset,long size){
this.limitSql = String.format(LIMIT_SQL,offset,size);
return this;
}
public SelectSqlBuilder orderByDescSql(String column) {
if (StringUtils.isBlank(this.orderBySql)) {
this.orderBySql = String.format(ORDER_BY_SQL, column, SqlConstants.DESC);
} else {
this.orderBySql += String.format(",%s %s", column, SqlConstants.DESC);
}
return this;
}
public SelectSqlBuilder orderByAscSql(String column) {
if (StringUtils.isBlank(this.orderBySql)) {
this.orderBySql = String.format(ORDER_BY_SQL, column, SqlConstants.ASC);
} else {
this.orderBySql += String.format(",%s %s", column, SqlConstants.ASC);
}
return this;
}
@Override
public String build() {
String from = tableName;
if(ifMultiTableQuery){
from = new StringBuilder().append(tableName).append(SqlConstants.AS).append(alias).append(multiTable).toString();
}
return String.format(SELECT_SQL,selectColumns,from,where.getSql(),orderBySql,limitSql,lastSql);
}
@Override
public SelectSqlBuilder between(String column, Object firstVal, Object secondVal) {
where.between(column,firstVal,secondVal);
return this;
}
@Override
public SelectSqlBuilder eq(String column, Object value) {
where.eq(column,value);
return this;
}
@Override
public SelectSqlBuilder ne(String column, Object value) {
where.ne(column,value);
return this;
}
@Override
public SelectSqlBuilder in(String column, Collection<?> values) {
where.in(column,values);
return this;
}
@Override
public SelectSqlBuilder in(String column, Object... values) {
where.in(column,values);
return this;
}
@Override
public SelectSqlBuilder like(String column, Object values) {
where.like(column,values);
return this;
}
@Override
public SelectSqlBuilder likeRight(String column, Object value) {
where.likeRight(column,value);
return this;
}
@Override
public SelectSqlBuilder likeLeft(String column, Object value) {
where.likeLeft(column,value);
return this;
}
@Override
public SelectSqlBuilder gt(String column, Object value) {
where.gt(column,value);
return this;
}
@Override
public SelectSqlBuilder ge(String column, Object value) {
where.ge(column,value);
return this;
}
@Override
public SelectSqlBuilder lt(String column, Object value) {
where.lt(column,value);
return this;
}
@Override
public SelectSqlBuilder le(String column, Object value) {
where.le(column,value);
return this;
}
@Override
public SelectSqlBuilder or() {
where.or();
return this;
}
@Override
public SelectSqlBuilder and() {
return null;
}
@Override
public String getSql() {
return String.format(SELECT_SQL,selectColumns,tableName,where.getSql(),orderBySql,limitSql,lastSql);
}
}
package com.example.test1.databind.sql.where;
import java.util.Collection;
/**
* @description: sql条件处理接口
* @author: Xiao
* @date: 2024/7/8 12:26
* @Version: 1.0
*/
public interface Where<Parent> {
/**
* between
*
* @param column 字段
* @param firstVal 值一
* @param secondVal 值二
* @return 链式调用
*/
Parent between(String column, Object firstVal, Object secondVal);
/**
* 等于
*
* @param column 字段
* @param value 值
* @return 链式调用
*/
Parent eq(String column, Object value);
/**
* 不等于
*
* @param column 字段
* @param value 值
* @return
*/
Parent ne(String column, Object value);
/**
* 指定列表
*
* @param column 字段
* @param values 值
* @return 链式调用
*/
Parent in(String column, Collection<?> values);
/**
* 指定列表
*
* @param column 字段
* @param values 值
* @return 链式调用
*/
Parent in(String column, Object... values);
/**
* 全模糊
*
* @param column 字段
* @param values 值
* @return 链式调用
*/
Parent like(String column, Object values);
/**
* 模糊左匹配
*
* @param column 字段
* @param value 值
* @return 链式调用
*/
Parent likeRight(String column, Object value);
/**
* 模糊右匹配
*
* @param column 字段
* @param value 值
* @return 链式调用
*/
Parent likeLeft(String column, Object value);
/**
* 大于
*
* @param column 字段
* @param value 值
* @return 链式调用
*/
Parent gt(String column, Object value);
/**
* 大于等于
*
* @param column 字段
* @param value 值
* @return 链式调用
*/
Parent ge(String column, Object value);
/**
* 小于
*
* @param column 字段
* @param value 值
* @return 链式调用
*/
Parent lt(String column, Object value);
/**
* 小于等于
*
* @param column 字段
* @param value 值
* @return 链式调用
*/
Parent le(String column, Object value);
/**
* 链式调用
* @return
*/
Parent or();
/**
* 条件拼接
* @return
*/
Parent and();
/**
* 获取结果
* @return
*/
String getSql();
}
package com.example.test1.databind.sql.where.impl;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.enums.SqlKeyword;
import com.example.test1.databind.sql.SqlConstants;
import com.example.test1.databind.sql.where.Where;
import com.example.test1.util.SqlFormatUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.Arrays;
import java.util.Collection;
import java.util.stream.Collectors;
/**
* @description:
* @author: Xiao
* @date: 2024/7/8 12:42
* @Version: 1.0
*/
public class WhereImpl implements Where<WhereImpl> {
private String whereSql = "";
@Override
public WhereImpl between(String column, Object firstVal, Object secondVal) {
//判断非逻辑运算符后缀
boolean notLogicalOperatorSuffix = !(whereSql.endsWith(SqlConstants.OR)
|| whereSql.endsWith(SqlConstants.AND));
if(StringUtils.isNotBlank(whereSql) && notLogicalOperatorSuffix){
whereSql = whereSql + SqlConstants.AND;
}
String fValue = SqlFormatUtils.parseForString(firstVal);
String sValue = SqlFormatUtils.parseForString(secondVal);
whereSql += column + SqlConstants.BETWEEN + fValue + SqlConstants.AND + sValue;
return this;
}
@Override
public WhereImpl eq(String whereColumn, Object value) {
setWhereSql(whereColumn,SqlConstants.EQ,value);
return this;
}
@Override
public WhereImpl ne(String whereColumn, Object value) {
setWhereSql(whereColumn,SqlConstants.NE,value);
return this;
}
@Override
public WhereImpl in(String whereColumn, Collection<?> values) {
String value = values.stream().map(SqlFormatUtils::parseForString).collect(Collectors.joining(SqlConstants.COMMA)) + SqlConstants.RIGHT_BRACKET;
setWhereSql(whereColumn,"in (",value);
return this;
}
@Override
public WhereImpl in(String column, Object... values) {
in(column, Arrays.stream(values).collect(Collectors.toList()));
return null;
}
@Override
public WhereImpl like(String column, Object values) {
setWhereSql(column,"like '%",values + "%' ");
return this;
}
@Override
public WhereImpl likeRight(String column, Object value) {
setWhereSql(column,"like '",value + "%' ");
return this;
}
@Override
public WhereImpl likeLeft(String column, Object value) {
setWhereSql(column,"like '%",value + "' ");
return this;
}
@Override
public WhereImpl gt(String column, Object value) {
setWhereSql(column,SqlConstants.GT,value);
return this;
}
@Override
public WhereImpl ge(String column, Object value) {
setWhereSql(column,SqlConstants.GE,value);
return this;
}
@Override
public WhereImpl lt(String column, Object value) {
setWhereSql(column,SqlConstants.LT,value);
return this;
}
@Override
public WhereImpl le(String column, Object value) {
setWhereSql(column,SqlConstants.LE,value);
return this;
}
@Override
public WhereImpl or() {
return null;
}
@Override
public WhereImpl and() {
return null;
}
@Override
public String getSql() {
if(StringUtils.isBlank(whereSql)){
return "";
}
return SqlConstants.WHERE + whereSql;
}
private void setWhereSql(String whereColumn, String symbol, Object value) {
//判断非逻辑运算符后缀
boolean notLogicalOperatorSuffix = !(whereSql.endsWith(SqlConstants.OR)
|| whereSql.endsWith(SqlConstants.AND));
if(StringUtils.isNotBlank(whereSql) && notLogicalOperatorSuffix){
whereSql += SqlConstants.AND;
}
if(!symbol.contains(SqlConstants.IN.replace(SqlConstants.BLANK,SqlConstants.SPACE))
&& symbol.contains(SqlConstants.LIKE.replace(SqlConstants.BLANK,SqlConstants.SPACE))){
value = SqlFormatUtils.parseForString(value);
}
whereSql += StrUtil.toUnderlineCase(whereColumn)+ SqlConstants.BLANK + symbol + value;
}
}
配置类:
package com.example.test1.databind.property;
/**
* @Author xx
* @Date 2024/6/28 9:28
* @Description:
* @Version 1.0
*/
public interface FastDataBindProperty {
/**
* 设置结果值库表字段
*
* @param valueColumn 结果值库表字段
*/
void setValueColumn(String valueColumn);
/**
* 设置where and后面的额外查询条件
*
* @param andCondition where and后面的额外查询条件
*/
void setAndCondition(String andCondition);
/**
* 设置查询条件值的实体类字段
*
* @param conditionProperty 实体类字段
*/
void setConditionProperty(String conditionProperty);
/**
* 设置库表查询字段
*
* @param conditionColumn 库表查询字段
*/
void setConditionColumn(String conditionColumn);
/**
* 指定查询的实体类
*
* @return 实体类
*/
Class<?> getEntityClass();
/**
* 获取查询的数据库表名
*
* @return 数据库表名
*/
String getTableName();
/**
* 获取作为条件的数据库表字段
*
* @return 作为条件的数据库表字段
*/
String getConditionColumn();
/**
* 指定Bean中获取条件值的字段
*
* @return Bean的字段
*/
String getConditionProperty();
/**
* 指定查询的额外条件
*
* @return 额外条件
*/
String getAndCondition();
/**
* 指定获取的结果值的数据库表字段
*
* @return 获取的结果值的数据库表字段
*/
String getValueColumn();
}
package com.example.test1.databind.property;
/**
* @Author xx
* @Date 2024/6/28 14:52
* @Description:
* @Version 1.0
*/
public class DefaultFastDataBindProperty implements FastDataBindProperty{
/**
* 数据库表名
*/
private String tableName;
/**
* 条件查询表字段
*/
private String conditionColumn;
/**
* 条件查询的值的来源字段
*/
private String conditionProperty;
/**
* 条件查询的值
*/
private Object conditionValue;
/**
* 结果值对应的表字段
*/
private String valueColumn;
/**
* and 语句条件
*/
private String andCondition = "";
private Class<?> entityClass;
public void setTableName(String tableName) {
this.tableName = tableName;
}
public void setConditionColumn(String conditionColumn) {
this.conditionColumn = conditionColumn;
}
public void setConditionProperty(String conditionProperty) {
this.conditionProperty = conditionProperty;
}
public void setConditionValue(Object conditionValue) {
this.conditionValue = conditionValue;
}
public void setValueColumn(String valueColumn) {
this.valueColumn = valueColumn;
}
public void setAndCondition(String andCondition) {
this.andCondition = andCondition;
}
public void setEntityClass(Class<?> entityClass) {
this.entityClass = entityClass;
}
@Override
public Class<?> getEntityClass() {
return entityClass;
}
@Override
public String getTableName() {
return tableName;
}
@Override
public String getConditionColumn() {
return conditionColumn;
}
@Override
public String getConditionProperty() {
return conditionProperty;
}
@Override
public String getAndCondition() {
return andCondition;
}
@Override
public String getValueColumn() {
return valueColumn;
}
}
package com.example.test1.databind.property;
import java.util.Optional;
/**
* @Author xx
* @Date 2024/6/28 9:30
* @Description: FastDataBind基础配置类
* @Version 1.0
*/
public abstract class BaseFastDataBindProperty implements FastDataBindProperty {
/**
* 数据库表名
*/
private final String tableName;
/**
* 条件查询表字段
*/
private String conditionColumn;
/**
* 条件查询的值的来源字段
*/
private String conditionProperty;
/**
* 结果值对应的表字段
*/
private String valueColumn;
/**
* and 语句条件
*/
private String andCondition;
/**
* 查询数据库表所对应的实体类
*/
private final Class<?> entityClass;
public BaseFastDataBindProperty(String tableName, String conditionColumn, String conditionProperty, String andCondition, Class<?> entityClass) {
this.tableName = tableName;
this.conditionColumn = conditionColumn;
this.conditionProperty = conditionProperty;
this.entityClass = entityClass;
this.andCondition = Optional.ofNullable(andCondition).orElse("");
}
public BaseFastDataBindProperty(String tableName, String conditionColumn, String conditionProperty, String valueColumn, String andCondition, Class<?> entityClass) {
this.tableName = tableName;
this.conditionColumn = conditionColumn;
this.conditionProperty = conditionProperty;
this.valueColumn = valueColumn;
this.entityClass = entityClass;
this.andCondition = Optional.ofNullable(andCondition).orElse("");
}
@Override
public void setValueColumn(String valueColumn) {
this.valueColumn = valueColumn;
}
@Override
public void setAndCondition(String andCondition) {
this.andCondition = andCondition;
}
/**
* 指定Bean中获取条件值的字段
*
* @param conditionProperty Bean的字段
*/
@Override
public void setConditionProperty(String conditionProperty) {
this.conditionProperty = conditionProperty;
}
@Override
public void setConditionColumn(String conditionColumn) {
this.conditionColumn = conditionColumn;
}
/**
* 指定查询实体
*
* @return 实体类
*/
@Override
public Class<?> getEntityClass() {
return entityClass;
}
/**
* 获取查询的数据库表名
*
* @return 数据库表名
*/
@Override
public String getTableName() {
return tableName;
}
/**
* 获取作为条件的数据库表字段
*
* @return 作为条件的数据库表字段
*/
@Override
public String getConditionColumn() {
return conditionColumn;
}
/**
* 指定Bean中获取条件值的字段
*
* @return Bean的字段
*/
@Override
public String getConditionProperty() {
return conditionProperty;
}
/**
* 指定查询的额外条件
*
* @return 额外条件
*/
@Override
public String getAndCondition() {
return andCondition;
}
/**
* 指定获取的结果值的数据库表字段
*
* @return 获取的结果值的数据库表字段
*/
@Override
public String getValueColumn() {
return valueColumn;
}
}
用到的相关工具类:
package com.example.test1.util;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.poi.ss.usermodel.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.text.ParseException;
import java.util.Date;
import static cn.hutool.core.text.CharPool.DOT;
/**
* @Author xx
* @Date 2024/6/28 11:01
* @Description: 反射工具类
* @Version 1.0
*/
@SuppressWarnings("rawtypes")
public class ReflectUtil {
private static Logger logger = LoggerFactory.getLogger(ReflectUtil.class);
private static final String SETTER_PREFIX = "set";
private static final String GETTER_PREFIX = "get";
private static final String CGLIB_CLASS_SEPARATOR = "$$";
private static String[] parsePatterns = {
"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
"yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};
/**
* 调用Getter方法.
* 支持多级,如:对象名.对象名.方法
*/
@SuppressWarnings("unchecked")
public static <E> E invokeGetter(Object obj, String propertyName) {
Object object = obj;
for (String name : StringUtils.split(propertyName, DOT)) {
String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name);
object = invokeMethod(object, getterMethodName, new Class[]{}, new Object[]{});
}
return (E) object;
}
/**
* 调用Setter方法, 仅匹配方法名。
* 支持多级,如:对象名.对象名.方法
*/
public static <E> void invokeSetter(Object obj, String propertyName, E value) {
Object object = obj;
String[] names = StringUtils.split(propertyName, ".");
for (int i = 0; i < names.length; i++) {
if (i < names.length - 1) {
String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
object = invokeMethod(object, getterMethodName, new Class[]{}, new Object[]{});
} else {
String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
invokeMethodByName(object, setterMethodName, new Object[]{value});
}
}
}
/**
* 直接调用对象方法, 无视private/protected修饰符.
* 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用.
* 同时匹配方法名+参数类型,
*/
@SuppressWarnings("unchecked")
public static <E> E invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes,
final Object[] args) {
if (obj == null || methodName == null) {
return null;
}
Method method = getAccessibleMethod(obj, methodName, parameterTypes);
if (method == null) {
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
return null;
}
try {
return (E) method.invoke(obj, args);
} catch (Exception e) {
String msg = "method: " + method + ", obj: " + obj + ", args: " + args + "";
throw convertReflectionExceptionToUnchecked(msg, e);
}
}
/**
* 直接调用对象方法, 无视private/protected修饰符,
* 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用.
* 只匹配函数名,如果有多个同名函数调用第一个。
*/
@SuppressWarnings("unchecked")
public static <E> E invokeMethodByName(final Object obj, final String methodName, final Object[] args) {
Method method = getAccessibleMethodByName(obj, methodName, args.length);
if (method == null) {
// 如果为空不报错,直接返回空。
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
return null;
}
try {
// 类型转换(将参数数据类型转换为目标方法参数类型)
Class<?>[] cs = method.getParameterTypes();
for (int i = 0; i < cs.length; i++) {
if (args[i] != null && !args[i].getClass().equals(cs[i])) {
if (cs[i] == String.class) {
args[i] = Convert.toStr(args[i]);
if (StringUtils.endsWith((String) args[i], ".0")) {
args[i] = StringUtils.substringBefore((String) args[i], ".0");
}
} else if (cs[i] == Integer.class) {
args[i] = Convert.toInt(args[i]);
} else if (cs[i] == Long.class) {
args[i] = Convert.toLong(args[i]);
} else if (cs[i] == Double.class) {
args[i] = Convert.toDouble(args[i]);
} else if (cs[i] == Float.class) {
args[i] = Convert.toFloat(args[i]);
} else if (cs[i] == Date.class) {
if (args[i] instanceof String) {
args[i] = parseDate(args[i]);
} else {
args[i] = DateUtil.getJavaDate((Double) args[i]);
}
} else if (cs[i] == boolean.class || cs[i] == Boolean.class) {
args[i] = Convert.toBool(args[i]);
}
}
}
return (E) method.invoke(obj, args);
} catch (Exception e) {
String msg = "method: " + method + ", obj: " + obj + ", args: " + args + "";
throw convertReflectionExceptionToUnchecked(msg, e);
}
}
/**
* 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
* 如向上转型到Object仍无法找到, 返回null.
* 只匹配函数名。
* 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
*/
public static Method getAccessibleMethodByName(final Object obj, final String methodName, int argsNum) {
// 为空不报错。直接返回 null
if (obj == null) {
return null;
}
Validate.notBlank(methodName, "methodName can't be blank");
for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
Method[] methods = searchType.getDeclaredMethods();
for (Method method : methods) {
if (method.getName().equals(methodName) && method.getParameterTypes().length == argsNum) {
makeAccessible(method);
return method;
}
}
}
return null;
}
/**
* 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
* 如向上转型到Object仍无法找到, 返回null.
* 匹配函数名+参数类型。
* 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
*/
public static Method getAccessibleMethod(final Object obj, final String methodName,
final Class<?>... parameterTypes) {
// 为空不报错。直接返回 null
if (obj == null) {
return null;
}
Validate.notBlank(methodName, "methodName can't be blank");
for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
try {
Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
makeAccessible(method);
return method;
} catch (NoSuchMethodException e) {
continue;
}
}
return null;
}
/**
* 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
*/
public static void makeAccessible(Method method) {
boolean status =(Modifier.isPublic(method.getModifiers()) && Modifier.isPublic(method.getDeclaringClass().getModifiers()))
|| method.isAccessible();
if (status) {
return;
}
method.setAccessible(true);
}
/**
* 将反射时的checked exception转换为unchecked exception.
*/
public static RuntimeException convertReflectionExceptionToUnchecked(String msg, Exception e) {
if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException
|| e instanceof NoSuchMethodException) {
return new IllegalArgumentException(msg, e);
} else if (e instanceof InvocationTargetException) {
return new RuntimeException(msg, ((InvocationTargetException) e).getTargetException());
}
return new RuntimeException(msg, e);
}
/**
* 日期转换
* @param str
* @return
*/
private static Date parseDate(Object str) {
if(str == null){
return null;
}
try {
return DateUtils.parseDate(str.toString(),parsePatterns);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}
package com.example.test1.util;
import org.apache.commons.lang3.StringUtils;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.text.NumberFormat;
import java.util.Set;
import static cn.hutool.core.util.CharsetUtil.UTF_8;
/**
* @Author xx
* @Date 2024/6/28 11:06
* @Description: 类型转换器
* @Version 1.0
*/
public class Convert {
/**
* 转换为字符串<br>
* 如果给定的值为null,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static String toStr(Object value, String defaultValue) {
if (null == value) {
return defaultValue;
}
if (value instanceof String) {
return (String) value;
}
return value.toString();
}
/**
* 转换为字符串<br>
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static String toStr(Object value) {
return toStr(value, null);
}
/**
* 转换为字符<br>
* 如果给定的值为null,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Character toChar(Object value, Character defaultValue) {
if (null == value) {
return defaultValue;
}
if (value instanceof Character) {
return (Character) value;
}
final String valueStr = toStr(value, null);
return StringUtils.isEmpty(valueStr) ? defaultValue : valueStr.charAt(0);
}
/**
* 转换为字符<br>
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Character toChar(Object value) {
return toChar(value, null);
}
/**
* 转换为byte<br>
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Byte toByte(Object value, Byte defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Byte) {
return (Byte) value;
}
if (value instanceof Number) {
return ((Number) value).byteValue();
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return Byte.parseByte(valueStr);
} catch (Exception e) {
return defaultValue;
}
}
/**
* 转换为byte<br>
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Byte toByte(Object value) {
return toByte(value, null);
}
/**
* 转换为Short<br>
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Short toShort(Object value, Short defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Short) {
return (Short) value;
}
if (value instanceof Number) {
return ((Number) value).shortValue();
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return Short.parseShort(valueStr.trim());
} catch (Exception e) {
return defaultValue;
}
}
/**
* 转换为Short<br>
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Short toShort(Object value) {
return toShort(value, null);
}
/**
* 转换为Number<br>
* 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Number toNumber(Object value, Number defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Number) {
return (Number) value;
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return NumberFormat.getInstance().parse(valueStr);
} catch (Exception e) {
return defaultValue;
}
}
/**
* 转换为Number<br>
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Number toNumber(Object value) {
return toNumber(value, null);
}
/**
* 转换为int<br>
* 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Integer toInt(Object value, Integer defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Integer) {
return (Integer) value;
}
if (value instanceof Number) {
return ((Number) value).intValue();
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return Integer.parseInt(valueStr.trim());
} catch (Exception e) {
return defaultValue;
}
}
/**
* 转换为int<br>
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Integer toInt(Object value) {
return toInt(value, null);
}
/**
* 转换为Integer数组<br>
*
* @param str 被转换的值
* @return 结果
*/
public static Integer[] toIntArray(String str) {
return toIntArray(",", str);
}
/**
* 转换为Long数组<br>
*
* @param str 被转换的值
* @return 结果
*/
public static Long[] toLongArray(String str) {
return toLongArray(",", str);
}
/**
* 转换为Integer数组<br>
*
* @param split 分隔符
* @param split 被转换的值
* @return 结果
*/
public static Integer[] toIntArray(String split, String str) {
if (StringUtils.isEmpty(str)) {
return new Integer[]{};
}
String[] arr = str.split(split);
final Integer[] ints = new Integer[arr.length];
for (int i = 0; i < arr.length; i++) {
final Integer v = toInt(arr[i], 0);
ints[i] = v;
}
return ints;
}
/**
* 转换为Long数组<br>
*
* @param split 分隔符
* @param str 被转换的值
* @return 结果
*/
public static Long[] toLongArray(String split, String str) {
if (StringUtils.isEmpty(str)) {
return new Long[]{};
}
String[] arr = str.split(split);
final Long[] longs = new Long[arr.length];
for (int i = 0; i < arr.length; i++) {
final Long v = toLong(arr[i], null);
longs[i] = v;
}
return longs;
}
/**
* 转换为String数组<br>
*
* @param str 被转换的值
* @return 结果
*/
public static String[] toStrArray(String str) {
return toStrArray(",", str);
}
/**
* 转换为String数组<br>
*
* @param split 分隔符
* @param split 被转换的值
* @return 结果
*/
public static String[] toStrArray(String split, String str) {
return str.split(split);
}
/**
* 转换为long<br>
* 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Long toLong(Object value, Long defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Long) {
return (Long) value;
}
if (value instanceof Number) {
return ((Number) value).longValue();
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
// 支持科学计数法
return new BigDecimal(valueStr.trim()).longValue();
} catch (Exception e) {
return defaultValue;
}
}
/**
* 转换为long<br>
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Long toLong(Object value) {
return toLong(value, null);
}
/**
* 转换为double<br>
* 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Double toDouble(Object value, Double defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Double) {
return (Double) value;
}
if (value instanceof Number) {
return ((Number) value).doubleValue();
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
// 支持科学计数法
return new BigDecimal(valueStr.trim()).doubleValue();
} catch (Exception e) {
return defaultValue;
}
}
/**
* 转换为double<br>
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Double toDouble(Object value) {
return toDouble(value, null);
}
/**
* 转换为Float<br>
* 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Float toFloat(Object value, Float defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Float) {
return (Float) value;
}
if (value instanceof Number) {
return ((Number) value).floatValue();
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return Float.parseFloat(valueStr.trim());
} catch (Exception e) {
return defaultValue;
}
}
/**
* 转换为Float<br>
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Float toFloat(Object value) {
return toFloat(value, null);
}
/**
* 转换为boolean<br>
* String支持的值为:true、false、yes、ok、no,1,0 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Boolean toBool(Object value, Boolean defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Boolean) {
return (Boolean) value;
}
String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
valueStr = valueStr.trim().toLowerCase();
switch (valueStr) {
case "true":
return true;
case "false":
return false;
case "yes":
return true;
case "ok":
return true;
case "no":
return false;
case "1":
return true;
case "0":
return false;
default:
return defaultValue;
}
}
/**
* 转换为boolean<br>
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Boolean toBool(Object value) {
return toBool(value, null);
}
/**
* 转换为Enum对象<br>
* 如果给定的值为空,或者转换失败,返回默认值<br>
*
* @param clazz Enum的Class
* @param value 值
* @param defaultValue 默认值
* @return Enum
*/
public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value, E defaultValue) {
if (value == null) {
return defaultValue;
}
if (clazz.isAssignableFrom(value.getClass())) {
@SuppressWarnings("unchecked")
E myE = (E) value;
return myE;
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return Enum.valueOf(clazz, valueStr);
} catch (Exception e) {
return defaultValue;
}
}
/**
* 转换为Enum对象<br>
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
*
* @param clazz Enum的Class
* @param value 值
* @return Enum
*/
public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value) {
return toEnum(clazz, value, null);
}
/**
* 转换为BigInteger<br>
* 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static BigInteger toBigInteger(Object value, BigInteger defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof BigInteger) {
return (BigInteger) value;
}
if (value instanceof Long) {
return BigInteger.valueOf((Long) value);
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return new BigInteger(valueStr);
} catch (Exception e) {
return defaultValue;
}
}
/**
* 转换为BigInteger<br>
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static BigInteger toBigInteger(Object value) {
return toBigInteger(value, null);
}
/**
* 转换为BigDecimal<br>
* 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static BigDecimal toBigDecimal(Object value, BigDecimal defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof BigDecimal) {
return (BigDecimal) value;
}
if (value instanceof Long) {
return new BigDecimal((Long) value);
}
if (value instanceof Double) {
return new BigDecimal((Double) value);
}
if (value instanceof Integer) {
return new BigDecimal((Integer) value);
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return new BigDecimal(valueStr);
} catch (Exception e) {
return defaultValue;
}
}
/**
* 转换为BigDecimal<br>
* 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static BigDecimal toBigDecimal(Object value) {
return toBigDecimal(value, null);
}
/**
* 将对象转为字符串<br>
* 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
*
* @param obj 对象
* @return 字符串
*/
public static String utf8Str(Object obj) {
return str(obj, Charset.forName(UTF_8));
}
/**
* 将对象转为字符串<br>
* 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
*
* @param obj 对象
* @param charsetName 字符集
* @return 字符串
*/
public static String str(Object obj, String charsetName) {
return str(obj, Charset.forName(charsetName));
}
/**
* 将对象转为字符串<br>
* 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
*
* @param obj 对象
* @param charset 字符集
* @return 字符串
*/
public static String str(Object obj, Charset charset) {
if (null == obj) {
return null;
}
if (obj instanceof String) {
return (String) obj;
} else if (obj instanceof byte[] || obj instanceof Byte[]) {
return str((Byte[]) obj, charset);
} else if (obj instanceof ByteBuffer) {
return str((ByteBuffer) obj, charset);
}
return obj.toString();
}
/**
* 将byte数组转为字符串
*
* @param bytes byte数组
* @param charset 字符集
* @return 字符串
*/
public static String str(byte[] bytes, String charset) {
return str(bytes, StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset));
}
/**
* 解码字节码
*
* @param data 字符串
* @param charset 字符集,如果此字段为空,则解码的结果取决于平台
* @return 解码后的字符串
*/
public static String str(byte[] data, Charset charset) {
if (data == null) {
return null;
}
if (null == charset) {
return new String(data);
}
return new String(data, charset);
}
/**
* 将编码的byteBuffer数据转换为字符串
*
* @param data 数据
* @param charset 字符集,如果为空使用当前系统字符集
* @return 字符串
*/
public static String str(ByteBuffer data, String charset) {
if (data == null) {
return null;
}
return str(data, Charset.forName(charset));
}
/**
* 将编码的byteBuffer数据转换为字符串
*
* @param data 数据
* @param charset 字符集,如果为空使用当前系统字符集
* @return 字符串
*/
public static String str(ByteBuffer data, Charset charset) {
if (null == charset) {
charset = Charset.defaultCharset();
}
return charset.decode(data).toString();
}
// ----------------------------------------------------------------------- 全角半角转换
/**
* 半角转全角
*
* @param input String.
* @return 全角字符串.
*/
public static String tosbc(String input) {
return tosbc(input, null);
}
/**
* 半角转全角
*
* @param input String
* @param notConvertSet 不替换的字符集合
* @return 全角字符串.
*/
public static String tosbc(String input, Set<Character> notConvertSet) {
char[] chars = input.toCharArray();
for (int i = 0; i < chars.length; i++) {
if (null != notConvertSet && notConvertSet.contains(chars[i])) {
// 跳过不替换的字符
continue;
}
if (chars[i] == ' ') {
chars[i] = '\u3000';
} else if (chars[i] < '\177') {
chars[i] = (char) (chars[i] + 65248);
}
}
return new String(chars);
}
/**
* 全角转半角
*
* @param input String.
* @return 半角字符串
*/
public static String todbc(String input) {
return todbc(input, null);
}
/**
* 替换全角为半角
*
* @param text 文本
* @param notConvertSet 不替换的字符集合
* @return 替换后的字符
*/
public static String todbc(String text, Set<Character> notConvertSet) {
char[] chars = text.toCharArray();
for (int i = 0; i < chars.length; i++) {
if (null != notConvertSet && notConvertSet.contains(chars[i])) {
// 跳过不替换的字符
continue;
}
if (chars[i] == '\u3000') {
chars[i] = ' ';
} else if (chars[i] > '\uFF00' && chars[i] < '\uFF5F') {
chars[i] = (char) (chars[i] - 65248);
}
}
String returnString = new String(chars);
return returnString;
}
/**
* 数字金额大写转换 先写个完整的然后将如零拾替换成零
*
* @param n 数字
* @return 中文大写数字
*/
public static String digitUppercase(double n) {
String[] fraction = {"角", "分"};
String[] digit = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
String[][] unit = {{"元", "万", "亿"}, {"", "拾", "佰", "仟"}};
String head = n < 0 ? "负" : "";
n = Math.abs(n);
String s = "";
for (int i = 0; i < fraction.length; i++) {
s += (digit[(int) (Math.floor(n * 10 * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", "");
}
if (s.length() < 1) {
s = "整";
}
int integerPart = (int) Math.floor(n);
for (int i = 0; i < unit[0].length && integerPart > 0; i++) {
String p = "";
for (int j = 0; j < unit[1].length && n > 0; j++) {
p = digit[integerPart % 10] + unit[1][j] + p;
integerPart = integerPart / 10;
}
s = p.replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i] + s;
}
return head + s.replaceAll("(零.)*零元", "元").replaceFirst("(零.)+", "").replaceAll("(零.)+", "零").replaceAll("^整$", "零元整");
}
}
package com.example.test1.util;
import cn.hutool.core.util.ReflectUtil;
import lombok.SneakyThrows;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* @Author xx
* @Date 2024/6/27 15:10
* @Description:
* @Version 1.0
*/
public class SpElUtils {
private final static String RESULT = "result";
/**
* 用于springEL表达式的解析
*/
private static SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
/**
* 用于获取方法参数定义的名字
*/
private static DefaultParameterNameDiscoverer defaultParameterNameDiscoverer = new DefaultParameterNameDiscoverer();
/**
* 根据EL表达式获取值
*
* @param joinPoint 连接点
* @param key springEL表达式
* @param classes 返回对象的class
* @return 获取值
*/
public static <T> T getValue(ProceedingJoinPoint joinPoint, String key, Class<T> classes) {
// 解析springEL表达式
EvaluationContext evaluationContext = getEvaluationContext(joinPoint, null);
return spelExpressionParser.parseExpression(key).getValue(evaluationContext, classes);
}
/**
* 根据EL表达式获取值
*
* @param joinPoint 连接点
* @param expression springEL表达式
* @param classes 返回对象的class
* @param result result
* @return 获取值
*/
public static <T> T getValue(JoinPoint joinPoint, String expression, Class<T> classes, Object result) throws NoSuchMethodException {
// 解析springEL表达式
EvaluationContext evaluationContext = getEvaluationContext(joinPoint, result);
return spelExpressionParser.parseExpression(expression).getValue(evaluationContext, classes);
}
/**
* 根据EL表达式获取值
*
* @param expression springEL表达式
* @param classes 返回对象的class
* @return 获取值
*/
public static <T> T getValue(String expression, Object sourceData, Class<T> classes) throws NoSuchMethodException {
// 解析springEL表达式
return getValue(expression, classes, getEvaluationContext(sourceData));
}
@SneakyThrows
public static EvaluationContext getEvaluationContext(Object sourceData){
EvaluationContext evaluationContext = new StandardEvaluationContext();
for (Field field : ReflectUtil.getFields(sourceData.getClass())) {
field.setAccessible(true);
evaluationContext.setVariable(field.getName(), field.get(sourceData));
}
return evaluationContext;
}
/**
* 根据EL表达式获取值
*
* @param expression springEL表达式
* @param classes 返回对象的class
* @return 获取值
*/
public static <T> T getValue(String expression, Class<T> classes, EvaluationContext evaluationContext) throws NoSuchMethodException {
// 解析springEL表达式
return spelExpressionParser.parseExpression(expression).getValue(evaluationContext, classes);
}
/**
* 获取参数上下文
*
* @param joinPoint 连接点
* @return 参数上下文
*/
@SneakyThrows
private static EvaluationContext getEvaluationContext(JoinPoint joinPoint, Object result) {
EvaluationContext evaluationContext = new StandardEvaluationContext();
String[] parameterNames = defaultParameterNameDiscoverer.getParameterNames(getMethod(joinPoint));
for (int i = 0; i < parameterNames.length; i++) {
evaluationContext.setVariable(parameterNames[i], joinPoint.getArgs()[i]);
}
evaluationContext.setVariable(RESULT, result);
return evaluationContext;
}
/**
* 获取目标方法
*
* @param joinPoint 连接点
* @return 目标方法
*/
private static Method getMethod(JoinPoint joinPoint) throws NoSuchMethodException {
Signature signature = joinPoint.getSignature();
return joinPoint.getTarget().getClass()
.getMethod(signature.getName(), ((MethodSignature) signature).getParameterTypes());
}
}
package com.example.test1.util;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import java.util.Objects;
import java.util.ServiceLoader;
import java.util.concurrent.TimeUnit;
/**
* @Author xx
* @Date 2024/6/27 14:19
* @Description:
* @Version 1.0
*/
public class SpiUtils {
/**
* SPI缓存key
*
* @param <T>
*/
private static final class SpiCacheKeyEntity<T> {
/**
* 实现的接口class
*/
private Class<T> classType;
/**
* 实现类的名称
*/
private String serviceName;
public SpiCacheKeyEntity(Class<T> classType, String serviceName) {
this.classType = classType;
this.serviceName = serviceName;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
SpiCacheKeyEntity<?> spiCacheKeyEntity = (SpiCacheKeyEntity<?>) o;
return Objects.equals(classType, spiCacheKeyEntity.classType) && Objects.equals(serviceName, spiCacheKeyEntity.serviceName);
}
@Override
public int hashCode() {
return Objects.hash(classType, serviceName);
}
}
private SpiUtils() {
}
/**
* 单例
* 根据接口实现类的名称以及接口获取实现类
*
* @param serviceName 实现类的名称
* @param classType 实现的接口class
* @return 具体的实现类
*/
public static <T> T getServiceImpl(String serviceName, Class<T> classType) {
return (T) SERVICE_IMPL_CACHE.get(new SpiCacheKeyEntity(classType, serviceName));
}
/**
* SPI接口实现类 Caffeine软引用同步加载缓存(其内部做了同步处理)
*/
public final static LoadingCache<SpiCacheKeyEntity, Object> SERVICE_IMPL_CACHE = Caffeine.newBuilder()
.expireAfterAccess(24, TimeUnit.HOURS)
.maximumSize(100)
.softValues()
.build(spiCacheKeyEntity -> getServiceImplByPrototype(spiCacheKeyEntity.serviceName, spiCacheKeyEntity.classType));
/**
* 多例
* 根据接口实现类的名称以及接口获取实现类
*
* @param serviceName 实现类的名称
* @param classType 实现的接口class
* @return 具体的实现类
*/
public static <T> T getServiceImplByPrototype(String serviceName, Class<T> classType) {
ServiceLoader<T> services = ServiceLoader.load(classType, Thread.currentThread().getContextClassLoader());
for (T s : services) {
if (s.getClass().getSimpleName().equals(serviceName)) {
return s;
}
}
return null;
}
}
package com.example.test1.util;
import com.example.test1.databind.sql.SqlConstants;
/**
* @description: sql工具
* @author: Xiao
* @date: 2024/7/8 13:43
* @Version: 1.0
*/
public class SqlFormatUtils {
/**
* 大写字母表
*/
private static final String UPPER_CASE_LETTER = "ABCDEFGHIJKLMNOPQRLSTUVWYZ";
private static final String SERIAL_VERSION_UID = "serialVersionUID";
/**
* 解析字段值为符合MySQL的字符串形式
* @param val 字段值
* @return 符合mysql的字符串
*/
public static String parseForString(Object val) {
if(val == null || val instanceof Number || val instanceof Boolean){
return String.valueOf(val);
}
if(val instanceof String){
String valStr = val.toString();
if(valStr.startsWith(SqlConstants.SINGLE_QUOTES) && valStr.endsWith(SqlConstants.SINGLE_QUOTES)){
return val.toString();
}
}
return SqlConstants.SINGLE_QUOTES + val + SqlConstants.SINGLE_QUOTES;
}
}
基本就是这些过程。


被折叠的 条评论
为什么被折叠?



