精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

主動寫入流對@ResponseBody注解的影響

京東云 ? 來源:京東零售 柯賢銘 ? 作者:京東零售 柯賢銘 ? 2024-10-29 11:28 ? 次閱讀

作者:京東零售 柯賢銘

問題回溯

2023年Q2某日運營反饋一個問題,商品系統商家中心某批量工具模板無法下載,導致功能無法使用(因為模板是動態變化的)

商家中心報錯(JSON串):

{"code":-1,"msg":"失敗"}

?

負責的同事看到失敗后立即與我展開討論(因為不是關鍵業務,所以不需要回滾,修復即可),我們發現新功能模板下載的代碼與之前的代碼有所不同,恰好之前的功能又可以正常運行,所以同事對現有代碼進行改造然后預發布測試完成后再次上線。

?

其他業務代碼:

/**
 * 模板下載
 */
@RequestMapping("/doBatchWareSetAd")
public void doBatchWareSetAd(@RequestParam MultipartFile file, HttpServletResponse response) {
	wareBatchBusiness.doBatchWareSetAd(file, response, getLongOrgCode(), getCurrentUserPin(), getCurrentUserId());
}

?

問題業務代碼:

/**
 * 模板下載
 */
@RequestMapping("/doBatchWareSetAdDemo")
@ResponseBody
public Map doBatchWareSetAd(@RequestParam MultipartFile file, HttpServletResponse response) {
	return wareBatchBusiness.doBatchWareSetAd(file, response, getLongOrgCode(), getCurrentUserPin(), getCurrentUserId());
}

?

上線的結果是;仍然無法使用。

其實也正常:因為兩種代碼在預發布都可以正常運行,在線上出錯只可能是因為其他原因,只不過我們不了解底層原理,害怕它 "可能" 有問題罷了,最終查詢得到的結論是權限系統管理員在線上環境沒有給我們配置相應的文件,導致請求為空,導致請求失敗。

?

探索 @ResponseBody 與主動寫入流的關系

我們都知道 @ResponseBody 注解可以幫助我們把返回對象轉化為JSON,方便展示和交互。

那它到底是如何工作的呢,請看下面的講解:

?

代碼案例1:

@RequestMapping("/test1")
@ResponseBody
public Map test1(HttpServletResponse response) {
    Map map = new HashMap();
    map.put("1", "1");
    return map;
}

// 響應
JSON報文

?

跟代碼發現其核心處理類為:RequestResponseBodyMethodProcessor.java

方法:org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor#handleReturnValue 會處理其相關返回值。

真正的核心處理方法:org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor#writeWithMessageConverters

關鍵DEBUG記錄如圖所示:

wKgaoWcgVl6ASzeIAACPuUuQfBA158.png

?

后續內容可以想象,肯定還有地方去把流按照指定的HEADER寫入,因為和本文無關所以不深究。

?

再來看代碼案例2:

@RequestMapping("/test2")
@ResponseBody
public Map test2(HttpServletResponse response) throws IOException {
    Map map = new HashMap();
    map.put("1", "1");

    response.setContentType("application/vnd.ms-excel");
    response.setHeader("Content-Disposition", String.format(
        "attachment; filename=%s_%s.xls", "Demo", System.currentTimeMillis()));

    OutputStream out = response.getOutputStream();
    out.flush();
    out.close();
    return map;
}

// 響應
提示下載文件

?

關鍵DEBUG源碼截圖:

wKgZoWcgVl-AEfpSAAA2pk7ToUA050.png

wKgaoWcgVmCADqguAAAlKaZXGoY120.png

?

可以發現Spring對這種方式操作文件流視作異常情況,然后拋出,在后續邏輯中完成整個請求,簡單來說就是 @ResponseBody 注解沒起到任何作用。

因此答案呼之欲出:當時功能不可用的罪魁禍首就是相關人員沒有配置參數導致,與寫法沒有任何關系。

?

結論與啟發

結論:

1.我們要相信自己的代碼,至少是要相信已經經過測試的代碼。

2.在委托他人或者自己配置環境參數,如權限、ZK等每次都保證預發布和線上同時配置,避免遺漏的情況。

?

啟發:

聊了這么多,那我們這種類似場景的代碼應該怎么寫?

既然主動寫入流會解除@ResponseBody的作用,反之又能發揮它的作用,那我們最佳方案是不是如下所示?

@RequestMapping("/test1")
@ResponseBody
public Map test1(HttpServletResponse response) {
    Map map = new HashMap();
    if (獲取不到文件配置 == true) {
        return map.put("msg", "獲取不到文件配置");
    }
    
    response.setContentType("application/vnd.ms-excel");
    response.setHeader("Content-Disposition", String.format(
        "attachment; filename=%s_%s.xls", "Demo", System.currentTimeMillis()));

    OutputStream out = response.getOutputStream();
    out.flush();
    out.close();
    return map;
}

