公司最分了个需求要优化代码
以前的代码
@RequestMapping(value = "/list", method = RequestMethod.POST) public @ResponseBody ApiResponse listDevice(@Validated @RequestBody ReqDeviceSearchItem reqDeviceSearchItem,
BindingResult bindingResult) { ApiResponse apiResponse = validate(bindingResult); if (apiResponse.hasError()) { return apiResponse; } try { ArrayList<ResDeviceInfo> list = deviceService.listOfChooseInfo(reqDeviceSearchItem); ImmutableMap immutableMap = ImmutableMap.of("list", list); return ApiResponse.successOf(immutableMap); } catch (BusinessException e) { log.info("error"); return ApiResponse.immediateOf(e.getErrCode(), e.getMessage()); } catch (Exception e) { log.error(""); return ApiResponse.FAIL; } }
这是controller层的代码这样的controller有几百个,重复的代码太多了
于是我就利用AOP加注解的形式来完成了这次的优化
优化后的代码
@RequestMapping(value = "/alltype/list", method = RequestMethod.POST) @ResponseBody @ControllerAround public ApiResponse findTypeList(@Validated @RequestBody ReqDeviceSearchItem reqDeviceSearchItem,
BindingResult bindingResult) throws Exception{ DeviceStatusList deviceStatusList = deviceService.findListType(reqDeviceSearchItem); ImmutableMap immutableMap = ImmutableMap.of("deviceStatusList", deviceStatusList); return ApiResponse.successOf(immutableMap); }
可以对比前后的代码加了一个注解@ControllerAround并抛了一个异常就剩了那么多的代码.
以下是我优化Controller的具体步骤
第一步要定义一个注解
@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface ControllerAround { }@Target使用来表示 注解的位置METHOD表示的是在方法上还有其他的一些类型在这里就不一一介绍了,你打开ctrl+右键点击进去里面有具体的描述
@Retention使用来表示注解在什么时候有用
@Documented将此注解包含在 javadoc 中
那么注解的作用是什么的请看第二部就知道了
第二部核心部分
@Aspect @Component @Slf4j public class ControllerAroundAspect { @Pointcut("@annotation(com.hangtuo.service.annotation.ControllerAround)") public void setJoinPoint() { } @Around(value = "setJoinPoint()") public Object aroundMethod(ProceedingJoinPoint joinPoint) { Object result = null; log.debug("ControllerAOP start..."); //todo 需要判断 方法的修饰符 判断有特定注解的方法不执行代理 直接执行 修改此处为责任链模式方便以后添加其他代理的处理方式
Signature signature = joinPoint.getSignature(); MethodSignature methodSignature = (MethodSignature)signature; Method targetMethod = methodSignature.getMethod(); try { Method realMethod = joinPoint.getTarget().getClass().getDeclaredMethod(signature.getName(), targetMethod.getParameterTypes()); int modifiers = realMethod.getModifiers(); //判断方法的类型 // Modifier.isPublic(modifiers); } catch (NoSuchMethodException e) { e.printStackTrace(); } //获得形式参数 Object[] args = joinPoint.getArgs(); // public ApiResponse changeDevicesStatus(DisableInfo disableInfo, BindingResult) BindingResult bindingResult = null; if (args != null) { for (Object obj : args) { if (obj instanceof BindingResult) { bindingResult = (BindingResult) obj; break; } } } //相当于 ApiResponse apiResponse = validate(bindingResult); if (bindingResult != null) { ApiResponse apiResponse = validate(bindingResult); //验证失败 直接返回 if (null != apiResponse) { return apiResponse; } try { result = joinPoint.proceed(); } catch (Throwable throwable) { throwable.printStackTrace(); if (throwable instanceof BusinessException) { BusinessException e = (BusinessException) throwable; log.error("ControllerAroundAspect error:{}", e.getMessage()); result = ApiResponse.failOf(e.getErrCode(), e.getMessage()); } else if (throwable instanceof Exception) { Exception e = (Exception) throwable; log.error("ControllerAroundAspect error:{}", e.getMessage()); result = ApiResponse.failOf(ReturnCode.CODE_FAIL, e.getMessage()); } else { log.error("ControllerAroundAspect error:{}", throwable.getMessage()); result = ApiResponse.failOf(ReturnCode.CODE_FAIL, throwable.getMessage()); } } } log.debug("ControllerAOP end..."); return result; } private ApiResponse validate(BindingResult bindingResult) { ApiResponse apiResponse = null; if (bindingResult.hasErrors()) { List<FieldError> list = bindingResult.getFieldErrors(); if (CollectionUtil.isNotEmpty(list)) { apiResponse = ApiResponse.immediateOf(ReturnCode.CODE_FAIL, list.get(0).getDefaultMessage(), null); } else { apiResponse = ApiResponse.immediateOf(ReturnCode.CODE_FAIL, "invalid request parameter"); } } return apiResponse; } }
定义了一个类利用spring的注解@Aspect和@Component
在类中定义两个方法
@Pointcut("@annotation(com.hangtuo.service.annotation.ControllerAround)") public void setJoinPoint() { }这个方法使用来声明切点的.在@Pointcut中参数就是切点的位置,在这里注解的作用就体现出来了,只要加了注解就可以AOP拦截了.这就是注解的作用
下面的方法就是使用AOP的环绕通知来实现的.使用@Around就可以完成.
具体逻辑就不在这里细说了说一下重要的几个方法
方法一
Object[] args = joinPoint.getArgs();这个方法使用来获取方法中的形式参数,具体的如何去判断参数类型,可以用下面这个JDK提供的instanceof方法.
if (obj instanceof BindingResult) {方法二
result = joinPoint.proceed();这个方法是核心的方法也就是要执行你写的哪些具体的业务逻辑.在执行这个方法的时候或抛一个Throwable还是利用instanceof方法来判断异常的类型从而来添加日志.到这里这个的注解已经就可以使用了.
使用这种思想还可以完成很多的工作例如在维护过程中要添加缓存就可以去使用这种方法.