Spring framework架構為我們提供了很多有用的工具,比如Validation類用于處于HTTP請求的參數校驗。
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
我們可以在Controller層擷取Error來判斷是否校驗失敗,但是這樣每一個Controller層的方法都有重複的代碼,我們可以實作統一的切面Aspect去為所有的方法都添加 校驗邏輯。
@Aspect是Spring面向切面程式設計最重要的注解~可以實作在方法執行的時候添加額外的行為,
包括方法執行前Before、方法執行後After、方法抛出異常Exception、方法環繞Around等等時機。
import com.nova.felixchat.infrastructure.commons.BusinessException;
import com.nova.felixchat.infrastructure.commons.enums.BizErrorCode;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import java.util.List;
/**
* @author linzihao
*/
@Slf4j
@Aspect
@Component
public class ParamValidateAspect {
@Pointcut("execution(* com.nova.felixchat..*(..))")
public void aspect() {
}
/*
* 配置前置通知,使用在方法aspect()上注冊的切入點
* 同時接受JoinPoint切入點對象,可以沒有該參數
*/
@Before("aspect()")
public void before(JoinPoint joinPoint) {
Object[] params = joinPoint.getArgs();
for (Object param : params) {
if (param instanceof Errors) {
Errors errors = (Errors) param;
if (errors.hasErrors()) {
List<ObjectError> errorList = errors.getAllErrors();
StringBuilder sb = new StringBuilder();
FieldError fieldError = (FieldError) errorList.get(0);
sb.append(fieldError.getDefaultMessage());
log.warn("======參數校驗異常======" + sb.toString().trim());
throw new BusinessException(BizErrorCode.REQUEST_PARAM_ILLEGAL);
}
}
}
}
}
當然,我們完全可以使用@ControllerAdvice或者@RestControllerAdvice來實作統一參數校驗。
import com.ligeit.supply.rules.infrastructure.commons.BizErrorCode;
import com.ligeit.supply.rules.infrastructure.commons.BusinessException;
import com.ligeit.supply.rules.infrastructure.commons.ResultData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
import java.io.IOException;
import java.util.Comparator;
import java.util.stream.Collectors;
/**
* 統一異常處理類
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 參數驗證統一處理
* @param e
* @return
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
BindingResult bindingResult = e.getBindingResult();
String msg = bindingResult.getFieldErrors().stream().sorted(Comparator.comparing(FieldError::getField))
.map(e1 -> e1.getDefaultMessage()).collect(Collectors.joining(","));
log.error("參數驗證失敗: {},", e.getMessage());
return ResultData.builder().code(BizErrorCode.REQUEST_PARAM_INVALID.getCode()).msg(msg).build();
}
//......其他異常處理邏輯
}