添加异常信息支持

This commit is contained in:
2024-03-21 12:52:32 +08:00
parent b0dfa847d5
commit 1a1a32cb4a
16 changed files with 391 additions and 5 deletions

View File

@@ -57,6 +57,12 @@
<artifactId>reflections</artifactId>
<version>0.10.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-beanutils/commons-beanutils -->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.4</version>
</dependency>
<dependency>

View File

@@ -44,7 +44,9 @@ public class R<T> {
public static <T> R<T> fail(String code, String msg) {
return create(null, code, msg);
}
public static <T> R<T> fail(String code, String msg, T data) {
return create(data, code, msg);
}
public static <T> R<T> create(T data, String code, String msg) {
return new R<>(data, code, msg);

View File

@@ -11,6 +11,8 @@ import cn.lihongjie.coal.empSalaryItem.dto.UpdateEmpSalaryItemDto;
import cn.lihongjie.coal.empSalaryItem.service.EmpSalaryItemService;
import cn.lihongjie.coal.empSalaryItemConfig.service.EmpSalaryItemConfigService;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@@ -34,7 +36,7 @@ public class EmpSalaryItemController {
}
@PostMapping("/update")
public EmpSalaryItemDto update(@RequestBody UpdateEmpSalaryItemDto request) {
public EmpSalaryItemDto update(@Valid @RequestBody UpdateEmpSalaryItemDto request) {
return this.service.update(request);
}

View File

@@ -1,6 +1,8 @@
package cn.lihongjie.coal.empSalaryItem.dto;
import cn.lihongjie.coal.base.dto.OrgCommonDto;
import cn.lihongjie.coal.validator.RequireCode;
import cn.lihongjie.coal.validator.RequireName;
import lombok.Data;
@@ -8,6 +10,8 @@ import org.hibernate.annotations.Comment;
import org.hibernate.annotations.Formula;
@Data
@RequireName
@RequireCode
public class UpdateEmpSalaryItemDto extends OrgCommonDto {

View File

@@ -12,18 +12,28 @@ import cn.lihongjie.coal.errorMsg.entity.ErrorMsgEntity;
import cn.lihongjie.coal.errorMsg.mapper.ErrorMsgMapper;
import cn.lihongjie.coal.errorMsg.repository.ErrorMsgRepository;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.InputStream;
import java.util.List;
@Service
@Slf4j
@Transactional
@@ -82,4 +92,56 @@ public class ErrorMsgService extends BaseService<ErrorMsgEntity, ErrorMsgReposit
return page.map(this.mapper::toDto);
}
@SneakyThrows
public void initDefault(){
ClassPathResource classPathResource = new ClassPathResource("/config/errorMsg.json");
ObjectMapper mapper = new ObjectMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
List<ErrorMsgEntity> errorMsgs;
List<ErrorMsgEntity> exists = findAll();
try (InputStream inputStream = classPathResource.getInputStream()) {
errorMsgs =
mapper.readValue(inputStream, new TypeReference<List<ErrorMsgEntity>>() {});
}
for (ErrorMsgEntity defaultMsg : errorMsgs) {
boolean found = false;
for (ErrorMsgEntity exist : exists) {
if (StringUtils.equalsIgnoreCase(defaultMsg.getCode(), exist.getCode()) ){
found = true;
if (!StringUtils.equals(defaultMsg.getMsg(), exist.getMsg())){
exist.setMsg(defaultMsg.getMsg());
this.repository.save(exist);
}
break;
}
}
if (!found) {
ErrorMsgEntity nd = new ErrorMsgEntity();
nd.setCode(defaultMsg.getCode());
nd.setName(defaultMsg.getName());
nd.setMsg(defaultMsg.getMsg());
this.repository.save(nd);
}
}
}
}

View File

@@ -10,7 +10,6 @@ import cn.lihongjie.coal.organization.dto.UpdateOrganizationDto;
import cn.lihongjie.coal.organization.entity.OrganizationEntity;
import cn.lihongjie.coal.organization.mapper.OrganizationMapper;
import cn.lihongjie.coal.organization.repository.OrganizationRepository;
import cn.lihongjie.coal.salaryItem.service.SalaryItemService;
import cn.lihongjie.coal.user.dto.CreateOrgAdminDto;
import cn.lihongjie.coal.user.service.UserService;
@@ -43,7 +42,6 @@ class OrganizationService extends BaseService<OrganizationEntity, OrganizationRe
@Autowired CoalParameterDefService coalParameterDefService;
@Autowired SalaryItemService salaryItemService;
@PostConstruct
public void init() {}
@@ -60,7 +58,6 @@ class OrganizationService extends BaseService<OrganizationEntity, OrganizationRe
dto.setPassword(request.getOrgAdminPassword());
userService.createOrgAdmin(dto);
coalParameterDefService.initDefault(entity.getId());
salaryItemService.initOrgDefault(entity.getId());
return getById(entity.getId());
}

View File

@@ -2,6 +2,7 @@ package cn.lihongjie.coal.runner;
import cn.lihongjie.coal.coalParameterDef.service.CoalParameterDefService;
import cn.lihongjie.coal.dictionary.service.DictionaryService;
import cn.lihongjie.coal.errorMsg.service.ErrorMsgService;
import cn.lihongjie.coal.organization.entity.OrganizationEntity;
import cn.lihongjie.coal.organization.service.OrganizationService;
import cn.lihongjie.coal.passwordDict.service.PasswordDictService;
@@ -50,6 +51,8 @@ public class InitDataRunner implements CommandLineRunner {
@Autowired PasswordDictService passwordDictService;
@Autowired ErrorMsgService errorMsgService;
@Override
@Transactional
public void run(String... args) throws Exception {
@@ -79,6 +82,7 @@ public class InitDataRunner implements CommandLineRunner {
passwordDictService.initDict();
errorMsgService.initDefault();
} finally {
SecurityContextHolder.clearContext();

View File

@@ -4,19 +4,55 @@ import cn.lihongjie.coal.base.dto.R;
import cn.lihongjie.coal.exception.BizException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.ConstraintViolation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.HandlerMethod;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@RestControllerAdvice
@Slf4j
@Order(1)
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public R handleException(
MethodArgumentNotValidException ex, HttpServletRequest request, HandlerMethod handlerMethod) {
logEx(ex, request, handlerMethod);
List<ConstraintViolation> allError =
ex.getBindingResult().getAllErrors().stream()
.map(oe -> oe.unwrap(ConstraintViolation.class))
.collect(Collectors.toList());
List<Map<String, ? extends Object>> errorData =
allError.stream()
.map(
x ->
Map.of(
"field",
x.getPropertyPath() == null? "null" : x.getPropertyPath().toString(),
"msg",
x.getMessage(),
"annotation",
x.getConstraintDescriptor()
.getAnnotation() == null ? "null":x.getConstraintDescriptor()
.getAnnotation()
.annotationType()
.getName()))
.collect(Collectors.toList());
return R.fail("validError", errorData.stream().map(x -> x.get("msg") + "").collect(Collectors.joining(", ")), errorData);
}
@ExceptionHandler(BizException.class)
public R handleException(
BizException ex, HttpServletRequest request, HandlerMethod handlerMethod) {

View File

@@ -0,0 +1,63 @@
package cn.lihongjie.coal.spring.config;
import cn.lihongjie.coal.errorMsg.service.ErrorMsgService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceResolvable;
import org.springframework.context.NoSuchMessageException;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import java.util.*;
@Component
public class ValidatorConfig {
@Autowired private ErrorMsgService errorMsgService;
public MessageSource messageSource(){
return new MessageSource() {
@Override
public String getMessage(
String code, Object[] args, String defaultMessage, Locale locale) {
String message = errorMsgService.getMsg(code);
return StringUtils.firstNonBlank(message, defaultMessage);
}
@Override
public String getMessage(String code, Object[] args, Locale locale)
throws NoSuchMessageException {
return getMessage(
code, args, getMessage("default.message", args, "", locale), locale);
}
@Override
public String getMessage(MessageSourceResolvable resolvable, Locale locale)
throws NoSuchMessageException {
String[] codes = resolvable.getCodes();
for (String code : codes) {
String message = getMessage(code, resolvable.getArguments(), "", locale);
if (StringUtils.isNotBlank(message)) {
return message;
}
}
return resolvable.getDefaultMessage();
}
};
}
@Bean
public LocalValidatorFactoryBean validator() {
LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
bean.setValidationMessageSource(messageSource());
return bean;
}
}

View File

@@ -0,0 +1,34 @@
package cn.lihongjie.coal.validator;
import static java.lang.annotation.ElementType.*;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.*;
import java.lang.annotation.Documented;
@Target({ TYPE, ANNOTATION_TYPE, TYPE_USE })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = RequireValidator.class)
@Documented
@Repeatable(Require.List.class)
public @interface Require {
String message() default "{require.default}";
String field() ;
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
@Target({ TYPE, ANNOTATION_TYPE, TYPE_USE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface List {
Require[] value();
}
}

View File

@@ -0,0 +1,26 @@
package cn.lihongjie.coal.validator;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import jakarta.validation.*;
import jakarta.validation.constraints.*;
import java.lang.annotation.*;
import java.lang.annotation.Documented;
@NotNull
@Target({ TYPE, ANNOTATION_TYPE, TYPE_USE })
@Require(field = "code")
@Retention(RUNTIME)
@Constraint(validatedBy = { })
@Documented
@ReportAsSingleViolation
public @interface RequireCode {
String message() default "{require.code}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}

View File

@@ -0,0 +1,26 @@
package cn.lihongjie.coal.validator;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import jakarta.validation.*;
import jakarta.validation.constraints.*;
import java.lang.annotation.*;
import java.lang.annotation.Documented;
@NotNull
@Target({ TYPE, ANNOTATION_TYPE, TYPE_USE })
@Require(field = "fileIds")
@Retention(RUNTIME)
@Constraint(validatedBy = { })
@Documented
@ReportAsSingleViolation
public @interface RequireFiles {
String message() default "{require.fileIds}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}

View File

@@ -0,0 +1,27 @@
package cn.lihongjie.coal.validator;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import jakarta.validation.*;
import jakarta.validation.constraints.*;
import java.lang.annotation.*;
import java.lang.annotation.Documented;
import java.util.*;
@NotNull
@Target({ TYPE, ANNOTATION_TYPE, TYPE_USE })
@Require(field = "name")
@Retention(RUNTIME)
@Constraint(validatedBy = { })
@Documented
@ReportAsSingleViolation
public @interface RequireName {
String message() default "{require.name}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}

View File

@@ -0,0 +1,26 @@
package cn.lihongjie.coal.validator;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import jakarta.validation.*;
import jakarta.validation.constraints.*;
import java.lang.annotation.*;
import java.lang.annotation.Documented;
@NotNull
@Target({ TYPE, ANNOTATION_TYPE, TYPE_USE })
@Require(field = "sortKey")
@Retention(RUNTIME)
@Constraint(validatedBy = { })
@Documented
@ReportAsSingleViolation
public @interface RequireSortKey {
String message() default "{require.sortKey}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}

View File

@@ -0,0 +1,45 @@
package cn.lihongjie.coal.validator;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
@Slf4j
public class RequireValidator implements ConstraintValidator<Require, Object> {
private String field;
@Override
public void initialize(Require constraintAnnotation) {
this.field = constraintAnnotation.field();
}
@SneakyThrows
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
try {
Object fv = PropertyUtils.getProperty(value, field);
if (fv instanceof CharSequence s){
return StringUtils.isNotBlank(s);
}
return !ObjectUtils.isEmpty(fv) ;
} catch (Exception e) {
log.error("error", e);
return false;
}
}
}

View File

@@ -0,0 +1,26 @@
[
{
"code": "success",
"msg": "成功"
},
{
"code": "require.default",
"msg": "必填项未填写"
},
{
"code": "require.name",
"msg": "名称必填"
},
{
"code": "require.code",
"msg": "编码必填"
},
{
"code": "require.sortKey",
"msg": "排序字段必填"
},
{
"code": "require.fileIds",
"msg": "必须上传附件"
}
]