首页 > 其他分享 >主动写入流对@ResponseBody注解的影响

主动写入流对@ResponseBody注解的影响

时间:2023-09-19 12:16:16浏览次数:40  
标签:map Map 代码 写入 ResponseBody 流对 response out

问题回溯

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<String, Object> doBatchWareSetAd(@RequestParam MultipartFile file, HttpServletResponse response) {
	return wareBatchBusiness.doBatchWareSetAd(file, response, getLongOrgCode(), getCurrentUserPin(), getCurrentUserId());
}

上线的结果是;仍然无法使用。

其实也正常:因为两种代码在预发布都可以正常运行,在线上出错只可能是因为其他原因,只不过我们不了解底层原理,害怕它 "可能" 有问题罢了,最终查询得到的结论是权限系统管理员在线上环境没有给我们配置相应的文件,导致请求为空,导致请求失败。

探索 @ResponseBody 与主动写入流的关系

我们都知道 @ResponseBody 注解可以帮助我们把返回对象转化为JSON,方便展示和交互。

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

代码案例1:

@RequestMapping("/test1")
@ResponseBody
public Map<String, String> test1(HttpServletResponse response) {
    Map<String, String> 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记录如图所示:

后续内容可以想象,肯定还有地方去把流按照指定的HEADER写入,因为和本文无关所以不深究。

再来看代码案例2:

@RequestMapping("/test2")
@ResponseBody
public Map<String, String> test2(HttpServletResponse response) throws IOException {
    Map<String, String> 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源码截图

可以发现Spring对这种方式操作文件流视作异常情况,然后抛出,在后续逻辑中完成整个请求,简单来说就是 @ResponseBody 注解没起到任何作用。

因此答案呼之欲出:当时功能不可用的罪魁祸首就是相关人员没有配置参数导致,与写法没有任何关系。

结论与启发

结论:

  1. 我们要相信自己的代码,至少是要相信已经经过测试的代码。
  2. 在委托他人或者自己配置环境参数,如权限、ZK等每次都保证预发布和线上同时配置,避免遗漏的情况。

启发:

聊了这么多,那我们这种类似场景的代码应该怎么写?

既然主动写入流会解除@ResponseBody的作用,反之又能发挥它的作用,那我们最佳方案是不是如下所示?

@RequestMapping("/test1")
@ResponseBody
public Map<String, String> test1(HttpServletResponse response) {
    Map<String, String> 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;
}

如此一来,当发生预期之外的情况,我们有非常明显的报错提示,当正常时又可以完美实现功能,妙哉(我觉得)~

作者:京东零售 柯贤铭

来源:京东云开发者社区 转载请注明来源

标签:map,Map,代码,写入,ResponseBody,流对,response,out
From: https://www.cnblogs.com/Jcloud/p/17714263.html

相关文章

  • ES写入数据过程
    ES写入数据,本质是往shard写入数据,过程如下图:近实时的原理(refresh)        ES默认每隔1秒会从内存buffer中的数据写入filesystemcache,这个过程叫做refresh。这也是为什么说ES是近实时搜索的原因,因为数据写入到filesystemcache后才会被搜索到。Elasticsearch提......
  • 主动写入流对@ResponseBody注解的影响 | 京东云技术团队
    问题回溯2023年Q2某日运营反馈一个问题,商品系统商家中心某批量工具模板无法下载,导致功能无法使用(因为模板是动态变化的)商家中心报错(JSON串):{"code":-1,"msg":"失败"}负责的同事看到失败后立即与我展开讨论(因为不是关键业务,所以不需要回滚,修复即可),我们发现新功能模板下载的代码与之前......
  • python测试用例数据驱动(读取写入excel)
    Python中处理excel数据的模块非常多,比如:xlxd(只读)、xlwd(只写)、openpyxl(可读写)Excel文件和下面的py文件代码一定要在同一个文件夹内,不然需要指定具体的Excel文件路径注意:excel文件为xlsx,不能是xls再转换成xlsx格式的文件,会报错fromopenpyxlimportload_workbookcl......
  • 图片数据写入excel
    importjson#importpandasaspdfromopenpyxlimportWorkbookfromopenpyxl.drawing.imageimportImageexcel_col_map={1:"A",2:"B",3:"C",4:"D",5:"E",6:"F",......
  • 修改pip配置文件pip.ini显示权限不足,无法写入时该如何解决
    如题,尝试修改pip配置pip3configsetglobal.index-urlhttps://pypi.tuna.tsinghua.edu.cn/simple时出现如下报错: WritingtoC:\ProgramFiles\WindowsApps\PythonSoftwareFoundation.Python.3.7_3.7.2544.0_x64__qbz5n2kfra8p0\pip.iniERROR:Unabletosaveconfigura......
  • sqlserver存储过程报错:当前事务无法提交,而且无法支持写入日志文件的操作。请回滚该事
    ​ ​编辑 现象:系统出现异常,手动执行过程提示如上。  问题排查:1.直接执行的过程事务挂起(排除)2.重启数据库实例(重启后无效)3.过程中套用过程,套用的过程中使用事务,因为插入的表结构字段超出最大长度(修改表结构问题恢复) 结论:事务执行失败,嵌套层级太深。  ​......
  • 20230914-python爬取数据写入到excel
    python爬取数据写入到excel1。查看是否安装了相应的插件 piplist2。查看是否安装了  pandas     (安装命令在cmd中安装,pipinstallpandas)3。查看是否安装 openpyxl      pipinstallopenpyxl ####写入excelimportpandasaspddf=pd.DataFra......
  • 关于批量写入数据库
    今天上午写个程序要将几张表内的数据读出写入一张表(2w多数据),开始没有使用批处理(每条写入都自动commit),写入速度在分钟级(太慢了后来就没计时),后来添加了批处理(不自动commit),全部用时20多秒。可见批处理写入数据库要快很多。程序大致结构如下:EntityManagerem=JPA.em();em.setFlus......
  • tyoora 写入注册表创建快捷方式到Windows右键新建栏
    注意,编码方式不要采用utf-8编码,否则会有中文乱码解决方法,使用ANSI编码,保存文件为.reg格式,双击运行,给权限运行新建栏目即生成可新建的Markdown文档文件WindowsRegistryEditorVersion5.00[HKEY_CLASSES_ROOT\.md]@="Typora.exe"[HKEY_CLASSES_ROOT\.md\ShellNew]......
  • ArrayList/MySQL数据批量写入Excel表格
    ArrayList/MySQL数据集合写入Excel1.文章概述:写入Excel文件通常需要使用一些库或工具,而"EasyExcel"通常是指的阿里巴巴开源的EasyExcel库。这个库可以让我们在Java中简便地进行Excel文件的读写操作。2.导入配置:<dependency><groupId>com.alibaba</group......