调整 errorCode 模块的自动生成逻辑

This commit is contained in:
YunaiV 2021-04-19 01:21:35 +08:00
parent 54e26d9e8b
commit 06774a7a0b
20 changed files with 428 additions and 355 deletions

View File

@ -1,26 +1,36 @@
package cn.iocoder.dashboard.framework.errorcode.config; package cn.iocoder.dashboard.framework.errorcode.config;
import cn.iocoder.dashboard.modules.system.service.errorcode.ErrorCodeRemoteLoaderImpl; import cn.iocoder.dashboard.framework.errorcode.core.generator.ErrorCodeAutoGenerator;
import cn.iocoder.dashboard.modules.system.service.errorcode.ErrorCodeAutoGeneratorImpl; import cn.iocoder.dashboard.framework.errorcode.core.loader.ErrorCodeLoader;
import cn.iocoder.dashboard.framework.errorcode.core.service.ErrorCodeFrameworkService;
import cn.iocoder.dashboard.framework.errorcode.core.loader.ErrorCodeLoaderImpl;
import cn.iocoder.dashboard.framework.errorcode.core.generator.ErrorCodeAutoGeneratorImpl;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.EnableScheduling;
/**
* 错误码配置类
*/
@Configuration @Configuration
@EnableConfigurationProperties(ErrorCodeProperties.class) @EnableConfigurationProperties(ErrorCodeProperties.class)
@EnableScheduling // 开启调度任务的功能因为 ErrorCodeRemoteLoader 通过定时刷新错误码 @EnableScheduling // 开启调度任务的功能因为 ErrorCodeRemoteLoader 通过定时刷新错误码
public class ErrorCodeAutoConfiguration { public class ErrorCodeAutoConfiguration {
@Bean @Bean
public ErrorCodeAutoGeneratorImpl errorCodeAutoGenerator(ErrorCodeProperties errorCodeProperties) { public ErrorCodeAutoGenerator errorCodeAutoGenerator(@Value("${spring.application.name}") String applicationName,
return new ErrorCodeAutoGeneratorImpl(errorCodeProperties.getGroup()) ErrorCodeProperties errorCodeProperties,
.setErrorCodeConstantsClass(errorCodeProperties.getConstantsClass()); ErrorCodeFrameworkService errorCodeFrameworkService) {
return new ErrorCodeAutoGeneratorImpl(applicationName, errorCodeProperties.getConstantsClass(),
errorCodeFrameworkService);
} }
@Bean @Bean
public ErrorCodeRemoteLoaderImpl errorCodeRemoteLoader(ErrorCodeProperties errorCodeProperties) { public ErrorCodeLoader errorCodeLoader(@Value("${spring.application.name}") String applicationName,
return new ErrorCodeRemoteLoaderImpl(errorCodeProperties.getGroup()); ErrorCodeFrameworkService errorCodeFrameworkService) {
return new ErrorCodeLoaderImpl(applicationName, errorCodeFrameworkService);
} }
} }

View File

@ -1,25 +1,25 @@
package cn.iocoder.dashboard.framework.errorcode.config; package cn.iocoder.dashboard.framework.errorcode.config;
import lombok.Getter; import lombok.Data;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotEmpty;
/**
* 错误码的配置属性类
*
* @author dlyan
*/
@ConfigurationProperties("yudao.error-code") @ConfigurationProperties("yudao.error-code")
@Data
@Validated @Validated
@Getter
@Setter
public class ErrorCodeProperties { public class ErrorCodeProperties {
/**
* 应用分组
*/
@NotNull(message = "应用分组不能为空,请设置 yudao.error-code.group 配置项,推荐直接使用 spring.application.name 配置项")
private String group;
/** /**
* 错误码枚举类 * 错误码枚举类
*/ */
@NotEmpty(message = "错误码枚举类不能为空")
private String constantsClass; private String constantsClass;
}
}

View File

@ -1,14 +0,0 @@
package cn.iocoder.dashboard.framework.errorcode.core;
public interface ErrorCodeRemoteLoader {
/**
* 全量加载 ErrorCode 错误码
*/
void loadErrorCodes();
/**
* 增量加载 ErrorCode 错误码
*/
void refreshErrorCodes();
}

View File