?

如此一來,當發生預期之外的情況,我們有非常明顯的報錯提示,當正常時又可以完美實現功能,妙哉(我覺得)~

審核編輯 黃宇

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 代碼
    +關注

    關注

    30

    文章

    4744

    瀏覽量

    68345
  • JSON
    +關注

    關注

    0

    文章

    117

    瀏覽量

    6940
收藏 人收藏

    評論

    相關推薦

    如何通過注解來優化我們的Java代碼

    Java注解可以說是我們編碼過程中最常用的。本篇文章將給大家介紹Java注解的概念、作用以及如何使用注解來提升代碼的可讀性和靈活性,并介紹如何通過注解來優化我們的Java代碼。 1、什
    的頭像 發表于 09-30 11:39 ?593次閱讀

    機種新品導入流

    機種新品導入流
    發表于 08-11 10:08

    redis緩存注解怎么使用

    spring boot —— redis 緩存注解使用教程
    發表于 09-11 14:43

    HarmonyOS注解的使用方法分享

    javax.annotation.processing.Processor 文件寫入注解處理器的全稱,包括包路徑4、使用注解在entry模塊的build.gradle文件中添加依賴dependencies
    發表于 03-28 14:04

    分析java注解基本概念

    什么是注解(Annotation): Annotation(注解)就是Java提供了一種元程序中的元素關聯任何信息和著任何元數據(metadata)的途徑和方法。Annotion(注解)是一個接口
    發表于 09-27 14:53 ?0次下載

    注解定義Bean及開發

    注解本質是一個繼承了Annotation 的特殊接口,其具體實現類是Java 運行時生成的動態代理類。
    發表于 08-02 10:26 ?432次閱讀

    Spring Web MVC注解

    RequestMapping注解的主要用途是將Web請求與請求處理類中的方法進行映射。Spring MVC和Spring WebFlux都通過`RquestMappingHandlerMapping`和`RequestMappingHndlerAdapter`兩個類來提供對@RequestMapping
    的頭像 發表于 04-07 11:32 ?579次閱讀
    Spring Web MVC<b class='flag-5'>注解</b>

    Spring Dependency Inject與Bean Scops注解

    DependsOn`注解可以配置Spring IoC容器在初始化一個Bean之前,先初始化其他的Bean對象。下面是此注解使用示例代碼:
    的頭像 發表于 04-07 11:35 ?661次閱讀
    Spring Dependency Inject與Bean Scops<b class='flag-5'>注解</b>

    容器配置及Spring Boot注解

    Autowired注解用于標記Spring將要解析和注入的依賴項。此注解可以作用在構造函數、字段和setter方法上。
    的頭像 發表于 04-07 11:45 ?558次閱讀
    容器配置及Spring Boot<b class='flag-5'>注解</b>

    Springboot常用注解合集

    前幾章,在系統啟動類里面,都加入了此啟動注解,此注解是個組合注解,包括了`@SpringBootConfiguration`、`@EnableAutoConfiguration`和`@ComponentScan`
    的頭像 發表于 04-07 14:27 ?707次閱讀
    Springboot常用<b class='flag-5'>注解</b>合集

    JAVA中注解是怎么做到的(上)

    注解想必大家在項目中經常使用,比如Spring框架中常用的一些注解:`@Controller`、`@Service`、`@RequestMapping`等等,它是JDK1.5及以后版本引入的一個特性
    的頭像 發表于 05-11 10:57 ?621次閱讀

    JAVA中注解是怎么做到的(下)

    注解想必大家在項目中經常使用,比如Spring框架中常用的一些注解:`@Controller`、`@Service`、`@RequestMapping`等等,它是JDK1.5及以后版本引入的一個特性
    的頭像 發表于 05-11 10:57 ?547次閱讀
    JAVA中<b class='flag-5'>注解</b>是怎么做到的(下)

    springmvc常用5種注解

    SpringMVC是一種基于Java的Web框架,使用注解可以更加方便靈活地開發和管理控制器,實現請求的映射和處理。在SpringMVC中,有許多常用的注解,本文將詳細介紹其中的五種注解,并且詳細
    的頭像 發表于 11-22 16:51 ?811次閱讀

    springboot核心注解

    Spring Boot 是基于 Spring 框架的開源框架,它可以幫助開發者快速構建、部署和運行獨立的、生產級的 Spring 應用程序。Spring Boot 提供了一系列核心注解,這些注解可以
    的頭像 發表于 11-23 09:23 ?493次閱讀

    SpringBoot核心注解由幾個注解組成

    簡化應用程序開發的注解,其中核心注解包括 @SpringBootApplication、@RestController、@RequestMapping、@Autowired、@ComponentScan
    的頭像 發表于 12-03 15:09 ?703次閱讀