Spring MVC之適配器的獲取及執行(RequestMappingHandlerAdapter)

首先看下doDispatch()方法如何找到適合的適配器來執行方法的:java

 1     protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {  2         Iterator i$ = this.handlerAdapters.iterator();  3 
 4  HandlerAdapter ha;  5         do {  6             if (!i$.hasNext()) {  7                 throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");  8  }  9 
10             ha = (HandlerAdapter)i$.next(); 11             if (this.logger.isTraceEnabled()) { 12                 this.logger.trace("Testing handler adapter [" + ha + "]"); 13  } 14         } while(!ha.supports(handler)); //遍歷初始化時候保存好的適配器,經過執行每一個適配器的supports方法,若是支持就是他了。 15 
16         return ha; 17     }

注: 這塊也有點責任鏈模式的意思...web

下面看下RequestMappingHandlerAdapter是怎麼實現support方法的,看以前先上類圖。json

實際上support方法是在AbstractHandlerMethodAdapter這個父類實現的,而後給本身留個鉤子方法,讓子類實現設計模式

1     public final boolean supports(Object handler) { 2         return handler instanceof HandlerMethod && this.supportsInternal((HandlerMethod)handler); 3  } 4 
5     protected abstract boolean supportsInternal(HandlerMethod var1); //鉤子方法

這裏RequestMappingHandlerAdapter的supportInternal直接是返回的true,估計後續擴展其餘子類可能會複雜些,這就是設計模式的好處。緩存

這樣就找到了合適的適配器,下面來看執行:session

 1     protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {  2         HttpServletRequest processedRequest = request;  3         HandlerExecutionChain mappedHandler = null;  4         boolean multipartRequestParsed = false;  5         WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);  6 
 7         try {  8             try {  9                 ModelAndView mv = null; 10                 Exception dispatchException = null; 11 
12                 try { 13                     processedRequest = this.checkMultipart(request); 14                     multipartRequestParsed = processedRequest != request; 15                     mappedHandler = this.getHandler(processedRequest, false); //獲取處理器 16                     if (mappedHandler == null || mappedHandler.getHandler() == null) { 17                         this.noHandlerFound(processedRequest, response); 18                         return; 19  } 20 
21                     HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler()); //獲取適配器 22                     String method = request.getMethod(); 23                     boolean isGet = "GET".equals(method); 24                     if (isGet || "HEAD".equals(method)) { 25                         long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); 26                         if (this.logger.isDebugEnabled()) { 27                             String requestUri = urlPathHelper.getRequestUri(request); 28                             this.logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified); 29  } 30 
31                         if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) { 32                             return; 33  } 34  } //這一塊是處理重複請求??? 有大神知道請留言.... 35 
36                     if (!mappedHandler.applyPreHandle(processedRequest, response)) { 37                         return; 38  } //執行攔截器的preHandle方法 39 
40                     try { 41                         mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); //執行真正的Controller方法,就是咱們的方法 42                     } finally { 43                         if (asyncManager.isConcurrentHandlingStarted()) { 44                             return; 45  } 46 
47  } 48 
49                     this.applyDefaultViewName(request, mv); //設置視圖名稱 50  mappedHandler.applyPostHandle(processedRequest, response, mv); //執行攔截器的postHandle方法 51                 } catch (Exception var28) { 52                     dispatchException = var28; 53  } 54 
55                 this.processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);//渲染視圖 56             } catch (Exception var29) { 57                 this.triggerAfterCompletion(processedRequest, response, mappedHandler, var29); 58             } catch (Error var30) { 59                 this.triggerAfterCompletionWithError(processedRequest, response, mappedHandler, var30); 60  } 61 
62         } finally { 63             if (asyncManager.isConcurrentHandlingStarted()) { 64  mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); //執行攔截器的afterConcurrentHandlingStarted 65                 return; 66             } else { 67                 if (multipartRequestParsed) { 68                     this.cleanupMultipart(processedRequest); 69  } 70 
71  } 72  } 73     }

攔截器這裏就不在多說,這塊就是返回false就不在往下執行。下面咱們重點滿ha.handle()方法,是若是映射參數,找到咱們的方法,封裝結果的。app

類圖前面已經展現了,實際上handle是在父類AbstractHandlerMethodAdapter實現的異步

