why:
Зачем использовать aop для реализации проверки?
answer:
Механизм проверки Spring mvc по умолчанию @Valid + BindingResult, Но эта реализация по умолчанию должна получить BindingResult в методе контроллера для проверки.
eg:if (result.hasErrors()) { List<ObjectError> allErrors = result.getAllErrors(); List<String> errorlists = new ArrayList<>(); for (ObjectError objectError : allErrors) { errorlists.add(objectError.getDefaultMessage()); } }
Получить списки ошибок. Таким образом, каждый метод, который необходимо проверить, должен вызываться неоднократно, даже если он инкапсулирован.
Возможно, приведенное выше не может указывать на реализацию Spring @Valid + BindingResult, позвольте мне сначала дать «каштан».
1. Каштан (старая версия)
1.1 Уровень интерфейса (IDAL)
например: простой запрос POST, @RequestBody получает данные запроса, @Valid + BindingResult для проверки
- httpMethid: POST
- параметры: @RequestBody получает данные запроса
- действительный: @Valid + BindingResult
@ResponseBody
@PostMapping("body")
public ResponseVO bodyPost(@RequestBody @Valid TestVO body,BindingResult result){
//校验到错误
if (result.hasErrors()) {
List<ObjectError> allErrors = result.getAllErrors();
List<String> lists = new ArrayList<>();
for (ObjectError objectError : allErrors) {
lists.add(objectError.getDefaultMessage());
}
return new ResponseVO(HttpStatus.BAD_REQUEST.value(), "parameter empty", lists);
}
return new ResponseVO(HttpStatus.OK.value(), "bodyPost", null);
}
1.2 Контент проверки Entity (vo)
Существует множество аннотаций проверки @Valid + BindingResult, которые доступны в Интернете!
public class TestVO {
@Getter
@Setter
@Min(value = 0,message = "请求参数isString不能小于0")
private Integer isInt;
@Getter
@Setter
@NotBlank(message = "请求参数isString不能为空")
private String isString;
}
1.3 Тестирование результатов
2. проверка aop (версия обновления)
Видно, что если необходимо проверить несколько тел, таких как bodyPost, то есть фрагмент кода, который необходимо воспроизводить непрерывно, даже если он изменен на повторно используемый метод родительского класса, его необходимо вызвать. Поэтому, подумав об этом, он все еще кажется неэлегантным. Так что есть аоп для проверки лица.
2.1 Уровень интерфейса (IDAL)
Да! Вы правильно прочитали, приведенный выше код исчез, и нет необходимости вызывать общий метод родительского класса. Всего одна аннотация, и все готово: @ParamValid
@ParamValid
@ResponseBody
@PostMapping("body")
public ResponseVO bodyPost(@RequestBody @Valid TestVO body,BindingResult result){
return new ResponseVO("bodyPost", null);
}
2.2 Пользовательские аннотации
Эта аннотация также является простой аннотацией для методов.
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ParamValid {}
2.3 Важно! Реализация аспекта (Аспект)
Детали раздела:
- @Before: используйте метод аннотации @annotation(XX), этот метод будет вызываться всякий раз, когда используется требуемая аннотация (@ParamValid).
- JoinPoint: получить параметры метода через JoinPoint, чтобы получить содержимое, проверенное BindingResult.
- Пакет проверки переноса: перенос исходного пакета проверки в Aspect: validRequestParams
- Результат проверки ответа:
- Получить ответ через RequestContextHolder
- Получить ответ OutputStream
- Обернуть BindingResult в ответ
@Aspect
@Component
public class ParamValidAspect {
private static final Logger log = LoggerFactory.getLogger(ParamValidAspect.class);
@Before("@annotation(paramValid)")
public void paramValid(JoinPoint point, ParamValid paramValid) {
Object[] paramObj = point.getArgs();
if (paramObj.length > 0) {
if (paramObj[1] instanceof BindingResult) {
BindingResult result = (BindingResult) paramObj[1];
ResponseVO errorMap = this.validRequestParams(result);
if (errorMap != null) {
ServletRequestAttributes res = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletResponse response = res.getResponse();
response.setCharacterEncoding("UTF-8");
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
response.setStatus(HttpStatus.BAD_REQUEST.value());
OutputStream output = null;
try {
output = response.getOutputStream();
errorMap.setCode(null);
String error = new Gson().toJson(errorMap);
log.info("aop 检测到参数不规范" + error);
output.write(error.getBytes("UTF-8"));
} catch (IOException e) {
log.error(e.getMessage());
} finally {
try {
if (output != null) {
output.close();
}
} catch (IOException e) {
log.error(e.getMessage());
}
}
}
}
}
}
/**
* 校验
*/
private ResponseVO validRequestParams(BindingResult result) {
if (result.hasErrors()) {
List<ObjectError> allErrors = result.getAllErrors();
List<String> lists = new ArrayList<>();
for (ObjectError objectError : allErrors) {
lists.add(objectError.getDefaultMessage());
}
return new ResponseVO(HttpStatus.BAD_REQUEST.value(), "parameter empty", lists);
}
return null;
}
}
2.4 Результаты испытаний
Глядя на два приведенных выше результата, вы можете сравнить преимущества использования Spring AOP с @Valid + BindingResult для проверки:
- Удалить избыточность кода
- Асинхронная обработка АОП
- Оптимизация реализации кода