在上一家公司中我经常看到接口中返回的直接是一个对象集。然而在响应后却又封装了{msg:”,state:”,obj:”},这些参数我就很纳闷这个是如何实现的。我第一反应就是使用了AOP。但是找了许久并未发现哪里使用了AOP的形式。经过层层的深入我发现了一个接口和一个注解,才慢慢的打开迷层。
ResponseBodyAdvice
ResponseBodyAdvice 这个接口一看就是通过增强器进行织入的,我们从Advice就可以看出。这个需要配合@ControllerAdvice或者@RestControllerAdvice
ResponseBodyAdvice接口是spring4.1的特性,其作用是在响应体写出前做一些处理,比如修改返回值,加密等。允许在执行@ResponseBody或ResponseEntity控制器方法之后但在使用HttpMessageConverter编写正文之前自定义响应。可以直接在RequestMappingHandlerAdapter和ExceptionHandlerExceptionResolver注册实现,或者更有可能在@ControllerAdvice中注解,在这种情况下,它们都会被两者自动检测到。
下面我们来看下这个接口的定义
public interface ResponseBodyAdvice<T> { / * 此组件是否支持给定的控制器方法返回类型和所选的HttpMessageConverter类型。 * 这个方法返回true后才会执行下面的beforeBodyWrite方法 */ boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType); / * 在选择HttpMessageConverter之后且在调用其write方法之前调用 */ @Nullable T beforeBodyWrite(@Nullable T body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response); }
接口的使用我们直接在Controller进行增强,这里我们增强的是RestController看代码
@RestControllerAdvice(basePackages = "com.kaysanshi") public class ResponseControllerAdvice implements ResponseBodyAdvice<Object> { @Override public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) { // 获取当前controller请求的方法是否有SkipR注解 SkipR skipR = returnType.getMethod().getAnnotation(SkipR.class); if(null != skipR) return false; // 是否是返回的R对象 return !returnType.getMethod().getReturnType().equals(R.class); } @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { // 这个地方是自己判断的其他的直接返回当前对象,不进行包装 if(request.getHeaders().containsKey(SecurityConstants.INNER) && SecurityConstants.INNER_TRUE.equalsIgnoreCase(request.getHeaders().getFirst(SecurityConstants.INNER))) { return body; } if (returnType.getGenericParameterType().equals(String.class)) { return JSON.toJSONString(new R<>(body)); } return new R<>(body); } }
在这个beforeBodyWrite的方法中我们可以实现自己的想要的内容,这里有我们通过inner注解进行过滤了fegin中返回的封装,直接将响应返回到上游。当不是标示inner的调用,我们将其封装到返回实体的对象中。
在看这个接口我发现FastJson也是通过对这个接口的实现,封装了一下将对象转为Json的使用。而我们不使用Rest处理的时候,就是
FastJsonViewResponseBodyAdvice 实现了对ResponseBodyAdvice的接口的实现
对应的返回实体R对象的封装如下
@Builder @Accessors(chain = true) @AllArgsConstructor @NoArgsConstructor @Data public class R<T> implements Serializable { private static final long serialVersionUID = -L; private String state; private String msg; private T obj; public R(T obj){ super(); this.state = CommonConstants.SUCCESS; this.obj = obj; } public R(FirstException e) { super(); this.state = e.getCode(); this.msg = e.getMessage(); } public R(FirstArgsException e) { super(); this.state = e.getCode(); this.msg = e.getMessage(); } public R(LogicException e) { super(); this.state = e.getCode(); this.msg = e.getMessage(); } public R(LogicArgsException e) { super(); this.state = e.getCode(); this.msg = e.getMessage(); } public R(AccessDeniedException e) { super(); this.state = SecurityConstants.ACCESS_DENIED; this.msg = e.getMessage(); } public R(NotBreakerException e) { super(); this.state = e.getCode(); this.msg = e.getMessage(); } public R(Throwable e) { super(); if(InfoUtils.isContain(e.getMessage())) { this.state = e.getMessage(); this.msg = InfoUtils.getInfo(this.state); } else { this.state = CommonConstants.FAIL; this.msg = InfoUtils.getInfo(FirstException.ERROR_CODE); } } public R<T> success(T obj){ this.state = CommonConstants.SUCCESS; this.obj = obj; return this; } public R<T> error(String msg){ this.state = CommonConstants.FAIL; this.msg = msg; return this; } public R<T> error(){ this.state = CommonConstants.FAIL; this.msg = InfoUtils.getInfo(FirstException.ERROR_CODE); return this; } @JSONField(serialize = false) @JsonIgnore public Boolean getIsSuccess() { return Objects.equal(CommonConstants.SUCCESS, this.state); } public String toJson() { return JSON.toJSONString(this); } }
经过以上的方式我们就可以做成一个全局的统一响应的封装。
ControllerAdvice
这样我们已经知道ControllerAdvice的一个应用场景,是结合ResponseBodyAdvice进行使用的,同样我们也可以将ControllerAdvice的应用到其他场景。比如:统一异常处理,全局数据绑定,全局数据处理(上面的可以算成这个场景)。
/ * user:kay三石 * time: 8:44 * desc: 公共的异常处理类 / @ControllerAdvice public class BaseExceptionHandler { @ExceptionHandler(Exception.class) @ResponseBody public BaseResult error(Exception e) { e.printStackTrace(); System.out.println("调用了公共异常处理类"); return BaseResult.notOk(e.getMessage()); } }
当然我们也可以通过这两个结合做一些其他方面的实现,其他的可以自行去查阅资料进行使用。这里我们主要是说的ResponseBodyAdvice和@ControllerAdvice的一起使用返回统一的响应格式。
2024最新激活全家桶教程,稳定运行到2099年,请移步至置顶文章:https://sigusoft.com/99576.html
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。 文章由激活谷谷主-小谷整理,转载请注明出处:https://sigusoft.com/16485.html