背景
公司封裝了自己的基礎核心包core-base,里邊包含了Validation的異常捕獲處理類;同時開發項目有全局異常捕獲處理類,經測試發現,core-base里邊的不起作用
可能原因:
- 未掃描外部依賴包
- 標注@RestControllerAdvice的類,他們會依次加載,遇到異常時,按照類加載順序進行判斷,如果前面的類有能處理這個異常的方法,就給前面的類處理
解決
- 使用@ComponentScan()掃描
- 設置加載優先級,@Order注解標注或實現Ordered接口,重寫getOrder()方法;
@Order(Ordered.HIGHEST_PRECEDENCE) // order如果不標注數字,默認最低優先級,因為其默認值是int最大值
常用Validation異常處理配置
- 多個參數校驗時,默認返回所有的錯誤結果,如果只返回第一個校驗失敗的結果,可通過get(0)獲取第一個,或者通過編寫配置就可以實現
import com.dangbo.entity.ResultDTO;
import com.dangbo.enums.ResultCode;
import java.util.stream.Collectors;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE)
public class ValidationExceptionHandler {
@ExceptionHandler({MethodArgumentNotValidException.class})
public ResultDTO MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
String messages = fieldErrors.stream()
.map(o -> o.getDefaultMessage())
.collect(Collectors.joining(","));
return ResultDTO.error(ResultCode.HTTP_INTERNAL_SERVER_ERROR, messages);
}
@ExceptionHandler({BindException.class})
public ResultDTO BindExceptionHandler(BindException e) {
List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
// 多個參數校驗時,默認返回所有的錯誤結果
String messages = fieldErrors.stream()
.map(o -> o.getDefaultMessage())
.collect(Collectors.joining(","));
return ResultDTO.error(ResultCode.HTTP_INTERNAL_SERVER_ERROR, messages);
}
@ExceptionHandler({ConstraintViolationException.class})
public ResultDTO ConstraintViolationExceptionHandler(ConstraintViolationException e) {
Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
String messages = constraintViolations.stream()
.map(o -> o.getMessage())
.collect(Collectors.joining(","));
return ResultDTO.error(ResultCode.HTTP_INTERNAL_SERVER_ERROR, messages);
}
}
// 通用配置
import org.hibernate.validator.HibernateValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
/**
* validate參數校驗默認的是一個參數校驗失敗后,還會繼續校驗后面的參數
* 通過這個配置改成:校驗參數時只要出現校驗失敗的情況,就立即拋出對應的異常,結束校驗,不再進行后續的校驗
*/
@Configuration
public class ValidationConfig {
@Bean
public Validator validator() {
ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
.configure()
//failFast的意思只要出現校驗失敗的情況,就立即結束校驗,不再進行后續的校驗。
.failFast(true)
.buildValidatorFactory();
return validatorFactory.getValidator();
}
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
MethodValidationPostProcessor methodValidationPostProcessor = new MethodValidationPostProcessor();
methodValidationPostProcessor.setValidator(validator());
return methodValidationPostProcessor;
}
}