探索讨论java aop、拦截器、注解、反射用于统一通用型业务处理的优略

背景

  • 前期项目业务已上线,需优化。多个地方避免重复提交,并且需要解析返回结果,根据返回结果的成败,补充不同的数据,再响应到前端。
  • 考虑尽量减少或避免改动原代码业务方法,但是也要能避免重复提交。
  • 项目具有restful风格,即同一个uri会有对应多个方法,这些方法对应 http的get/post/delete/update
  • 项目方法返回的结果数据类型不统一

分析

  • 减少或改动源代码业务方法,则需要统一处理,具体方案需要从如下方向考虑: 过滤器/拦截器/注解/AOP
  • 方案需满足如下要求:
    • 1.业务方法前判定(是否需要调用业务),是否直接返回判定结果。
    • 2.业务方法后排定,是否直接返回业务数据。
    • 3.业务方法后排定,需要解析业务返回的数据(数据类型不统一),并根据数据中的某些参数,判定是否需要新建返回数据,并返回数据
  • 方案对比如下:
方案特点适用性
过滤器 filter只满足要求1不适用本场景
拦截器 HandlerInterceptorAdapter只满足要求1、2不适用本场景
拦截器 ResponseBodyAdvice只满足要求3
AOP+注解+反射满足全部要求,终极大招。。采用

