在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,並且也很是簡單,好比某些場景會須要咱們在響應裏面加入特定一些什麼響應頭或者須要轉化爲指定格式。