java实现自定义包装注解

导读:本篇文章讲解 java实现自定义包装注解,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

java实现自定义包装注解的方式不少,可以采用aop方式,还可以单纯采用拦截器配合ResponseBodyAdvice(响应结果处理)方式。这篇文章我用到的是第二种。

1. 自定义一个注解

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
public @interface ResponseResult {

}

作用:自定义的包装注解,可在controller类/具体接口方法上添加,最后实现效果就是检测到有这个注解标记的话,可对范围内的接口返回值进行统一格式包装。

2. 定义一个拦截器处理@ResponseResult注解

@Component
@Slf4j
public class ResponseResultInterceptor implements HandlerInterceptor {
  /**
 1. 标记名称
   */
  public static final String RESPONSE_RESULT_ANN="RESPONSE-RESULT-ANN";

  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
      throws Exception {
    //请求的方法
    if(handler instanceof HandlerMethod) {
      final HandlerMethod handlerMethod= (HandlerMethod) handler;
      final Class<?> clazz=handlerMethod.getBeanType();
      final Method method=handlerMethod.getMethod();
      log.info("拦截该请求接口,判断方法或该方法所在的类上是否有统一包装的注解@ResponseResult:{}->{}",clazz.getSimpleName(),method.getName());
      //判断是否在类对象上面加了注解
      if (clazz.isAnnotationPresent(ResponseResult.class)){
        //设置此请求返回体,需要包装,往下传递,在ResponseAdvice接口进行判断
        request.setAttribute(RESPONSE_RESULT_ANN,clazz.getAnnotation(ResponseResult.class));
        //方法体上是否有注解
      }else if (method.isAnnotationPresent(ResponseResult.class)){
        //设置此请求返回体,需要包装,往下传递,在ResponseAdvice接口进行判断
        request.setAttribute(RESPONSE_RESULT_ANN,method.getAnnotation(ResponseResult.class));
      }
    }
    return true;
  }
}

注:HandlerInterceptor接口是必须要实现的,是spring web中的拦截器接口。而提到的ResponseAdvice接口是在下一步完成。

3. 注册自定义的拦截器
拦截器要想生效需要被注册。

@Configuration
public class WebAppConfigurer implements WebMvcConfigurer {

  @Autowired
  private ResponseResultInterceptor responseResultInterceptor;

  /**
 1. 注册拦截器
   */
  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    //  针对@ResponseResult注解的拦截器
    registry.addInterceptor(responseResultInterceptor).addPathPatterns("/**");
    //  - /**: 匹配所有路径
    //  - /com/**:匹配 /com/ 下的所有路径
    //  - /com/*:只匹配 /com/luopan,不匹配 /com/luopan/guides ("/*"只匹配一级子目录,"/**"匹配所有子目录)
  }
}

responseResultInterceptor就是我们上一步自定义的拦截器。

4.实现对请求响应后的结果的处理

@Slf4j
@RestControllerAdvice(basePackages = "com.luopan.guides.web.controller")
public class ResponseAdvice implements ResponseBodyAdvice<Object> {

  /**
   * 标记名称
   */
  public static final String RESPONSE_RESULT_ANN = "RESPONSE-RESULT-ANN";

  @Autowired
  private ObjectMapper objectMapper;


  /**
   * 请求是否包含了 包装注解 标记,没有就直接返回,不需要重写返回体
   */
  @Override
  public boolean supports(MethodParameter returnType,
      Class<? extends HttpMessageConverter<?>> converterType) {
    ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder
        .getRequestAttributes();
    assert sra != null;
    HttpServletRequest request = sra.getRequest();
    //判断请求 是否有包装标记
    ResponseResult responseResultAnn = (ResponseResult) request.getAttribute(RESPONSE_RESULT_ANN);
    return responseResultAnn != null;
  }

  @SneakyThrows
  @Override
  public Object beforeBodyWrite(Object body, MethodParameter returnType,
      MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType,
      ServerHttpRequest request, ServerHttpResponse response) {
    if (body instanceof String) {
      return objectMapper.writeValueAsString(Result.ok(body));
    }
    log.info("有包装注解,拦截返回接口数据成功,封装成统一返回格式");
    return Result.ok(body);
  }


}

注:
1.@RestControllerAdvice是需要处理的范围,一般指定controller层
2.自定义的包装注解是否存在的判断是通过定义的标记名称来实现
3.这个类要想生效,需要在controller层中调用方法上加入@RequstMapping和@ResponseBody
4.文中的Result.ok()是我自定义的返回格式,可根据需求自行定义。
5.加上

    if (body instanceof String) {
      return objectMapper.writeValueAsString(Result.ok(body));
    }

的目的是因为可能对返回类型是String的话可能无法识别解析。

最终效果:
在这里插入图片描述
只要加了该注解,就会对接口的返回类型进行统一包装,不用重复劳动,写上类似return Result.ok(JsonUtil.json2Map(response));
这种代码。
后续也可在此基础上实现同一异常处理。

ps:因为目前所在公司属于个人任务时间充裕那种,所以我不用像之前那样已赶紧做出来为主,更多的思考,优化,造轮子才是有成就感。希望看到的朋友一起共进步,讨论。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/92309.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!