要点

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface NoRepeatSubmit {

    int lockTime() default CoreConst.CURRENT_LOCK_BETWEEN;
    boolean  freshLock() default false;
    boolean useLock() default false;

}
    @GetMapping("/api/xmind/list")
    @NoRepeatSubmit(useLock = true)
    @ResponseBody
    public Response list(


    @GetMapping("/api/caserepo/list")
    @NoRepeatSubmit(useLock = true)
    @ResponseBody
    public ResultVO caseRepoList(

@Aspect
@Component
@Slf4j
public class NoRepeatSubmitAfterAop {

    @Autowired
    private ISysBufferLockService sysBufferLockService;


    @Autowired
    private ResultComponentUtil resultComponentUtil;

    @Pointcut("@annotation(com.mi.info.mitest.casemanage.web.aop.NoRepeatSubmit)")
    public void pointCut(){}

    @After("pointCut()")
    public void doAfter(JoinPoint joinPoint){

        Object[] arrs = joinPoint.getArgs();
        String methodName = joinPoint.getSignature().getName();
        Class className = joinPoint.getSignature().getDeclaringType();

        log.info("noRepeatSubmit doAfter--methodName:{}",methodName);
    }

//    @After("pointcut()")
//    public void after(JoinPoint jp) {
//        MethodSignature signature = (MethodSignature) jp.getSignature();
//        Method method = signature.getMethod();
//        Annotation[] annotations = method.getAnnotations();
//        Arrays.stream(annotations).forEach(annotation -> {
//            Class annotationType = annotation.annotationType();
//            if (annotationType == CasemanageReadDB.class) {
//                DataSourceContextHolder.clearCasemanageDatasourceType();
//            }
//        });
//    }

//    @Before("pointCut()")
    public void doBefore(JoinPoint joinPoint){

        Object[] arrs = joinPoint.getArgs();
        String methodName = joinPoint.getSignature().getName();
        Class className = joinPoint.getSignature().getDeclaringType();
        log.info("before--methodName:{}",methodName);

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();

        String userId = UserInfoUtil.getUserId();
        long nowTime = System.currentTimeMillis();

//        SysBufferLock sysBufferLock = sysBufferLockService.getById(userId);

    }


//    @After("pointCut()")
//    @Around("pointCut()")
//    @Around("execution(* com.ifueen.controller.*.*(..)) && @annotation(noRepeatSubmit)")
    @Around("@annotation(noRepeatSubmit)")
    public Object around(ProceedingJoinPoint joinPoint, NoRepeatSubmit noRepeatSubmit) throws Throwable {

//        Object[] arrs = joinPoint.getArgs();
//        Signature signature = joinPoint.getSignature();
//
//        String methodName = joinPoint.getSignature().getName();
//        Class className = joinPoint.getSignature().getDeclaringType();
//        Method[] methods = className.getMethods();
//        log.info("noRepeatSubmit around--methodName:{}",methodName);


        Object result =null;

        if(noRepeatSubmit.freshLock()){
            sysBufferLockService.freshLock();

        }else if(noRepeatSubmit.useLock()){

             ErrorCodeEnum errorCodeEnum = sysBufferLockService.passLock();
             if(errorCodeEnum.equalsByCode(ErrorCodeEnum.SUCCESS)){

                 result = joinPoint.proceed();

                 Integer code = -1;
                 if(result instanceof Response) {
                     code = ((Response) result).getCode();

                 }else if(result instanceof ResultVO ) {
                     code = ((ResultVO) result).getCode();
                 }

                 sysBufferLockService.dealLock(ErrorCodeEnum.SUCCESS.getCode().equals(code));

             }else {

                 //方法返回值类型
                 Method method = ((MethodSignature)joinPoint.getSignature()).getMethod();
                 Class returnType = method.getReturnType();

                 if(returnType.isAssignableFrom(Response.class)){
                     return ResponseBuilder.create().error(errorCodeEnum.getCode(),errorCodeEnum.getMsg(),null).build();

                 }else if(returnType.isAssignableFrom(ResultVO.class)){
                     return resultComponentUtil.error(errorCodeEnum.getCode(),errorCodeEnum.getMsg());
                 }
             }
        }
        return result==null? joinPoint.proceed():result;
    }
}

失败案例

@Slf4j
@ControllerAdvice
public class NoRepeatSubmitAfterInterceptor implements ResponseBodyAdvice<Object> {

   
   @Override
   public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
      return true;
   }

   @Override
   public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {

      System.out.println("TestResponseBodyAdvice==>beforeBodyWrite:" + o.toString() + ","
              + methodParameter);
      return o;
   }
}
@Slf4j
@WebInterceptor(order = Const.InterceptorOrder.AVOID_SUMBIY_AGAIN_ORDER,
   includePatterns = {
        "/api/**",
   })
public class NoRepeatSubmitBeforeInterceptor extends HandlerInterceptorAdapter {

   @Autowired
   private ISysBufferLockService sysBufferLockService;

   ObjectMapper objectMapper = new ObjectMapper();

   /**
    * 在请求处理之前进行调用(Controller方法调用之前)
    */
   @Override
   public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

      NoRepeatSubmit noRepeatSubmit=getAnno(handler,NoRepeatSubmit.class);

      if (noRepeatSubmit != null ) {

         boolean freshLock = noRepeatSubmit.freshLock();
         boolean useLock = noRepeatSubmit.useLock();

         if(freshLock){
            sysBufferLockService.freshLock();
         }else if(useLock){
//            if(!sysBufferLockService.passLock()){
//               return respFail(response,SUMMBIT_HAVING_DONE);
//            }
         }
      }

      return true;
   }


   @Override
   public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

      NoRepeatSubmit noRepeatSubmit=getAnno(handler,NoRepeatSubmit.class);

      if (noRepeatSubmit != null ) {
         boolean useLock = noRepeatSubmit.useLock();
         if(useLock){

            boolean succ=false;

            Object result = request.getAttribute("response");


//            if(true){
//               succ=true;
//            }
            sysBufferLockService.dealLock(succ);
         }
      }
      super.postHandle(request, response, handler, modelAndView);
   }

   @Override
   public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

      NoRepeatSubmit noRepeatSubmit=getAnno(handler,NoRepeatSubmit.class);

      if (noRepeatSubmit != null ) {
         boolean useLock = noRepeatSubmit.useLock();
         if(useLock){

            boolean succ=false;

            Map<String, String[]> parameterMap = request.getParameterMap();

            Object result = request.getAttribute("response");

            PrintWriter writer = response.getWriter();

            String s = response.getWriter().toString();
            response.getWriter().println();

//            if(true){
//               succ=true;
//            }
            sysBufferLockService.dealLock(succ);
         }
      }

      super.afterCompletion(request, response, handler, ex);
   }

   /** 返回失败结果Json数据 */
   private boolean respFail(HttpServletResponse response, ErrorCodeEnum errorCodeEnum) throws IOException {
      Map<String, Object> map = new HashMap<>();
      map.put("code", errorCodeEnum.getCode());
      map.put("msg", errorCodeEnum.getMsg());
      map.put("data", null);
      String s = objectMapper.writeValueAsString(map);

      response.setCharacterEncoding("UTF-8");
      response.setContentType("application/json; charset=utf-8");
      response.getWriter().write(s);

      return false;
   }

   private <T extends Annotation> T getAnno(Object handler,Class<T> annotationClass){
      if (handler instanceof HandlerMethod) {
         HandlerMethod handlerMethod = (HandlerMethod) handler;
         Method method = handlerMethod.getMethod();
         return method.getAnnotation(annotationClass);
      }
      return null;
   }

相关方案

相关资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值