@ -1,19 +1,25 @@
package cn.iocoder.dashboard.modules.system.controller.errorcode.dto; package cn.iocoder.dashboard.framework.errorcode.core.dto;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.io.Serializable;
/** /**
* 错误码自动生成 DTO * 错误码自动生成 DTO
*
* @author dylan
*/ */
@Data @Data
@Accessors(chain = true) @Accessors(chain = true)
public class ErrorCodeAutoGenerateDTO implements Serializable { public class ErrorCodeAutoGenerateReqDTO {
/**
* 应用名
*/
@NotNull(message = "应用名不能为空")
private String applicationName;
/** /**
* 错误码编码 * 错误码编码
*/ */
@ -24,10 +30,5 @@ public class ErrorCodeAutoGenerateDTO implements Serializable {
*/ */
@NotEmpty(message = "错误码错误提示不能为空") @NotEmpty(message = "错误码错误提示不能为空")
private String message; private String message;
/**
* 错误码分组
*/
@NotNull(message = "错误码分组不能为空")
private String group;
} }

View File

@ -0,0 +1,28 @@
package cn.iocoder.dashboard.framework.errorcode.core.dto;
import lombok.Data;
import java.util.Date;
/**
* 错误码的 Response DTO
*
* @author 芋道源码
*/
@Data
public class ErrorCodeRespDTO {
/**
* 错误码编码
*/
private Integer code;
/**
* 错误码错误提示
*/
private String message;
/**
* 更新时间
*/
private Date updateTime;
}

View File

@ -1,6 +1,8 @@
package cn.iocoder.dashboard.framework.errorcode.core; package cn.iocoder.dashboard.framework.errorcode.core.generator;
/** /**
* 错误码的自动生成器
*
* @author dylan * @author dylan
*/ */
public interface ErrorCodeAutoGenerator { public interface ErrorCodeAutoGenerator {
@ -9,4 +11,5 @@ public interface ErrorCodeAutoGenerator {
* 将配置类到错误码写入数据库 * 将配置类到错误码写入数据库
*/ */
void execute(); void execute();
} }

View File

@ -0,0 +1,101 @@
package cn.iocoder.dashboard.framework.errorcode.core.generator;
import cn.iocoder.dashboard.common.exception.ErrorCode;
import cn.iocoder.dashboard.framework.errorcode.core.dto.ErrorCodeAutoGenerateReqDTO;
import cn.iocoder.dashboard.framework.errorcode.core.service.ErrorCodeFrameworkService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* ErrorCodeAutoGenerator 的实现类
* 目的是扫描指定的 {@link #errorCodeConstantsClass} 写入到 system 的数据库中
*
* @author dylan
*/
@RequiredArgsConstructor
@Slf4j
public class ErrorCodeAutoGeneratorImpl implements ErrorCodeAutoGenerator {
/**
* 应用分组
*/
private final String applicationName;
/**
* 错误码枚举类
*/
private final String errorCodeConstantsClass;
/**
* 错误码 Service
*/
private final ErrorCodeFrameworkService errorCodeService;
@Override
@EventListener(ApplicationReadyEvent.class)
@Async // 异步保证项目的启动过程毕竟非关键流程
public void execute() {
// 第一步获得错误码类
Class<?> errorCodeConstantsClazz = parseErrorCodeConstantsClass();
if (errorCodeConstantsClazz == null) {
return;
}
// 第二步获得错误码数组
List<ErrorCodeAutoGenerateReqDTO> autoGenerateDTOs = parseErrorCode(errorCodeConstantsClazz);
log.info("[execute][解析到错误码数量为 ({}) 个]", autoGenerateDTOs.size());
// 第三步写入到 system 的数据库
errorCodeService.autoGenerateErrorCodes(autoGenerateDTOs);
log.info("[execute][写入到 system 组件完成]");
}
/**
* 解析 errorCodeConstantsClass 变量获得错误码类
*
* @return 错误码类
*/
private Class<?> parseErrorCodeConstantsClass() {
// 校验 errorCodeConstantsClass 参数
if (!StringUtils.hasText(errorCodeConstantsClass)) {
log.info("[execute][未配置 yudao.error-code.constants-class 配置项,不进行自动写入到当前服务中]");
return null;
}
try {
return Class.forName(errorCodeConstantsClass);
} catch (ClassNotFoundException e) {
log.error("[execute][配置的 ({}) 找不到对应的类]", errorCodeConstantsClass);
return null;
}
}
/**
* 解析错误码类获得错误码数组
*
* @return 错误码数组
*/
private List<ErrorCodeAutoGenerateReqDTO> parseErrorCode(Class<?> errorCodeConstantsClazz) {
List<ErrorCodeAutoGenerateReqDTO> autoGenerateDTOs = new ArrayList<>();
Arrays.stream(errorCodeConstantsClazz.getFields()).forEach(field -> {
if (field.getType() != ErrorCode.class) {
return;
}
try {
ErrorCode errorCode = (ErrorCode) field.get(errorCodeConstantsClazz);
autoGenerateDTOs.add(new ErrorCodeAutoGenerateReqDTO().setApplicationName(applicationName)
.setCode(errorCode.getCode()).setMessage(errorCode.getMsg()));
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
});
return autoGenerateDTOs;
}
}

View File

@ -0,0 +1,24 @@
package cn.iocoder.dashboard.framework.errorcode.core.loader;
import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil;
/**
* 错误码加载器
*
* 注意错误码最终加载到 {@link cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil} MESSAGES 变量中
*
* @author dlyan
*/
public interface ErrorCodeLoader {
/**
* 添加错误码
*
* @param code 错误码的编号
* @param msg 错误码的提示
*/
default void putErrorCode(Integer code, String msg) {
ServiceExceptionUtil.put(code, msg);
}
}

View File

@ -0,0 +1,73 @@
package cn.iocoder.dashboard.framework.errorcode.core.loader;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.dashboard.framework.errorcode.core.dto.ErrorCodeRespDTO;
import cn.iocoder.dashboard.framework.errorcode.core.service.ErrorCodeFrameworkService;
import cn.iocoder.dashboard.util.date.DateUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Scheduled;
import java.util.Date;
import java.util.List;
/**
* ErrorCodeLoader 的实现类 system 的数据库中加载错误码
*
* 考虑到错误码会刷新所以按照 {@link #REFRESH_ERROR_CODE_PERIOD} 频率增量加载错误码
*
* @author dlyan
*/
@RequiredArgsConstructor
@Slf4j
public class ErrorCodeLoaderImpl implements ErrorCodeLoader {
/**
* 刷新错误码的频率单位毫秒
*/
private static final int REFRESH_ERROR_CODE_PERIOD = 60 * 1000;
/**
* 应用分组
*/
private final String applicationName;
/**
* 错误码 Service
*/
private final ErrorCodeFrameworkService errorCodeService;
/**
* 缓存错误码的最大更新时间用于后续的增量轮询判断是否有更新
*/
private Date maxUpdateTime;
@EventListener(ApplicationReadyEvent.class)
public void loadErrorCodes() {
this.loadErrorCodes0();
}
@Scheduled(fixedDelay = REFRESH_ERROR_CODE_PERIOD, initialDelay = REFRESH_ERROR_CODE_PERIOD)
public void refreshErrorCodes() {
this.loadErrorCodes0();
}
private void loadErrorCodes0() {
// 加载错误码
List<ErrorCodeRespDTO> errorCodeRespDTOs = errorCodeService.getErrorCodeList(applicationName, maxUpdateTime);
if (CollUtil.isEmpty(errorCodeRespDTOs)) {
return;
}
log.info("[loadErrorCodes0][加载到 ({}) 个错误码]", errorCodeRespDTOs.size());
// 刷新错误码的缓存
errorCodeRespDTOs.forEach(errorCodeRespDTO -> {
// 写入到错误码的缓存
putErrorCode(errorCodeRespDTO.getCode(), errorCodeRespDTO.getMessage());
// 记录下更新时间方便增量更新
maxUpdateTime = DateUtils.max(maxUpdateTime, errorCodeRespDTO.getUpdateTime());
});
}
}

View File

@ -0,0 +1,35 @@
package cn.iocoder.dashboard.framework.errorcode.core.service;
import cn.iocoder.dashboard.framework.errorcode.core.dto.ErrorCodeAutoGenerateReqDTO;
import cn.iocoder.dashboard.framework.errorcode.core.dto.ErrorCodeRespDTO;
import javax.validation.Valid;
import java.util.Date;
import java.util.List;
/**
* 错误码 Framework Service 接口
*
* @author 芋道源码
*/
public interface ErrorCodeFrameworkService {
/**
* 自动创建错误码
*
* @param autoGenerateDTOs 错误码信息
*/
void autoGenerateErrorCodes(@Valid List<ErrorCodeAutoGenerateReqDTO> autoGenerateDTOs);
/**
* 增量获得错误码数组
*
* 如果 minUpdateTime 为空时则获取所有错误码
*
* @param applicationName 应用名
* @param minUpdateTime 最小更新时间
* @return 错误码数组
*/
List<ErrorCodeRespDTO> getErrorCodeList(String applicationName, Date minUpdateTime);
}

View File

@ -2,23 +2,16 @@ package cn.iocoder.dashboard.modules.system.controller.errorcode;
import cn.iocoder.dashboard.common.pojo.CommonResult; import cn.iocoder.dashboard.common.pojo.CommonResult;
import cn.iocoder.dashboard.common.pojo.PageResult; import cn.iocoder.dashboard.common.pojo.PageResult;
import cn.iocoder.dashboard.modules.system.controller.errorcode.dto.ErrorCodeAutoGenerateDTO;
import cn.iocoder.dashboard.modules.system.controller.errorcode.dto.ErrorCodeCreateDTO; import cn.iocoder.dashboard.modules.system.controller.errorcode.dto.ErrorCodeCreateDTO;
import cn.iocoder.dashboard.modules.system.controller.errorcode.dto.ErrorCodePageDTO; import cn.iocoder.dashboard.modules.system.controller.errorcode.dto.ErrorCodePageDTO;
import cn.iocoder.dashboard.modules.system.controller.errorcode.dto.ErrorCodeUpdateDTO; import cn.iocoder.dashboard.modules.system.controller.errorcode.dto.ErrorCodeUpdateDTO;
import cn.iocoder.dashboard.modules.system.controller.errorcode.vo.ErrorCodeVO; import cn.iocoder.dashboard.modules.system.controller.errorcode.vo.ErrorCodeVO;
import cn.iocoder.dashboard.modules.system.service.errorcode.ErrorCodeService; import cn.iocoder.dashboard.modules.system.service.errorcode.impl.ErrorCodeServiceImpl;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotNull;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List; import java.util.List;
import static cn.iocoder.dashboard.common.pojo.CommonResult.success; import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
@ -29,34 +22,7 @@ import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
public class ErrorCodeController { public class ErrorCodeController {
@Resource @Resource
private ErrorCodeService errorCodeService; private ErrorCodeServiceImpl errorCodeService;
/**
* 获得指定分组下的错误码列表
*
* @param group 错误码分组
* @param minUpdateTime 最小更新时间允许为空
* 通过该参数我们可以增量获取超过 minUpdateTime 时间的错误码
* @return 错误码列表
*/
@ApiOperation("获取指定分组下的状态码")
@GetMapping("/list-group")
public CommonResult<List<ErrorCodeVO>> listErrorCodes(@NotNull(message = "错误码分组不能为空") String group, Date minUpdateTime) {
return success(errorCodeService.listErrorCodes(group, minUpdateTime));
}
/**
* 自动生成错误码
*
* @param autoGenerateDTOs 自动生成信息 DTO
*/
@ApiOperation("自动生成错误码")
@PostMapping("/generate")
public CommonResult<Boolean> autoGenerateErrorCodes(@RequestBody List<ErrorCodeAutoGenerateDTO> autoGenerateDTOs) {
errorCodeService.autoGenerateErrorCodes(autoGenerateDTOs);
return success(Boolean.TRUE);
}
/** /**
* 创建错误码 * 创建错误码
@ -130,11 +96,4 @@ public class ErrorCodeController {
return success(errorCodeService.pageErrorCode(pageDTO)); return success(errorCodeService.pageErrorCode(pageDTO));
} }
@InitBinder
protected void init(HttpServletRequest request, ServletRequestDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
}
} }

View File

@ -1,15 +1,11 @@
package cn.iocoder.dashboard.modules.system.controller.errorcode.dto; package cn.iocoder.dashboard.modules.system.controller.errorcode.dto;
import cn.iocoder.dashboard.framework.validator.InEnum;
import cn.iocoder.dashboard.modules.system.enums.errorcode.ErrorCodeTypeEnum;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.io.Serializable;
@ApiModel("错误码更新 DTO") @ApiModel("错误码更新 DTO")
@Data @Data

View File

@ -1,7 +1,8 @@
package cn.iocoder.dashboard.modules.system.convert.errorcode; package cn.iocoder.dashboard.modules.system.convert.errorcode;
import cn.iocoder.dashboard.common.pojo.PageResult; import cn.iocoder.dashboard.common.pojo.PageResult;
import cn.iocoder.dashboard.modules.system.controller.errorcode.dto.ErrorCodeAutoGenerateDTO; import cn.iocoder.dashboard.framework.errorcode.core.dto.ErrorCodeAutoGenerateReqDTO;
import cn.iocoder.dashboard.framework.errorcode.core.dto.ErrorCodeRespDTO;
import cn.iocoder.dashboard.modules.system.controller.errorcode.dto.ErrorCodeCreateDTO; import cn.iocoder.dashboard.modules.system.controller.errorcode.dto.ErrorCodeCreateDTO;
import cn.iocoder.dashboard.modules.system.controller.errorcode.dto.ErrorCodeUpdateDTO; import cn.iocoder.dashboard.modules.system.controller.errorcode.dto.ErrorCodeUpdateDTO;
import cn.iocoder.dashboard.modules.system.controller.errorcode.vo.ErrorCodeVO; import cn.iocoder.dashboard.modules.system.controller.errorcode.vo.ErrorCodeVO;
@ -14,13 +15,10 @@ import org.mapstruct.factory.Mappers;
import java.util.List; import java.util.List;
/**
* @author dylan
*/
@Mapper(unmappedSourcePolicy = ReportingPolicy.IGNORE) @Mapper(unmappedSourcePolicy = ReportingPolicy.IGNORE)
public interface ErrorCodeConvert { public interface SysErrorCodeConvert {
ErrorCodeConvert INSTANCE = Mappers.getMapper(ErrorCodeConvert.class); SysErrorCodeConvert INSTANCE = Mappers.getMapper(SysErrorCodeConvert.class);
ErrorCodeVO convert (ErrorCodeDO bean); ErrorCodeVO convert (ErrorCodeDO bean);
@ -33,7 +31,8 @@ public interface ErrorCodeConvert {
ErrorCodeDO convert (ErrorCodeUpdateDTO bean); ErrorCodeDO convert (ErrorCodeUpdateDTO bean);
ErrorCodeDO convert(ErrorCodeAutoGenerateDTO bean); ErrorCodeDO convert(ErrorCodeAutoGenerateReqDTO bean);
List<ErrorCodeRespDTO> convertList02(List<ErrorCodeDO> list);
} }

View File

@ -1,22 +1,34 @@
package cn.iocoder.dashboard.modules.system.dal.dataobject.errorcode; package cn.iocoder.dashboard.modules.system.dal.dataobject.errorcode;
import cn.iocoder.dashboard.modules.system.enums.errorcode.ErrorCodeTypeEnum; import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.TableField; import cn.iocoder.dashboard.modules.system.enums.errorcode.SysErrorCodeTypeEnum;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors; import lombok.ToString;
@TableName(value = "sys_error_code")
@Data @Data
@TableName(value = "system_error_code") @EqualsAndHashCode(callSuper = true)
@EqualsAndHashCode() @ToString(callSuper = true)
@Accessors(chain = true) public class ErrorCodeDO extends BaseDO {
public class ErrorCodeDO {
/** /**
* 错误码编号 * 错误码编号
*/ */
@TableId
private Integer id; private Integer id;
/**
* 错误码类型
*
* 枚举 {@link SysErrorCodeTypeEnum}
*/
private Integer type;
/**
* 应用名
*/
private String applicationName;
/** /**
* 错误码编码 * 错误码编码
*/ */
@ -25,21 +37,9 @@ public class ErrorCodeDO {
* 错误码错误提示 * 错误码错误提示
*/ */
private String message; private String message;
/**
* 错误码类型
*
* 外键 {@link ErrorCodeTypeEnum}
*/
private Integer type;
/**
* 错误码分组
*
* 一般情况下可以采用应用名
*/
@TableField("`group`") // 避免和数据库关键字冲突
private String group;
/** /**
* 错误码备注 * 错误码备注
*/ */
private String memo; private String memo;
} }

View File

@ -15,6 +15,7 @@ import java.util.List;
@Mapper @Mapper
public interface ErrorCodeMapper extends BaseMapper<ErrorCodeDO> { public interface ErrorCodeMapper extends BaseMapper<ErrorCodeDO> {
default IPage<ErrorCodeDO> selectPage(ErrorCodePageDTO pageDTO) { default IPage<ErrorCodeDO> selectPage(ErrorCodePageDTO pageDTO) {
return selectPage(new Page<>(pageDTO.getPageNo(), pageDTO.getPageSize()), return selectPage(new Page<>(pageDTO.getPageNo(), pageDTO.getPageSize()),
new QueryWrapperX<ErrorCodeDO>().likeIfPresent("`group`", pageDTO.getGroup()) new QueryWrapperX<ErrorCodeDO>().likeIfPresent("`group`", pageDTO.getGroup())
@ -29,8 +30,9 @@ public interface ErrorCodeMapper extends BaseMapper<ErrorCodeDO> {
return selectOne(new QueryWrapper<ErrorCodeDO>().eq("code", code)); return selectOne(new QueryWrapper<ErrorCodeDO>().eq("code", code));
} }
default List<ErrorCodeDO> selectListByGroup(String group, Date minUpdateTime) { default List<ErrorCodeDO> selectListByApplicationNameAndUpdateTimeGt(String applicationName, Date minUpdateTime) {
return selectList(new QueryWrapperX<ErrorCodeDO>().eq("`group`", group) return selectList(new QueryWrapperX<ErrorCodeDO>().eq("application_name", applicationName)
.gtIfPresent("update_time", minUpdateTime)); .gtIfPresent("update_time", minUpdateTime));
} }
} }

View File

@ -1,14 +1,19 @@
package cn.iocoder.dashboard.modules.system.enums.errorcode; package cn.iocoder.dashboard.modules.system.enums.errorcode;
import cn.iocoder.dashboard.common.core.IntArrayValuable; import cn.iocoder.dashboard.common.core.IntArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays; import java.util.Arrays;
/** /**
* 错误码的类型枚举
*
* @author dylan * @author dylan
*/ */
@AllArgsConstructor
public enum ErrorCodeTypeEnum implements IntArrayValuable { @Getter
public enum SysErrorCodeTypeEnum implements IntArrayValuable {
/** /**
* 自动生成 * 自动生成
@ -19,20 +24,16 @@ public enum ErrorCodeTypeEnum implements IntArrayValuable {
*/ */
MANUAL_OPERATION(2); MANUAL_OPERATION(2);
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ErrorCodeTypeEnum::getType).toArray(); public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(SysErrorCodeTypeEnum::getType).toArray();
/**
* 类型
*/
private final Integer type; private final Integer type;
ErrorCodeTypeEnum(Integer type) {
this.type = type;
}
public Integer getType() {
return type;
}
@Override @Override
public int[] array() { public int[] array() {
return ARRAYS; return ARRAYS;
} }
} }

View File

@ -1,80 +0,0 @@
package cn.iocoder.dashboard.modules.system.service.errorcode;
import cn.iocoder.dashboard.common.exception.ErrorCode;
import cn.iocoder.dashboard.common.pojo.CommonResult;
import cn.iocoder.dashboard.framework.errorcode.core.ErrorCodeAutoGenerator;
import cn.iocoder.dashboard.modules.system.controller.errorcode.dto.ErrorCodeAutoGenerateDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@RequiredArgsConstructor
@Slf4j
public class ErrorCodeAutoGeneratorImpl implements ErrorCodeAutoGenerator {
/**
* 应用分组
*/
private final String group;
/**
* 错误码枚举类
*/
private String errorCodeConstantsClass;
@Resource
private ErrorCodeService errorCodeService;
public ErrorCodeAutoGeneratorImpl setErrorCodeConstantsClass(String errorCodeConstantsClass) {
this.errorCodeConstantsClass = errorCodeConstantsClass;
return this;
}
@Override
@EventListener(ApplicationReadyEvent.class)
@Async // 异步保证项目的启动过程毕竟非关键流程
public void execute() {
// 校验 errorCodeConstantsClass 参数
if (!StringUtils.hasText(errorCodeConstantsClass)) {
log.info("[execute][未配置 yudao.error-code.constants-class 配置项,不进行自动写入到当前服务中]");
return;
}
Class errorCodeConstantsClazz;
try {
errorCodeConstantsClazz = Class.forName(errorCodeConstantsClass);
} catch (ClassNotFoundException e) {
log.error("[execute][配置的 ({}) 找不到对应的类]", errorCodeConstantsClass);
return;
}
// 写入 system-service 服务
log.info("[execute][自动将 ({}) 类的错误码,准备写入到当前服务]", errorCodeConstantsClass);
List<ErrorCodeAutoGenerateDTO> autoGenerateDTOs = new ArrayList<>();
Arrays.stream(errorCodeConstantsClazz.getFields()).forEach(field -> {
if (field.getType() != ErrorCode.class) {
return;
}
try {
ErrorCode errorCode = (ErrorCode) field.get(errorCodeConstantsClazz);
autoGenerateDTOs.add(new ErrorCodeAutoGenerateDTO().setGroup(group)
.setCode(errorCode.getCode()).setMessage(errorCode.getMessage()));
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
});
CommonResult<Boolean> autoGenerateErrorCodesResult = errorCodeService.autoGenerateErrorCodes1(autoGenerateDTOs);
if (autoGenerateErrorCodesResult.isSuccess()) {
log.info("[execute][自动将 ({}) 类的错误码,成功写入到当前服务]", errorCodeConstantsClass);
} else {
log.error("[execute][自动将 ({}) 类的错误码,失败写入到当前服务,原因为 ({}/{})]", errorCodeConstantsClass,
autoGenerateErrorCodesResult.getCode(), autoGenerateErrorCodesResult.getMsg());
}
}
}

View File

@ -1,71 +0,0 @@
package cn.iocoder.dashboard.modules.system.service.errorcode;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.dashboard.common.pojo.CommonResult;
import cn.iocoder.dashboard.framework.errorcode.core.ErrorCodeRemoteLoader;
import cn.iocoder.dashboard.modules.system.controller.errorcode.vo.ErrorCodeVO;
import cn.iocoder.dashboard.util.date.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Scheduled;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
@Slf4j
public class ErrorCodeRemoteLoaderImpl implements ErrorCodeRemoteLoader {
private static final int REFRESH_ERROR_CODE_PERIOD = 60 * 1000;
/**
* 应用分组
*/
private final String group;
@Resource
private ErrorCodeService errorCodeService;
private Date maxUpdateTime;
public ErrorCodeRemoteLoaderImpl(String group) {
this.group = group;
}
@Override
@EventListener(ApplicationReadyEvent.class)
public void loadErrorCodes() {
// ErrorCodeRpc 全量加载 ErrorCode 错误码
CommonResult<List<ErrorCodeVO>> listErrorCodesResult = errorCodeService.listErrorCodes1(group, null);
listErrorCodesResult.checkError();
log.info("[loadErrorCodes][从 group({}) 全量加载到 {} 个 ErrorCode 错误码]", group, listErrorCodesResult.getData().size());
// 写入到 ServiceExceptionUtil
listErrorCodesResult.getData().forEach(errorCodeVO -> {
ServiceExceptionUtil.put(errorCodeVO.getCode(), errorCodeVO.getMessage());
// 记录下更新时间方便增量更新
maxUpdateTime = DateUtils.max(maxUpdateTime, errorCodeVO.getUpdateTime());
});
}
@Override
@Scheduled(fixedDelay = REFRESH_ERROR_CODE_PERIOD, initialDelay = REFRESH_ERROR_CODE_PERIOD)
public void refreshErrorCodes() {
// ErrorCodeRpc 增量加载 ErrorCode 错误码
// TODO 优化点假设删除错误码的配置会存在问题
CommonResult<List<ErrorCodeVO>> listErrorCodesResult = errorCodeService.listErrorCodes1(group, maxUpdateTime);
listErrorCodesResult.checkError();
if (CollUtil.isEmpty(listErrorCodesResult.getData())) {
return;
}
log.info("[refreshErrorCodes][从 group({}) 增量加载到 {} 个 ErrorCode 错误码]", group, listErrorCodesResult.getData().size());
// 写入到 ServiceExceptionUtil
listErrorCodesResult.getData().forEach(errorCodeVO -> {
ServiceExceptionUtil.put(errorCodeVO.getCode(), errorCodeVO.getMessage());
// 记录下更新时间方便增量更新
maxUpdateTime = DateUtils.max(maxUpdateTime, errorCodeVO.getUpdateTime());
});
}
}

View File

@ -0,0 +1,12 @@
package cn.iocoder.dashboard.modules.system.service.errorcode;
import cn.iocoder.dashboard.framework.errorcode.core.service.ErrorCodeFrameworkService;
/**
* 错误码 Service 接口
*
* @author 芋道源码
*/
public interface SysErrorCodeService extends ErrorCodeFrameworkService {
}

View File

@ -1,45 +1,45 @@
package cn.iocoder.dashboard.modules.system.service.errorcode; package cn.iocoder.dashboard.modules.system.service.errorcode.impl;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil; import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.dashboard.common.pojo.CommonResult;
import cn.iocoder.dashboard.common.pojo.PageResult; import cn.iocoder.dashboard.common.pojo.PageResult;
import cn.iocoder.dashboard.modules.system.controller.errorcode.dto.ErrorCodeAutoGenerateDTO; import cn.iocoder.dashboard.framework.errorcode.core.dto.ErrorCodeAutoGenerateReqDTO;
import cn.iocoder.dashboard.framework.errorcode.core.dto.ErrorCodeRespDTO;
import cn.iocoder.dashboard.modules.system.controller.errorcode.dto.ErrorCodeCreateDTO; import cn.iocoder.dashboard.modules.system.controller.errorcode.dto.ErrorCodeCreateDTO;
import cn.iocoder.dashboard.modules.system.controller.errorcode.dto.ErrorCodePageDTO; import cn.iocoder.dashboard.modules.system.controller.errorcode.dto.ErrorCodePageDTO;
import cn.iocoder.dashboard.modules.system.controller.errorcode.dto.ErrorCodeUpdateDTO; import cn.iocoder.dashboard.modules.system.controller.errorcode.dto.ErrorCodeUpdateDTO;
import cn.iocoder.dashboard.modules.system.controller.errorcode.vo.ErrorCodeVO; import cn.iocoder.dashboard.modules.system.controller.errorcode.vo.ErrorCodeVO;
import cn.iocoder.dashboard.modules.system.convert.errorcode.ErrorCodeConvert; import cn.iocoder.dashboard.modules.system.convert.errorcode.SysErrorCodeConvert;
import cn.iocoder.dashboard.modules.system.dal.dataobject.errorcode.ErrorCodeDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.errorcode.ErrorCodeDO;
import cn.iocoder.dashboard.modules.system.dal.mysql.errorcode.ErrorCodeMapper; import cn.iocoder.dashboard.modules.system.dal.mysql.errorcode.ErrorCodeMapper;
import cn.iocoder.dashboard.modules.system.enums.errorcode.ErrorCodeTypeEnum; import cn.iocoder.dashboard.modules.system.enums.errorcode.SysErrorCodeTypeEnum;
import cn.iocoder.dashboard.util.collection.CollectionUtils; import cn.iocoder.dashboard.modules.system.service.errorcode.SysErrorCodeService;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.validation.Valid; import javax.annotation.Resource;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.ERROR_CODE_DUPLICATE; import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.ERROR_CODE_DUPLICATE;
import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.ERROR_CODE_NOT_EXISTS; import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.ERROR_CODE_NOT_EXISTS;
import static cn.iocoder.dashboard.common.pojo.CommonResult.success; import static cn.iocoder.dashboard.util.collection.CollectionUtils.convertMap;
import static cn.iocoder.dashboard.util.collection.CollectionUtils.convertSet;
/** /**
* 错误码 Service * 错误码 Service 实现类
*/ */
@Slf4j
@Validated
@Service @Service
public class ErrorCodeService { @Validated
@Slf4j
public class ErrorCodeServiceImpl implements SysErrorCodeService {
@Autowired @Resource
ErrorCodeMapper errorCodeMapper; private ErrorCodeMapper errorCodeMapper;
/** /**
* 创建错误码 * 创建错误码
@ -47,13 +47,13 @@ public class ErrorCodeService {
* @param createDTO 创建错误码 DTO * @param createDTO 创建错误码 DTO
* @return 错误码 * @return 错误码
*/ */
public ErrorCodeVO createErrorCode(@Valid ErrorCodeCreateDTO createDTO) { public ErrorCodeVO createErrorCode(ErrorCodeCreateDTO createDTO) {
checkDuplicateErrorCode(createDTO.getCode(), null); checkDuplicateErrorCode(createDTO.getCode(), null);
// 插入到数据库 // 插入到数据库
ErrorCodeDO errorCodeDO = ErrorCodeConvert.INSTANCE.convert(createDTO); ErrorCodeDO errorCodeDO = SysErrorCodeConvert.INSTANCE.convert(createDTO);
errorCodeMapper.insert(errorCodeDO); errorCodeMapper.insert(errorCodeDO);
// 返回 // 返回
return ErrorCodeConvert.INSTANCE.convert(errorCodeDO); return SysErrorCodeConvert.INSTANCE.convert(errorCodeDO);
} }
/** /**
@ -61,62 +61,17 @@ public class ErrorCodeService {
* *
* @param updateDTO 更新错误码 DTO * @param updateDTO 更新错误码 DTO
*/ */
public void updateErrorCode(@Valid ErrorCodeUpdateDTO updateDTO) { public void updateErrorCode(ErrorCodeUpdateDTO updateDTO) {
checkDuplicateErrorCode(updateDTO.getCode(), updateDTO.getId()); checkDuplicateErrorCode(updateDTO.getCode(), updateDTO.getId());
// 校验更新的错误码是否存在 // 校验更新的错误码是否存在
if (errorCodeMapper.selectById(updateDTO.getId()) == null) { if (errorCodeMapper.selectById(updateDTO.getId()) == null) {
throw ServiceExceptionUtil.exception(ERROR_CODE_NOT_EXISTS); throw ServiceExceptionUtil.exception(ERROR_CODE_NOT_EXISTS);
} }
// 更新到数据库 // 更新到数据库
ErrorCodeDO updateObject = ErrorCodeConvert.INSTANCE.convert(updateDTO); ErrorCodeDO updateObject = SysErrorCodeConvert.INSTANCE.convert(updateDTO);
errorCodeMapper.updateById(updateObject); errorCodeMapper.updateById(updateObject);
} }
@Transactional
public void autoGenerateErrorCodes(@Valid List<ErrorCodeAutoGenerateDTO> autoGenerateDTOs) {
if (CollUtil.isEmpty(autoGenerateDTOs)) {
return;
}
List<ErrorCodeDO> errorCodeDOs = errorCodeMapper.selectListByCodes(
CollectionUtils.convertSet(autoGenerateDTOs, ErrorCodeAutoGenerateDTO::getCode));
Map<Integer, ErrorCodeDO> errorCodeDOMap = CollectionUtils.convertMap(errorCodeDOs, ErrorCodeDO::getCode);
// 遍历 autoGenerateBOs 数组逐个插入或更新考虑到每次量级不大就不走批量了
autoGenerateDTOs.forEach(autoGenerateDTO -> {
ErrorCodeDO errorCodeDO = errorCodeDOMap.get(autoGenerateDTO.getCode());
// 不存在则进行新增
if (errorCodeDO == null) {
errorCodeDO = ErrorCodeConvert.INSTANCE.convert(autoGenerateDTO)
.setType(ErrorCodeTypeEnum.AUTO_GENERATION.getType());
errorCodeMapper.insert(errorCodeDO);
return;
}
// 存在则进行更新更新有三个前置条件
// 条件 1. 只更新自动生成的错误码 Type ErrorCodeTypeEnum.AUTO_GENERATION
if (!ErrorCodeTypeEnum.AUTO_GENERATION.getType().equals(errorCodeDO.getType())) {
return;
}
// 条件 2. 分组 group 必须匹配避免存在错误码冲突的情况
if (!autoGenerateDTO.getGroup().equals(errorCodeDO.getGroup())) {
log.error("[autoGenerateErrorCodes][自动创建({}/{}) 错误码失败,数据库中已经存在({}/{})]",
autoGenerateDTO.getCode(), autoGenerateDTO.getGroup(),
errorCodeDO.getCode(), errorCodeDO.getGroup());
return;
}
// 条件 3. 错误提示语存在差异
if (autoGenerateDTO.getMessage().equals(errorCodeDO.getMessage())) {
return;
}
// 最终匹配进行更新
errorCodeMapper.updateById(new ErrorCodeDO().setId(errorCodeDO.getId()).setMessage(autoGenerateDTO.getMessage()));
});
}
public CommonResult<Boolean> autoGenerateErrorCodes1(@Valid List<ErrorCodeAutoGenerateDTO> autoGenerateDTOs) {
autoGenerateErrorCodes(autoGenerateDTOs);
return success(Boolean.TRUE);
}
/** /**
* 删除错误码 * 删除错误码
* *
@ -139,7 +94,7 @@ public class ErrorCodeService {
*/ */
public ErrorCodeVO getErrorCode(Integer errorCodeId) { public ErrorCodeVO getErrorCode(Integer errorCodeId) {
ErrorCodeDO errorCodeDO = errorCodeMapper.selectById(errorCodeId); ErrorCodeDO errorCodeDO = errorCodeMapper.selectById(errorCodeId);
return ErrorCodeConvert.INSTANCE.convert(errorCodeDO); return SysErrorCodeConvert.INSTANCE.convert(errorCodeDO);
} }
/** /**
@ -150,7 +105,7 @@ public class ErrorCodeService {
*/ */
public List<ErrorCodeVO> listErrorCodes(List<Integer> errorCodeIds) { public List<ErrorCodeVO> listErrorCodes(List<Integer> errorCodeIds) {
List<ErrorCodeDO> errorCodeDOs = errorCodeMapper.selectBatchIds(errorCodeIds); List<ErrorCodeDO> errorCodeDOs = errorCodeMapper.selectBatchIds(errorCodeIds);
return ErrorCodeConvert.INSTANCE.convertList(errorCodeDOs); return SysErrorCodeConvert.INSTANCE.convertList(errorCodeDOs);
} }
/** /**
@ -161,7 +116,7 @@ public class ErrorCodeService {
*/ */
public PageResult<ErrorCodeVO> pageErrorCode(ErrorCodePageDTO pageDTO) { public PageResult<ErrorCodeVO> pageErrorCode(ErrorCodePageDTO pageDTO) {
IPage<ErrorCodeDO> errorCodeDOPage = errorCodeMapper.selectPage(pageDTO); IPage<ErrorCodeDO> errorCodeDOPage = errorCodeMapper.selectPage(pageDTO);
return ErrorCodeConvert.INSTANCE.convertPage(errorCodeDOPage); return SysErrorCodeConvert.INSTANCE.convertPage(errorCodeDOPage);
} }
/** /**
@ -186,14 +141,53 @@ public class ErrorCodeService {
} }
} }
public List<ErrorCodeVO> listErrorCodes(String group, Date minUpdateTime) { @Override
List<ErrorCodeDO> errorCodeDOs = errorCodeMapper.selectListByGroup(group, minUpdateTime); @Transactional
return ErrorCodeConvert.INSTANCE.convertList(errorCodeDOs); public void autoGenerateErrorCodes(List<ErrorCodeAutoGenerateReqDTO> autoGenerateDTOs) {
if (CollUtil.isEmpty(autoGenerateDTOs)) {
return;
}
// 获得错误码
List<ErrorCodeDO> errorCodeDOs = errorCodeMapper.selectListByCodes(
convertSet(autoGenerateDTOs, ErrorCodeAutoGenerateReqDTO::getCode));
Map<Integer, ErrorCodeDO> errorCodeDOMap = convertMap(errorCodeDOs, ErrorCodeDO::getCode);
// 遍历 autoGenerateBOs 数组逐个插入或更新考虑到每次量级不大就不走批量了
autoGenerateDTOs.forEach(autoGenerateDTO -> {
ErrorCodeDO errorCodeDO = errorCodeDOMap.get(autoGenerateDTO.getCode());
// 不存在则进行新增
if (errorCodeDO == null) {
errorCodeDO = SysErrorCodeConvert.INSTANCE.convert(autoGenerateDTO)
.setType(SysErrorCodeTypeEnum.AUTO_GENERATION.getType());
errorCodeMapper.insert(errorCodeDO);
return;
}
// 存在则进行更新更新有三个前置条件
// 条件 1. 只更新自动生成的错误码 Type ErrorCodeTypeEnum.AUTO_GENERATION
if (!SysErrorCodeTypeEnum.AUTO_GENERATION.getType().equals(errorCodeDO.getType())) {
return;
}
// 条件 2. 分组 group 必须匹配避免存在错误码冲突的情况
if (!autoGenerateDTO.getApplicationName().equals(errorCodeDO.getApplicationName())) {
log.error("[autoGenerateErrorCodes][自动创建({}/{}) 错误码失败,数据库中已经存在({}/{})]",
autoGenerateDTO.getCode(), autoGenerateDTO.getApplicationName(),
errorCodeDO.getCode(), errorCodeDO.getApplicationName());
return;
}
// 条件 3. 错误提示语存在差异
if (autoGenerateDTO.getMessage().equals(errorCodeDO.getMessage())) {
return;
}
// 最终匹配进行更新
errorCodeMapper.updateById(new ErrorCodeDO().setId(errorCodeDO.getId()).setMessage(autoGenerateDTO.getMessage()));
});
} }
public CommonResult<List<ErrorCodeVO>> listErrorCodes1(String group, Date minUpdateTime) { @Override
List<ErrorCodeDO> errorCodeDOs = errorCodeMapper.selectListByGroup(group, minUpdateTime); public List<ErrorCodeRespDTO> getErrorCodeList(String applicationName, Date minUpdateTime) {
return success(ErrorCodeConvert.INSTANCE.convertList(errorCodeDOs)); List<ErrorCodeDO> errorCodeDOs = errorCodeMapper.selectListByApplicationNameAndUpdateTimeGt(
applicationName, minUpdateTime);
return SysErrorCodeConvert.INSTANCE.convertList02(errorCodeDOs);
} }
} }