1     public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 2         return this.handleInternal(request, response, (HandlerMethod)handler); //子類實現這個方法 3  } 4 
5     protected abstract ModelAndView handleInternal(HttpServletRequest var1, HttpServletResponse var2, HandlerMethod var3) throws Exception;
 1     protected final ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {  2         if (this.getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {  3             this.checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);  4         } else {  5             this.checkAndPrepare(request, response, true);  6  } //看代碼應該是從session中獲取一些信息,而後初始化header等信息,不知道準確不?請你們指正!  7         //這塊就是根據須要是否進行同步操做
 8         if (this.synchronizeOnSession) {  9             HttpSession session = request.getSession(false); 10             if (session != null) { 11                 Object mutex = WebUtils.getSessionMutex(session); 12  synchronized(mutex) { 13                     return this.invokeHandleMethod(request, response, handlerMethod); 14  } 15  } 16  } 17         //正式進入執行環節
18         return this.invokeHandleMethod(request, response, handlerMethod); 19     }

下面這個方法很是重要,將重點講解:async

 1     private ModelAndView invokeHandleMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {  2         ServletWebRequest webRequest = new ServletWebRequest(request, response);  3         WebDataBinderFactory binderFactory = this.getDataBinderFactory(handlerMethod); //建立@InitBinder註解的方法的工廠類,進行緩存  4         ModelFactory modelFactory = this.getModelFactory(handlerMethod, binderFactory);//建立@ModelAttribute@ControllerAdvice註解方法工廠並緩存  5         ServletInvocableHandlerMethod requestMappingMethod = this.createRequestMappingMethod(handlerMethod, binderFactory);  6         ModelAndViewContainer mavContainer = new ModelAndViewContainer(); //建立結果容器並初始化一些參數,  7  mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));  8  modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);//執行@ModelAttribute註解的方法,將結果放到結果容器中  9         mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect); 10         AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response); //下面異步這一塊不太明白,等後續在慢慢分析 11         asyncWebRequest.setTimeout(this.asyncRequestTimeout); 12         WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); 13         asyncManager.setTaskExecutor(this.taskExecutor); 14  asyncManager.setAsyncWebRequest(asyncWebRequest); 15         asyncManager.registerCallableInterceptors(this.callableInterceptors); 16         asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors); 17         if (asyncManager.hasConcurrentResult()) { 18             Object result = asyncManager.getConcurrentResult(); 19             mavContainer = (ModelAndViewContainer)asyncManager.getConcurrentResultContext()[0]; 20  asyncManager.clearConcurrentResult(); 21             if (this.logger.isDebugEnabled()) { 22                 this.logger.debug("Found concurrent result value [" + result + "]"); 23  } 24 
25             requestMappingMethod = requestMappingMethod.wrapConcurrentResult(result); 26  } 27 
28         requestMappingMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]); //繼續執行方法 29         return asyncManager.isConcurrentHandlingStarted() ? null : this.getModelAndView(mavContainer, modelFactory, webRequest); //返回值了,兩種狀況 30     }
 1     public final void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {  2         Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs); //執行方法,獲取返回值  3         this.setResponseStatus(webRequest);  4         if (returnValue == null) {  5             if (this.isRequestNotModified(webRequest) || this.hasResponseStatus() || mavContainer.isRequestHandled()) {  6                 mavContainer.setRequestHandled(true);  7                 return;  8  }  9         } else if (StringUtils.hasText(this.responseReason)) { 10             mavContainer.setRequestHandled(true); 11             return; 12  } 13 
14         mavContainer.setRequestHandled(false); 15 
16         try { //處理返回值 ,封裝結果集 17             this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest); 18         } catch (Exception var6) { 19             if (this.logger.isTraceEnabled()) { 20                 this.logger.trace(this.getReturnValueHandlingErrorMessage("Error handling return value", returnValue), var6); 21  } 22 
23             throw var6; 24  } 25     }
 1     public final Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {  2         Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs); //處理 參數  3         if (this.logger.isTraceEnabled()) {  4             StringBuilder builder = new StringBuilder("Invoking [");  5             builder.append(this.getMethod().getName()).append("] method with arguments ");  6  builder.append(Arrays.asList(args));  7             this.logger.trace(builder.toString());  8  }  9 
