大纲:
- 需求
- 实现
- 使用
一、需求
使用spring的controller时候,有很多重复性操作,可以做一个业务轮子统一实现这些功能。
1.打印日志:调用接口所属的类、方法名称、接口入参、出参、异常、接口调用时间等信息,出入参对象需要重写toString方法
2.请求参数校验,无需使用@valid注解,支持分组校验
3.提供系统业务异常处理,其他异常默认响应500,服务器异常。
二、实现
首先定义一个用于方法注解,用于controller的方法上
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface RestRequestHelper { Class[] validGroups() default {}; //参数校验的分组 }
然后定义切面around这个自定义的注解
代码中Result(响应结果)、ResultCodeEnum(响应码、响应码解释)、BaseException(自定义业务异常)都是系统内自己定义的,根据业务需求设计即可。
@Aspect @Component @Slf4j public class RequestHelperAspect { @Autowired private SmartValidator validator; @Around("@annotation(restRequestHelper)") public Object process(ProceedingJoinPoint pjp, RestRequestHelper restRequestHelper) { Class> targetClass = pjp.getTarget().getClass(); String className = targetClass.getSimpleName(); String methodName = pjp.getSignature().getName(); Object[] args = pjp.getArgs(); log.info("processing request:{}.{} begin,params:{}", className, methodName, args); long startTime = System.currentTimeMillis(); Object proceed = null; if ((proceed = validParams(args,restRequestHelper.validGroups())) == null) { try { proceed = pjp.proceed(); } catch (Throwable throwable) { log.error("processing request error:", throwable); if (throwable instanceof BaseException) { BaseException baseException = (BaseException) throwable; proceed = new Result<>(baseException.getErrorCode(), baseException.getMessage()); } else { proceed = new Result<>(ResultCodeEnum.SYSTEM_ERROR.getCode(), ResultCodeEnum.SYSTEM_ERROR.getMsg()); } } } long endTime = System.currentTimeMillis(); //响应参数toString String response = null; if (proceed instanceof Result) { Result result = (Result) proceed; response = result.toJson(); } else { response = proceed.toString(); } log.info("processing request:{}.{} end,params:{},response:{},use:{}ms", className, methodName, args, response, endTime - startTime); return proceed; } /** * 参数校验 * * @param args * @param classes * @return */ private Result validParams(Object[] args, Class[] classes) { Result errorResult = null; for (Object arg : args) { BindingResult bindingResult = new BeanPropertyBindingResult(arg, arg.getClass().getSimpleName()); if(classes.length>0){ validator.validate(arg, bindingResult,classes); }else { validator.validate(arg, bindingResult); } StringBuilder errorMsg = null; MaperrorMap = null; if (bindingResult.hasErrors()) { errorMsg = new StringBuilder(); errorMsg.append(ResultCodeEnum.INVALID_REQUEST.getMsg()); final List fieldErrors = bindingResult.getFieldErrors(); errorMap = new HashMap<>(fieldErrors.size()); for (FieldError fieldError : fieldErrors) { errorMap.put(fieldError.getField(), fieldError.getDefaultMessage()); } errorMsg.append(JSON.toJSON(errorMap)); errorResult = new Result(ResultCodeEnum.INVALID_REQUEST.getCode(), errorMsg.toString()); } } return errorResult; } }
三、使用
使用时候只要在controller中的方法上加上这个注解就可以了
@PostMapping("/create") @RestRequestHelper( validGroups = {XxxForm.Create.class})//validGroups为需要校验的分组,如果不需要分组校验,不写这个参数即可 public Result create(@RequestBody XxxForm form) { //业务处理 }
分组校验不会的参考我另一篇文章:https://www.cnblogs.com/liuboyuan/p/11093383.html