需求描述:
在一个项目中,很多的业务表都有一个唯一编码字段,如下:
同事把生成唯一编码字段的代码封装成了一个工具类,符合生成唯一编码规则的地方就可以使用啦!
代码如下:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CustomCode {
}
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.StaticLog;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.jeecg.common.aspect.annotation.CustomCode;
import org.springframework.util.ObjectUtils;
import java.lang.reflect.Field;
import java.util.Date;
/**
* 生成唯一编码
* @author liugang
*/
public class GenerateCodeUtil {
/**
* 日期格式
*/
public static final String dateFormat = "yyyyMMdd";
public static final Integer len = 4;
/**
* 生成统一编码
* @param prefix 编码前缀,不能为null
* @param code 历史code,可以为null,当为null时会自动生成新编码,不为null时会解析历史code并自动递增
* @return
*/
public static String generateCode(String prefix,String code){
return generateCode(prefix,code,len);
}
/**
* 生成统一编码
* @param prefix 编码前缀,不能为null
* @param entity 历史code,可以为null,当为null时会自动生成新编码,不为null时会解析历史code并自动递增
* @return
*/
public static <T> String generateCode(String prefix, T entity, BaseMapper baseMapper){
return generateCode(prefix,entity,baseMapper,len);
}
public static <T> String generateCode(String prefix, T entity, BaseMapper baseMapper,Integer len){
if (ObjectUtils.isEmpty(baseMapper)){
throw new IllegalArgumentException("baseMapper must not be null");
}
try {
QueryWrapper<T> queryWrapper = new QueryWrapper<>();
String columnName = getCodeName(entity.getClass());
StaticLog.info("获取到属性值{}",columnName);
String codeColumn = StrUtil.toUnderlineCase (columnName);
queryWrapper.likeRight(codeColumn,prefix+getTodayStr());
queryWrapper.orderByDesc(codeColumn);
queryWrapper.last("limit 1");
Object o = baseMapper.selectOne(queryWrapper);
String code = BeanUtil.getProperty(o, columnName).toString();
return generateCode(prefix,code,len);
}catch (NullPointerException e){
StaticLog.info("获取历史Code失败,自动生成新Code",e.getMessage());
return generateNewCode(prefix,len);
}
}
private static String getCodeName(Class<?> clazz){
Field[] fields = clazz.getDeclaredFields();
for(Field field : fields){
CustomCode annotation = field.getAnnotation(CustomCode.class);
if (annotation != null){
return field.getName();
}
}
throw new IllegalStateException(String.format("在实体%s没有找到声明@CustomCode的属性",clazz.getName()));
}
/**
* 生成统一编码
* @param prefix 编码前缀,不能为null
* @param code 历史code,可以为null,当为null时会自动生成新编码,不为null时会解析历史code并自动递增
* @param len 流水号长度
* @return
*/
public static String generateCode(String prefix,String code,Integer len){
if(StrUtil.isBlank(prefix)){
throw new IllegalArgumentException("prefix 不能为 null");
}
if (StrUtil.isBlank(code)){
return generateNewCode(prefix,len);
}else {
return generateOldCode(prefix, code,len);
}
}
private static String generateOldCode(String prefix,String code,Integer len){//eqin202308170001
try{
StringBuffer result = new StringBuffer(prefix);
StringBuffer old = new StringBuffer(code);
int dateLength = dateFormat.length();
int prefixLength = prefix.length();
String date = old.substring(prefixLength,+prefixLength+dateLength);
if (isToday(date)){
StaticLog.info("新的一天,自动生成新编码");
return generateNewCode(prefix,len);
}
result.append(date);
String no = old.substring(prefixLength+dateLength);
result.append(String.format("%0"+len+"d",Integer.parseInt(no)+1));
return result.toString();
}catch (Exception e){
StaticLog.error("解析编码出错,自动生成新编码");
return generateNewCode(prefix,len);
}
}
private static boolean isToday(String date){
return !DateUtil.isSameDay(DateUtil.parse(date),new Date());
}
private static String generateNewCode(String prefix,Integer len){
return String.format("%s%s%s",prefix,getTodayStr(),String.format("%0"+len+"d",1));
}
private static String getTodayStr(){
return DateUtil.format(new Date(), dateFormat);
}
}