10         Object returnValue = this.invoke(args); //反射執行方法 11         if (this.logger.isTraceEnabled()) { 12             this.logger.trace("Method [" + this.getMethod().getName() + "] returned [" + returnValue + "]"); 13  } 14 
15         return returnValue; 16     }
 1     private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {  2         MethodParameter[] parameters = this.getMethodParameters();  3         Object[] args = new Object[parameters.length];  4 
 5         for(int i = 0; i < parameters.length; ++i) { //遍歷方法的全部參數  6             MethodParameter parameter = parameters[i];  7             parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);  8             GenericTypeResolver.resolveParameterType(parameter, this.getBean().getClass()); //獲取設置參數類型  9             args[i] = this.resolveProvidedArgument(parameter, providedArgs); 10             if (args[i] == null) { 11                 if (this.argumentResolvers.supportsParameter(parameter)) { //這塊是遍歷預置的參數解析器,就是前面說的責任鏈模式,**composite負責查找和執行 12                     try { //由找到的參數解析器,來解析參數 13                         args[i] = this.argumentResolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory); 14                     } catch (Exception var9) { 15                         if (this.logger.isTraceEnabled()) { 16                             this.logger.trace(this.getArgumentResolutionErrorMessage("Error resolving argument", i), var9); 17  } 18 
19                         throw var9; 20  } 21                 } else if (args[i] == null) { 22                     String msg = this.getArgumentResolutionErrorMessage("No suitable resolver for argument", i); 23                     throw new IllegalStateException(msg); 24  } 25  } 26  } 27 
28         return args; 29     }

這塊以,沒有任何註解,參數爲javaBean的解析器爲例:ModelAttributeMethodProcessoride

 1     public boolean supportsParameter(MethodParameter parameter) {  2         if (parameter.hasParameterAnnotation(ModelAttribute.class)) {  3             return true;  4         } else if (this.annotationNotRequired) {  5             return !BeanUtils.isSimpleProperty(parameter.getParameterType());  6         } else {  7             return false;  8  }  9  } 10 
11     public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest request, WebDataBinderFactory binderFactory) throws Exception { 12         String name = ModelFactory.getNameForParameter(parameter); //若是當前參數用@ModelAttribute修飾了,返回value值或者參數類型第一個字母小寫 13         // 獲取須要綁定的表單對象,看參數容器包含name爲key的對象不,有的話就用它,沒有建立個新的。 
      Object attribute = mavContainer.containsAttribute(name) ? mavContainer.getModel().get(name) : this.createAttribute(name, parameter, binderFactory, request); 14 WebDataBinder binder = binderFactory.createBinder(request, attribute, name); 15 if (binder.getTarget() != null) { 16 this.bindRequestParameters(binder, request); 17 this.validateIfApplicable(binder, parameter); 18 if (binder.getBindingResult().hasErrors() && this.isBindExceptionRequired(binder, parameter)) { 19 throw new BindException(binder.getBindingResult()); 20 } 21 } 22      //以上就是參數綁定, 這塊領開一篇文章詳細說 23 Map<String, Object> bindingResultModel = binder.getBindingResult().getModel(); 24 mavContainer.removeAttributes(bindingResultModel); 25 mavContainer.addAllAttributes(bindingResultModel); 26 return binder.getTarget(); 27 }

參數就這樣遍歷處理,而後就開始經過反射 invoke執行了。接下來咱們看是怎麼封裝換回結果的

1         try { 2             this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest); 3         } catch (Exception var6) { 4             if (this.logger.isTraceEnabled()) { 5                 this.logger.trace(this.getReturnValueHandlingErrorMessage("Error handling return value", returnValue), var6); 6  } 7 
8             throw var6; 9         }

this.returnValuehandlers. 就是那個返回結果的包裝類,初始化的結果解析器就保存這裏,處理思路和參數解析器同樣的,

 1     public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {  2         HandlerMethodReturnValueHandler handler = this.getReturnValueHandler(returnType);  3         Assert.notNull(handler, "Unknown return value type [" + returnType.getParameterType().getName() + "]");  4  handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);  5  }  6 
 7     private HandlerMethodReturnValueHandler getReturnValueHandler(MethodParameter returnType) {  8         Iterator i$ = this.returnValueHandlers.iterator();  9 
10  HandlerMethodReturnValueHandler returnValueHandler; 11         do { 12             if (!i$.hasNext()) { 13                 return null; 14  } 15 
16             returnValueHandler = (HandlerMethodReturnValueHandler)i$.next(); 17             if (this.logger.isTraceEnabled()) { 18                 this.logger.trace("Testing if return value handler [" + returnValueHandler + "] supports [" + returnType.getGenericParameterType() + "]"); 19  } 20         } while(!returnValueHandler.supportsReturnType(returnType)); 21 
22         return returnValueHandler; 23     }

遍歷預置的全部結果解析器,結果解析器統一實現HandlerMethodReturnValueHandler 接口,實現supportReturnType方法:

