统一响应接口封装
在上一家公司中我经常看到接口中返回的直接是一个对象集。然而在响应后却又封装了{msg:,state:,obj:},这些参数我就很纳闷这个是如何实现的。我第一反应就是使用了AOP。但是找了许久并未发现哪里使用了AOP的形式。经过层层的深入我发现了一个接口和一个注解,才慢慢的打开迷层。ResponseBodyAdvice
ResponseBodyAdvice这个接口一看就是通过增强器进行织入的,我们从Advice就可以看出。这个需要配合ControllerAdvice或者RestControllerAdvice
ResponseBodyAdvice接口是spring4。1的特性,其作用是在响应体写出前做一些处理,比如修改返回值,加密等。允许在执行ResponseBody或ResponseEntity控制器方法之后但在使用HttpMessageConverter编写正文之前自定义响应。可以直接在RequestMappingHandlerAdapter和ExceptionHandlerExceptionResolver注册实现,或者更有可能在ControllerAdvice中注解,在这种情况下,它们都会被两者自动检测到。
下面我们来看下这个接口的定义publicinterfaceResponseBodyAdviceT{此组件是否支持给定的控制器方法返回类型和所选的HttpMessageConverter类型。这个方法返回true后才会执行下面的beforeBodyWrite方法booleansupports(MethodParameterreturnType,Classlt;?extendsHttpMessageConverterlt;?converterType);在选择HttpMessageConverter之后且在调用其write方法之前调用NullableTbeforeBodyWrite(NullableTbody,MethodParameterreturnType,MediaTypeselectedContentType,Classlt;?extendsHttpMessageConverterlt;?selectedConverterType,ServerHttpRequestrequest,ServerHttpResponseresponse);}
接口的使用我们直接在Controller进行增强,这里我们增强的是RestController看代码RestControllerAdvice(basePackagescom。kaysanshi)publicclassResponseControllerAdviceimplementsResponseBodyAdviceObject{Overridepublicbooleansupports(MethodParameterreturnType,Classlt;?extendsHttpMessageConverterlt;?converterType){获取当前controller请求的方法是否有SkipR注解SkipRskipRreturnType。getMethod()。getAnnotation(SkipR。class);if(null!skipR)returnfalse;是否是返回的R对象return!returnType。getMethod()。getReturnType()。equals(R。class);}OverridepublicObjectbeforeBodyWrite(Objectbody,MethodParameterreturnType,MediaTypeselectedContentType,Classlt;?extendsHttpMessageConverterlt;?selectedConverterType,ServerHttpRequestrequest,ServerHttpResponseresponse){这个地方是自己判断的其他的直接返回当前对象,不进行包装if(request。getHeaders()。containsKey(SecurityConstants。INNER)SecurityConstants。INNERTRUE。equalsIgnoreCase(request。getHeaders()。getFirst(SecurityConstants。INNER))){returnbody;}if(returnType。getGenericParameterType()。equals(String。class)){returnJSON。toJSONString(newR(body));}returnnewR(body);}}
在这个beforeBodyWrite的方法中我们可以实现自己的想要的内容,这里有我们通过inner注解进行过滤了fegin中返回的封装,直接将响应返回到上游。当不是标示inner的调用,我们将其封装到返回实体的对象中。
在看这个接口我发现FastJson也是通过对这个接口的实现,封装了一下将对象转为Json的使用。而我们不使用Rest处理的时候,就是FastJsonViewResponseBodyAdvice实现了对ResponseBodyAdvice的接口的实现
对应的返回实体R对象的封装如下BuilderAccessors(chaintrue)AllArgsConstructorNoArgsConstructorDatapublicclassRTimplementsSerializable{privatestaticfinallongserialVersionUID9141307870732228707L;privateStringstate;privateStringmsg;privateTobj;publicR(Tobj){super();this。stateCommonConstants。SUCCESS;this。objobj;}publicR(FirstExceptione){super();this。statee。getCode();this。msge。getMessage();}publicR(FirstArgsExceptione){super();this。statee。getCode();this。msge。getMessage();}publicR(LogicExceptione){super();this。statee。getCode();this。msge。getMessage();}publicR(LogicArgsExceptione){super();this。statee。getCode();this。msge。getMessage();}publicR(AccessDeniedExceptione){super();this。stateSecurityConstants。ACCESSDENIED;this。msge。getMessage();}publicR(NotBreakerExceptione){super();this。statee。getCode();this。msge。getMessage();}publicR(Throwablee){super();if(InfoUtils。isContain(e。getMessage())){this。statee。getMessage();this。msgInfoUtils。getInfo(this。state);}else{this。stateCommonConstants。FAIL;this。msgInfoUtils。getInfo(FirstException。ERRORCODE);}}publicRTsuccess(Tobj){this。stateCommonConstants。SUCCESS;this。objobj;returnthis;}publicRTerror(Stringmsg){this。stateCommonConstants。FAIL;this。msgmsg;returnthis;}publicRTerror(){this。stateCommonConstants。FAIL;this。msgInfoUtils。getInfo(FirstException。ERRORCODE);returnthis;}JSONField(serializefalse)JsonIgnorepublicBooleangetIsSuccess(){returnObjects。equal(CommonConstants。SUCCESS,this。state);}publicStringtoJson(){returnJSON。toJSONString(this);}}
经过以上的方式我们就可以做成一个全局的统一响应的封装。ControllerAdvice
这样我们已经知道ControllerAdvice的一个应用场景,是结合ResponseBodyAdvice进行使用的,同样我们也可以将ControllerAdvice的应用到其他场景。比如:统一异常处理,全局数据绑定,全局数据处理(上面的可以算成这个场景)。user:kay三石time:8:44desc:公共的异常处理类ControllerAdvicepublicclassBaseExceptionHandler{ExceptionHandler(Exception。class)ResponseBodypublicBaseResulterror(Exceptione){e。printStackTrace();System。out。println(调用了公共异常处理类);returnBaseResult。notOk(e。getMessage());}}
当然我们也可以通过这两个结合做一些其他方面的实现,其他的可以自行去查阅资料进行使用。这里我们主要是说的ResponseBodyAdvice和ControllerAdvice的一起使用返回统一的响应格式。