日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

SpringBoot对于标注@ResponseBody注解返回JSON数据的处理

發布時間:2025/3/15 javascript 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SpringBoot对于标注@ResponseBody注解返回JSON数据的处理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
  • 前面我們已經知道,解析request要找到參數解析器和返回值處理器,而對于@ResponseBody注解的方法,其實就是其對應的返回值處理器再起作用

  • 返回值處理器,我們知道有默認15種 :

    其中處理器RequestResponseBodyMethodHandler,就是我們使用@ResponseBody時,使用的處理器,底層如下:

  • 那么拿到對應的返回值處理器后,springMVC是如何對返回值進行操作的呢?
    debug發現,處理@ResponseBody,會調用以下方法:

    writeWithMessageConverters部分源碼:

  • protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType, ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {Object body;Class valueType;Object targetType;//先判斷要返回的值是不是字符串類型if (value instanceof CharSequence) {body = value.toString();valueType = String.class;targetType = String.class;} else {//拿到要返回的對象body = value;//拿到要返回對對象的類型valueType = this.getReturnValueType(value, returnType);targetType = GenericTypeResolver.resolveType(this.getGenericType(returnType), returnType.getContainingClass());}//再判斷返回值類型是不是資源類型(流數據),如果是,就調用下面對流數據處理的邏輯,例如直接響應if (this.isResourceType(value, returnType)) {outputMessage.getHeaders().set("Accept-Ranges", "bytes");if (value != null && inputMessage.getHeaders().getFirst("Range") != null && outputMessage.getServletResponse().getStatus() == 200) {Resource resource = (Resource)value;try {List<HttpRange> httpRanges = inputMessage.getHeaders().getRange();outputMessage.getServletResponse().setStatus(HttpStatus.PARTIAL_CONTENT.value());body = HttpRange.toResourceRegions(httpRanges, resource);valueType = body.getClass();targetType = RESOURCE_REGION_LIST_TYPE;} catch (IllegalArgumentException var19) {outputMessage.getHeaders().set("Content-Range", "bytes */" + resource.contentLength());outputMessage.getServletResponse().setStatus(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE.value());}}}//(媒體類型)內容協商,瀏覽器默認會以請求頭的方式告訴服務器他能接受什么樣的內容類型)//服務器最終根據自己自身的能力,決定服務器能生產出什么樣內容類型的數據MediaType selectedMediaType = null;MediaType contentType = outputMessage.getHeaders().getContentType();boolean isContentTypePreset = contentType != null && contentType.isConcrete();if (isContentTypePreset) {if (this.logger.isDebugEnabled()) {this.logger.debug("Found 'Content-Type:" + contentType + "' in response");}selectedMediaType = contentType;} else {HttpServletRequest request = inputMessage.getServletRequest();List<MediaType> acceptableTypes = this.getAcceptableMediaTypes(request);List<MediaType> producibleTypes = this.getProducibleMediaTypes(request, valueType, (Type)targetType);if (body != null && producibleTypes.isEmpty()) {throw new HttpMessageNotWritableException("No converter found for return value of type: " + valueType);}List<MediaType> mediaTypesToUse = new ArrayList();Iterator var15 = acceptableTypes.iterator();MediaType mediaType;while(var15.hasNext()) {mediaType = (MediaType)var15.next();Iterator var17 = producibleTypes.iterator();while(var17.hasNext()) {MediaType producibleType = (MediaType)var17.next();if (mediaType.isCompatibleWith(producibleType)) {mediaTypesToUse.add(this.getMostSpecificMediaType(mediaType, producibleType));}}}if (mediaTypesToUse.isEmpty()) {if (body != null) {throw new HttpMediaTypeNotAcceptableException(producibleTypes);}if (this.logger.isDebugEnabled()) {this.logger.debug("No match for " + acceptableTypes + ", supported: " + producibleTypes);}return;}MediaType.sortBySpecificityAndQuality(mediaTypesToUse);var15 = mediaTypesToUse.iterator();//遍歷協商,得到可以返回的數據類型while(var15.hasNext()) {mediaType = (MediaType)var15.next();if (mediaType.isConcrete()) {selectedMediaType = mediaType;break;}if (mediaType.isPresentIn(ALL_APPLICATION_MEDIA_TYPES)) {selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;break;}}if (this.logger.isDebugEnabled()) {this.logger.debug("Using '" + selectedMediaType + "', given " + acceptableTypes + " and supported " + producibleTypes);}}HttpMessageConverter converter;GenericHttpMessageConverter genericConverter;label159: {if (selectedMediaType != null) {selectedMediaType = selectedMediaType.removeQualityValue();Iterator var22 = this.messageConverters.iterator();//遍歷所有的HttpMessageConverter(看是否支持將 此 Class類型的對象,轉為MediaType類型的數據,過程是可逆的)//得到可匹配的消息轉換器,支持將對象轉成Json數據,這就是關鍵的核心//最終得到MappingJackson2HttpMessageConverter可以將對象寫為jsonwhile(var22.hasNext()) {converter = (HttpMessageConverter)var22.next();genericConverter = converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter)converter : null;if (genericConverter != null) {if (((GenericHttpMessageConverter)converter).canWrite((Type)targetType, valueType, selectedMediaType)) {break label159;}} else if (converter.canWrite(valueType, selectedMediaType)) {break label159;}}} }
    • 最終 MappingJackson2HttpMessageConverter 把對象轉為JSON(利用底層的jackson的objectMapper轉換的

    • MessageConverter規范

    • 默認的MessageConverter

    0 - 只支持Byte類型的 1 - String 2 - String 3 - Resource 4 - ResourceRegion 5 - DOMSource.class \ SAXSource.class) \ StAXSource.class \StreamSource.class \Source.class 6 - MultiValueMap 7 - true 8 - true 9 - 支持注解方式xml處理的。
    • 總結:
    ? 1、返回值處理器判斷是否支持這種類型返回值 supportsReturnType ? 2、返回值處理器調用 handleReturnValue 進行處理 ? 3、RequestResponseBodyMethodProcessor 可以處理返回值標了@ResponseBody 注解的。? 利用 MessageConverters 進行處理 將數據寫為json? A.內容協商(瀏覽器默認會以請求頭的方式告訴服務器他能接受什么樣的內容類型)? B.服務器最終根據自己自身的能力,決定服務器能生產出什么樣內容類型的數據,? C.SpringMVC會挨個遍歷所有容器底層的 HttpMessageConverter ,看誰能處理?? a.得到MappingJackson2HttpMessageConverter可以將對象寫為json? b.利用MappingJackson2HttpMessageConverter將對象轉為json再寫出去。
    • 附加:文件返回方式
      FileSystemResource 是Resource的實現類,所以springMVC最終會調用對應的messageConverter進行處理

    總結

    以上是生活随笔為你收集整理的SpringBoot对于标注@ResponseBody注解返回JSON数据的处理的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。