這裏咱們距離用@ResponseBody註解的結果解析器RequestResponseBodyMethodProcessor 前面說了,參數和結果集他都實現了

 1     public boolean supportsReturnType(MethodParameter returnType) {  2         return returnType.getMethodAnnotation(ResponseBody.class) != null; //判斷是否有@ResponseBody註解  3  }  4     public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException {  5         mavContainer.setRequestHandled(true);  6         if (returnValue != null) {  7             this.writeWithMessageConverters(returnValue, returnType, webRequest); //用內置的消息轉換器來轉換結果集  8  }  9 
10     }

這裏可能有人會問,消息轉換器何時加載的?是在RequestMappingHandlerAdapter這個bean實例化的時候加載的,同時加載參數和結果解析器時候注入到解析器當中的

 1     public RequestMappingHandlerAdapter() { //無參構造函數中初始化  2         StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();  3         stringHttpMessageConverter.setWriteAcceptCharset(false);  4         this.messageConverters = new ArrayList();  5         this.messageConverters.add(new ByteArrayHttpMessageConverter());  6         this.messageConverters.add(stringHttpMessageConverter);  7         this.messageConverters.add(new SourceHttpMessageConverter());  8         this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());  9  } 10     private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() { //構造參數解析器時候,注入進去 11         List<HandlerMethodReturnValueHandler> handlers = new ArrayList(); 12         handlers.add(new ModelAndViewMethodReturnValueHandler()); 13         handlers.add(new ModelMethodProcessor()); 14         handlers.add(new ViewMethodReturnValueHandler()); 15         handlers.add(new HttpEntityMethodProcessor(this.getMessageConverters(), this.contentNegotiationManager)); 16         handlers.add(new CallableMethodReturnValueHandler()); 17         handlers.add(new DeferredResultMethodReturnValueHandler()); 18         handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory)); 19         handlers.add(new ModelAttributeMethodProcessor(false)); 20         handlers.add(new RequestResponseBodyMethodProcessor(this.getMessageConverters(), this.contentNegotiationManager)); 21         handlers.add(new ViewNameMethodReturnValueHandler()); 22         handlers.add(new MapMethodProcessor()); 23         if (this.getCustomReturnValueHandlers() != null) { 24             handlers.addAll(this.getCustomReturnValueHandlers()); 25  } 26 
27         if (!CollectionUtils.isEmpty(this.getModelAndViewResolvers())) { 28             handlers.add(new ModelAndViewResolverMethodReturnValueHandler(this.getModelAndViewResolvers())); 29         } else { 30             handlers.add(new ModelAttributeMethodProcessor(true)); 31  } 32 
33         return handlers; 34     }

下面來看是怎麼尋找能夠合適的消息轉換器的

 1     protected <T> void writeWithMessageConverters(T returnValue, MethodParameter returnType, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException {  2         ServletServerHttpRequest inputMessage = this.createInputMessage(webRequest);  3         ServletServerHttpResponse outputMessage = this.createOutputMessage(webRequest);  4         this.writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);  5  }  6 
 7     protected <T> void writeWithMessageConverters(T returnValue, MethodParameter returnType, ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage) throws IOException, HttpMediaTypeNotAcceptableException {  8         Class<?> returnValueClass = returnValue.getClass();  9         HttpServletRequest servletRequest = inputMessage.getServletRequest(); 10         List<MediaType> requestedMediaTypes = this.getAcceptableMediaTypes(servletRequest); //獲取請求的MediaType,eg:"application/json" 11         List<MediaType> producibleMediaTypes = this.getProducibleMediaTypes(servletRequest, returnValueClass); //尋找支持這個返回類型的轉換器支持的MediaTyoe 12         Set<MediaType> compatibleMediaTypes = new LinkedHashSet(); 13         Iterator i$ = requestedMediaTypes.iterator(); 14      //雙循環兩個list,進行匹配,把複覈條件的MediaType放到compatibleMediaTypes中 //TODO有些不懂得是爲啥這塊要過濾一遍,  後面實現了 父類也作了判斷每一個字類是否支持MediaType了??
15  MediaType selectedMediaType; 16  Iterator i$; 17  MediaType mediaType; 18         while(i$.hasNext()) { 19             selectedMediaType = (MediaType)i$.next(); 20             i$ = producibleMediaTypes.iterator(); 21 
22             while(i$.hasNext()) { 23                 mediaType = (MediaType)i$.next(); 24                 if (selectedMediaType.isCompatibleWith(mediaType)) { 25                     compatibleMediaTypes.add(this.getMostSpecificMediaType(selectedMediaType, mediaType)); 26  } 27  } 28  } 29 
30         if (compatibleMediaTypes.isEmpty()) { 31             throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes); 32         } else { 33             List<MediaType> mediaTypes = new ArrayList(compatibleMediaTypes); 34  MediaType.sortBySpecificityAndQuality(mediaTypes); 35             selectedMediaType = null; 36             i$ = mediaTypes.iterator(); 37             //排序以後,選擇適合的MediaType
38             while(i$.hasNext()) { 39                 mediaType = (MediaType)i$.next(); 40                 if (mediaType.isConcrete()) { 41                     selectedMediaType = mediaType; 42                     break; 43  } 44 
45                 if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICATION)) { 46                     selectedMediaType = MediaType.APPLICATION_OCTET_STREAM; 47                     break; 48  } 49  } 50 
51             if (selectedMediaType != null) { 52                 selectedMediaType = selectedMediaType.removeQualityValue(); 53                 i$ = this.messageConverters.iterator(); 54                 //遍歷全部消息轉換器,canWrite是接口方法,至關於前面的support等,模式都是一個。而後知足的進行write。輸出結果。
55                 while(i$.hasNext()) { 56                     HttpMessageConverter<?> messageConverter = (HttpMessageConverter)i$.next(); 57                     if (messageConverter.canWrite(returnValueClass, selectedMediaType)) { 58  messageConverter.write(returnValue, selectedMediaType, outputMessage); 59                         if (this.logger.isDebugEnabled()) { 60                             this.logger.debug("Written [" + returnValue + "] as \"" + selectedMediaType + "\" using [" + messageConverter + "]"); 61  } 62 
63                         return; 64  } 65  } 66  } 67 
68             throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes); 69  } 70     }

