springboot返回值处理
上⼀次说到了springboot中对于参数处理的扩展,当然主要是说到如何针对特有的请求数据进⾏转换,并⾮站在spring的基础上看spring 如何完成这⼀逻辑,⽽关于spring内部处理或者说内置的处理将在sping源码中详细去理解。
今天将要说到的是springboot中如何处理⽅法返回值,使⽤spring较多的⼈会看到,对于⽅法的返回⼀般会有两种模式,⼀种是页⾯,⼀种是数据,分别对应了ModelAndView和被@ResponseBody标注的⽅法。下⾯简单的看下这两种⽅式的实现过程,同时如何扩展⾃⼰的实现。
对于springmvc,所有的请求⼊⼝则是通过DispatcherServlet.doDispatch处理,不妨从这⾥开始看下处理过程,对于此次不关注的点回直接略过。
⾸先定义⼀个简单的Controller,然后在doDispatch打个断点
主要关注ha,在spring中有很多的HandlerAdapter,我们⽤的⽐较多的当然是RequestMappingHandlerAdapter,相应的进⼊到handleInternal⽅法中,
下⼀步则会调⽤invokeHandlerMethod,内容⽐较多,但是不⽤关注太多,
这⾥可以看到,使⽤了⼀个invocableMethod,看代码可以看到其类型为ServletInvocableHandlerMethod,
这⾥关注下mavContainer.setRequestHandled(true),这也就是表明返回的ModelAndView是否会被视图解析器解析。returnValueHandlers也就是HandlerMethodReturnValueHandlerComposite,
此时会到对应的returnValueHandler去处理,调试会发现RequestResponseBodyMethodProcessor,
这⾥将结果交由MessageConverter处理,由于⽅法writeWithMessageConverters篇幅⽐较长,看下关键点
最终就会定位到我们熟悉的StringHttpMessageConverter、MappingJackson2HttpMessageConverter。
其实通过调试基本可以看到主要的逻辑流程。今天说到的返回值处理主要如何通过HandlerMethodRet
urnValueHandler接⼝进⾏扩展,通过上⾯的调试过程,我们可以看到,对改接⼝的使⽤时在RequestMappingHandlerAdapter出现 ,具体spring对该接⼝有哪些实现,这些实现是如何注⼊到RequestMappingHandlerAdapter中,这个不做深⼊。上⾯说到这⾥会选
择 RequestResponseBodyMethodProcessor,可以看下⼤致的实现,⽅便之后的扩展。
这也解释了为什么通过@ResponseBody标记的类或⽅法能够被处理了。
上⾯看到的,所以我们在扩展的时候也是⼀个道理。
下⾯看⼀个⽰例,将请求结果写到⽂件中并返回:
定义⼀个注解,类似@ResponseBody,ResponseFile :
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface ResponseFile {
String type() default "txt";
}
定义HandlerMethodReturnValueHandler实现类FileHandlerMethodReturnValueHandler:
public class FileHandlerMethodReturnValueHandler implements HandlerMethodReturnValueHandler,Ordered {
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return (AnnotatedElementUtils.ContainingClass(), ResponseFile.class) ||
returnType.hasMethodAnnotation(ResponseFile.class));
}
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) th        mavContainer.setRequestHandled(true);
ResponseFile methodResponseFile = MethodAnnotation(ResponseFile.class);
json值的类型有哪些if(methodResponseFile == null){
methodResponseFile = ContainingClass().getAnnotation(ResponseFile.class);
}
String fileType = pe();
HttpServletResponse response = getServletResponse(webRequest);
response.setHeader("content-type", "application/octet-stream");
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename="+UUID.randomUUID().toString()+"."+fileType);
ServletOutputStream out = OutputStream();
if(returnValue  instanceof ResponseFileEntity){
}else{
}
}
public HttpServletResponse getServletResponse(NativeWebRequest webRequest){
HttpServletResponse response = NativeResponse(HttpServletResponse.class);
return response;
}
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE-10;
}
}
将HandlerMethodReturnValueHandler注册到RequestMappingHandlerAdapter中:
@Configuration
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
@Override
public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
super.addReturnValueHandlers(returnValueHandlers);
returnValueHandlers.add(new FileHandlerMethodReturnValueHandler());
}
}
,根据源码你会发现,这个会注册到RequestMappingHandlerAdapter的customReturnValueHandlers中,但是⼀定要注意,默认情况下会有很多HandlerMethodReturnValueHandler,⽽具体使⽤哪⼀个是根据supportsReturnType进⾏适配,⼀段发现有匹配的处理,则会调⽤,看下⾯的代码你会发现,
⾃定义的处理器位置较后,如果默认的处理器有能够适配的,那么我们定义的就不会执⾏了,所有要注意。
最后就是测试了:
@ResponseFile
@GetMapping("/file")
public ResponseFileEntity toFile(){
ResponseFileEntity responseFileEntity = new ResponseFileEntity();
responseFileEntity.setIn(new ByteArrayInputStream("这是⼀段测试⽂字".getBytes()));
return responseFileEntity;
}
当发送对应请求时,会返回⼀个⽂件。
前⾯说到,我们⼀般情况下的返回值主要都是通过@ResponseBody处理,最后将返回值转换成json类型并返回,所有处理逻辑在RequestResponseBodyMethodProcessor中完成,前⾯也说到,主要是通过HttpMessageConverter完成,这个东西⽐较眼熟,同样,在spring中默认有很多HttpMessageConverter,⽐如常见的StringHttpMessageConverter、
MappingJackson2HttpMessageConverter等。
下⾯通过⾃定义⼀个HttpMessageConverter来针对@ResponseBody进⾏扩展:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。