在springmvc中,不少人都知道@ResponseBody,加了它那就会返回对应的数据结果(json),而不是一张jsp或者其余视图。若是不加,那么它就返回了一个具体的视图,如jsp。那么让咱们来深刻探析下这里面的究竟。java
在前一篇咱们主要讲述了springmvc对传入参数的接口HandlerMethodArgumentResolver。那么springmvc一样也也提供了一系列对响应返回值进行处理的接口,核心接口类就是本篇要介绍的HandlerMethodReturnValueHandler。web
public interface HandlerMethodReturnValueHandler { /** * Whether the given {@linkplain MethodParameter method return type} is * supported by this handler. * @param returnType the method return type to check * @return {@code true} if this handler supports the supplied return type; * {@code false} otherwise */ boolean supportsReturnType(MethodParameter returnType); /** * Handle the given return value by adding attributes to the model and * setting a view or setting the * {@link ModelAndViewContainer#setRequestHandled} flag to {@code true} * to indicate the response has been handled directly. * @param returnValue the value returned from the handler method * @param returnType the type of the return value. This type must have * previously been passed to {@link #supportsReturnType} which must * have returned {@code true}. * @param mavContainer the ModelAndViewContainer for the current request * @param webRequest the current request * @throws Exception if the return value handling results in an error */ void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception; }
HandlerMethodReturnValueHandler是在spring3.1以后引入的spring
它主要包含2个方法:json
1.supportsReturnType()决定了哪类类型的返回值将启用该返回值处理器mvc
2.handleReturnValue则是主要处理返回值的处理逻辑,而且将处理好的值返回给model,还能够处理该返回什么视图app
HandlerMethodReturnValueHandler的实现大多类都是已ReturnValueHandler或者Processor(包含了参数处理)结尾jsp
在初始化RequestMappingHandlerAdapter时候,springmvc默认初始化了一系列返回值处理器,而且提供了自动以的HandlerMethodReturnValueHandler的入口。ide
private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() { List<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>(); // Single-purpose return value types handlers.add(new ModelAndViewMethodReturnValueHandler()); handlers.add(new ModelMethodProcessor()); handlers.add(new ViewMethodReturnValueHandler()); handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters())); handlers.add(new StreamingResponseBodyReturnValueHandler()); handlers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.contentNegotiationManager, this.requestResponseBodyAdvice)); handlers.add(new HttpHeadersReturnValueHandler()); handlers.add(new CallableMethodReturnValueHandler()); handlers.add(new DeferredResultMethodReturnValueHandler()); handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory)); // Annotation-based return value types handlers.add(new ModelAttributeMethodProcessor(false)); handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.contentNegotiationManager, this.requestResponseBodyAdvice)); // Multi-purpose return value types handlers.add(new ViewNameMethodReturnValueHandler()); handlers.add(new MapMethodProcessor()); // Custom return value types 加入自定义的返回值处理器 if (getCustomReturnValueHandlers() != null) { handlers.addAll(getCustomReturnValueHandlers()); } // Catch-all if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) { handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers())); } else { handlers.add(new ModelAttributeMethodProcessor(true)); } return handlers; }
HandlerMethodReturnValueHandler的匹配是按照初始化的顺序,请看下面table罗列的处理器和对应的处理类型。源码分析
处理器 | 处理类型 |
针对一中类型 | |
ModelAndViewMethodReturnValueHandler | ModelAndView |
ModelMethodProcessor | Model |
ViewMethodReturnValueHandler | View |
ResponseBodyEmitterReturnValueHandler | ResponseEntity<ResponseBodyEmitter> |
StreamingResponseBodyReturnValueHandler | ResponseEntity<StreamingResponseBody> |
HttpHeadersReturnValueHandler | HttpHeaders |
CallableMethodReturnValueHandler | Callable |
DeferredResultMethodReturnValueHandler | DeferredResult、ListenableFuture、CompletionStage |
AsyncTaskMethodReturnValueHandler | WebAsyncTask |
针对注解 | |
ModelAttributeMethodProcessor | @ModelAttribute(require=false) |
RequestResponseBodyMethodProcessor | @ResponseBody |
处理多种类型 | |
ViewNameMethodReturnValueHandler | void、CharSequence(V4.2) |
MapMethodProcessor | Map |
自定义返回值处理器 | |
ModelAndViewResolverMethodReturnValueHandler | 默认处理,若是以上的都不知足就会进入 |
ModelAttributeMethodProcessor | @ModelAttribute(require=true) |
public boolean supportsReturnType(MethodParameter returnType) { //支持类型 return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) || returnType.hasMethodAnnotation(ResponseBody.class)); }
mavContainer.setRequestHandled(true);//请求是否已经彻底在处理程序中处理好,若是是fasle,则继续流转到对应的视图,若是设置为true,则不会再进过视图这一 层直接响应,默认是false。ui
public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException { mavContainer.setRequestHandled(true);//若是没有视图,则必须设置为true,不然会返回视图层 ServletServerHttpRequest inputMessage = createInputMessage(webRequest); ServletServerHttpResponse outputMessage = createOutputMessage(webRequest); // Try even with null return value. ResponseBodyAdvice could get involved. //输出 writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage); }
咱们来实现一个相似@ResponseBody的功能。
@Target ( {ElementType.TYPE, ElementType.METHOD}) @Retention (RetentionPolicy.RUNTIME) @Documented public @interface KingsResponseBody { String type() default "json"; }
public class CustomerHandlerMethodReturnValueHandler implements HandlerMethodReturnValueHandler { @Override public boolean supportsReturnType(MethodParameter returnType) { return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), KingsResponseBody.class) || returnType.hasMethodAnnotation(KingsResponseBody.class)); } @Override public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { KingsResponseBody anno = returnType.getMethodAnnotation(KingsResponseBody.class); mavContainer.setRequestHandled(true); String type = anno.type(); HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class); response.setContentType("text/json;charset=UTF-8"); try (PrintWriter out = response.getWriter()) { Gson jb = new Gson(); out.write(jb.toJson(returnValue)); out.flush(); } catch (IOException e) { throw e; } } }
有时候咱们还能够往响应头里面丢一些内容什么的,具体的实现根据需求而定。
<mvc:annotation-driven > <mvc:return-value-handlers> <bean class="com.kings.template.mvc.CustomerHandlerMethodReturnValueHandler"/> </mvc:return-value-handlers> </mvc:annotation-driven>
@Controller public class HandlerMethodReturnValueHandlerDemoController { @RequestMapping (value="/returnvalue/1",method=GET) @KingsResponseBody public List<Person> demo() { Person p1 = new Person(); p1.setName("WS"); Person p2 = new Person(); p2.setName("Kings"); return Lists.newArrayList(p1,p2); } }
访问:http://localhost:8080/returnvalue/1
返回:
[{"name":"WS"},{"name":"Kings"}]
当咱们须要统一处理springmvc返回值的时候咱们就能够考虑使用HandlerMethodReturnValueHandler,并且也很是简单,好比某些场景会须要咱们在响应里面加入特定一些什么响应头或者须要转化为指定格式。