下面介紹下,@ResponseBode標籤用的消息轉換器是MappingJacksonHttpMessageConverter;先看下類圖吧

 

MappingJacksonHttpMessageConverter重寫了父類的write方法:

1     public boolean canWrite(Class<?> clazz, MediaType mediaType) { 2         return this.objectMapper.canSerialize(clazz) && this.canWrite(mediaType); //canWrite(mediaType)是父類實現的 3     }
 1     protected boolean canWrite(MediaType mediaType) {  2         if (mediaType != null && !MediaType.ALL.equals(mediaType)) {  3             Iterator i$ = this.getSupportedMediaTypes().iterator(); //獲取子類解析器支持的MediaType,看下是否支持  4 
 5  MediaType supportedMediaType;  6             do {  7                 if (!i$.hasNext()) {  8                     return false;  9  } 10 
11                 supportedMediaType = (MediaType)i$.next(); 12             } while(!supportedMediaType.isCompatibleWith(mediaType)); 13 
14             return true; 15         } else { 16             return true; 17  } 18     }

write方法 父類也幫着實現了,父類具體作了如輸出,拼湊輸出流頭等信息

 1     public final void write(T t, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {  2         HttpHeaders headers = outputMessage.getHeaders();  3         if (headers.getContentType() == null) {  4             if (contentType == null || contentType.isWildcardType() || contentType.isWildcardSubtype()) {  5                 contentType = this.getDefaultContentType(t);  6  }  7 
 8             if (contentType != null) {  9  headers.setContentType(contentType); 10  } 11  } 12 
13         if (headers.getContentLength() == -1L) { 14             Long contentLength = this.getContentLength(t, headers.getContentType()); 15             if (contentLength != null) { 16  headers.setContentLength(contentLength); 17  } 18  } 19 
20         this.writeInternal(t, outputMessage); //鉤子方法,讓子類去實現 21  outputMessage.getBody().flush(); 22     }
 1     protected void writeInternal(Object object, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {  2         JsonEncoding encoding = this.getJsonEncoding(outputMessage.getHeaders().getContentType());  3         JsonGenerator jsonGenerator = this.objectMapper.getJsonFactory().createJsonGenerator(outputMessage.getBody(), encoding);  4         if (this.objectMapper.getSerializationConfig().isEnabled(Feature.INDENT_OUTPUT)) {  5  jsonGenerator.useDefaultPrettyPrinter();  6  }  7         //這塊就是默認用Jackson進行翻譯結果集了
 8         try {  9             if (this.prefixJson) { 10                 jsonGenerator.writeRaw("{} && "); 11  } 12 
13             this.objectMapper.writeValue(jsonGenerator, object); 14         } catch (JsonProcessingException var6) { 15             throw new HttpMessageNotWritableException("Could not write JSON: " + var6.getMessage(), var6); 16  } 17     }

由於用@ResponseBody不須要返回視圖,因此視圖那塊就返回Null,不須要渲染視圖了

相關文章
相關標籤/搜索