使用Spring进行文件的上传和下载

概览

  • 使用Spring进行文件的上传和下载
    • Spring上传文件接口设计
    • dubbo接口设计
      • 上传文件流的RPC的接口设计
    • Spring文件下载接口设计
    • dubbo接口设计
      • 下载文件流的RPC的接口设计
    • spring上传文件大小控制

使用Spring进行文件的上传和下载

本文主要介绍在Spring框架下面调用微服务的dubbo rpc接口进行文件的上传和下载,以及记录在实现过程中遇到的一些容易出错的地方。

Spring上传文件接口设计

contoller层的代码实现如下所示:

    @PostMapping("/submitEvidence")public BaseResponse<?> submitEvidence(@RequestParam("id") Long id, @RequestParam("label") String label,@RequestParam(value = "file") MultipartFile file) {uploadEvidence(id, label, file);return BaseResponse.success().errorMsg("操作成功").build();}}

使用postman请求上传文件接口,具体参数如下图所示:postman请求截图
Service层代码实现如下所示:

public void uploadEvidence(Long takeDownId, String label, MultipartFile multipartFile) {if(Objects.isNull(multipartFile)) {throw new RunTimeException("上传的文件不能为空");}String fileName = multipartFile.getOriginalFilename();InputStream file = null;try {file = multipartFile.getInputStream();} catch (IOException e) {}byte[] fileBytes = new byte[20 * 1024 * 1024];InputStream inputStream = null;ByteArrayOutputStream outputStream = null;try {outputStream =  new ByteArrayOutputStream();inputStream = multipartFile.getInputStream();try {byte[] buffer = new byte[1024];int read = inputStream.read(buffer);while (read != -1) {outputStream.write(buffer, 0, read);read = inputStream.read(buffer);}} catch (Exception e) {log.error("处理返回值失败" + e.getMessage());throw new RunTimeException("上传文件失败");} finally {try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}outputStream.flush();fileBytes = outputStream.toByteArray();} catch (IOException e) {}finally {if(outputStream != null) {try {outputStream.close();} catch (IOException e1) {e1.printStackTrace();throw new RuntimeException("上传文件失败");}}}UploadEvidenceNetCraftReq req = UploadEvidenceNetCraftReq.builder().takeDownId(takeDownId.intValue()).label(label).fileName(fileName).fileBytes(fileBytes).build();// outVendor是一个dubbo框架下的rpc服务,用于上传文件BaseResponse baseResponse = outerVendorsService.uploadEvidence(req);...}

dubbo接口设计

上传文件流的RPC的接口设计

我们构建的RPC接口采用的是dubbo框架,最初始的接口设计,将HttpServletResponse作为接口的参数类型传参,结果报错
io.netty.handler.codec.EncoderException: java.lang.IllegalStateException: Serialized class

Dubbo报错:io.netty.handler.codec.EncoderException: java.lang.IllegalStateException: Serialized class

HttpServletResponse不能被dubbo作为接口参数序列化,于是转而求其次,将可序列化的类型byte[]作为传输流的参数
outerVendorsService服务提供的上传文件的rpc接口:uploadEvidence接口,具体代码设计如下所示:

BaseResponse<UploadEvidenceRsp> uploadEvidence(UploadEvidenceReq req);
@Data
@Builder
@Jacksonized
public class UploadEvidenceReq implements Serializable {private Integer takeDownId;//使用可序列化的byte数组作为入参private byte[] fileBytes;private String fileName;private String label;
}@Data
@Setter
@Getter
public class UploadEvidenceRsp implements Serializable {private Integer file_id;@JsonProperty("error_code")private String errorCode;@JsonProperty("error_message")private String errorMessage;
}

Spring文件下载接口设计

文件下载的相关接口有两种实现:一种是将HttpServletResponse作为controller层的传参引入,将流写入到HttpServletResponse中,然后返回前端,但是在使用过程中,直接在HttpServletResponse的示例中setHeader失败,于是转而选择构ResponseEntity的方式来进行http返回值的构造,具体实现如下所示:

@GetMapping("/searchForEvidence")
public ResponseEntity searchForEvidence(@RequestParam String id) {return searchForEvidence(id);
}

使用postman请求下载文件接口,具体参数如下图所示:
下载文件接口
Service层代码实现如下所示:

public ResponseEntity fetchEvidence(Long takeDownId){FetchEvidenceNetCraftReq req = FetchEvidenceNetCraftReq.builder().takeDownId(takeDownId.intValue()).build();BaseResponse<QueryEvidenceRsp> rsp = outerVendorsService.fetchEvidence(req);if(Objects.isNull(rsp)) {throw new RunTimeException("拉取文件失败");}byte[] outPutBytes = null;if(Objects.nonNull(rsp) && rsp.isSuccess() == true) {QueryEvidenceRsp evidenceRsp = rsp.getResult();if(Objects.nonNull(evidenceRsp.getErrorCode())){String message = "errorCode:" + evidenceRsp.getErrorCode() + ",errorMessage:" + evidenceRsp.getErrorMessage();throw new RunTimeException(message);}outPutBytes = evidenceRsp.getFileBytes();String fileName = evidenceRsp.getFileName();HttpHeaders responseHeaders = new HttpHeaders();responseHeaders.setContentType(MediaType.valueOf(MediaType.APPLICATION_OCTET_STREAM_VALUE));// 设置文件格式responseHeaders.setContentLength(outPutBytes.length);responseHeaders.set("Content-Disposition", "attachment;filename=" + fileName);// 设置文件名return new ResponseEntity<>(outPutBytes, responseHeaders, HttpStatus.OK);}throw new RunTimeException("拉取文件失败");
}public class QueryEvidenceRsp implements Serializable {byte[] fileBytes;String fileName;String errorCode;String errorMessage;
}

dubbo接口设计

下载文件流的RPC的接口设计

参照之前的上传文件的设计,服务提供的下载文件的rpc接口设计:

@Data
@Setter
@Getter
public class QueryEvidenceRsp implements Serializable {byte[] fileBytes;String fileName;String errorCode;String errorMessage;
}@Data
@Builder
@Jacksonized
public class FetchEvidenceNetCraftReq implements Serializable {private Integer takeDownId;
}@Overridepublic BaseResponse fetchEvidence(FetchEvidenceNetCraftReq req) {if(Objects.isNull(netCraftConfig) || Objects.isNull(netCraftConfig.getAccessNetCraftDomain())) {log.error("netCraft config is not set");return BaseResponse.fail().errorCode(ErrorCode.BUSINESS_EXCEPTION.getCode()).errorMsg("netCraft config is not set").build();}String fetch_evidence = "https://" + netCraftConfig.getAccessNetCraftDomain()+ netCraftConfig.getFETCH_EVIDENCE();Map<String, String> headers = new HashMap<>();headers.put("content-type", "application/json");headers.put("Authorization", netCraftConfig.getAccessNetCraftAuthToken());ByteArrayOutputStream  outputStream = new ByteArrayOutputStream();byte[] fileBytes;String fileName;try {outputStream =  new ByteArrayOutputStream();fileName = getFromOctetStream(fetch_evidence + "?takedown_id="+ req.getTakeDownId(), headers, outputStream);if(Objects.isNull(fileName)) {return BaseResponse.fail().errorCode(ErrorCode.BUSINESS_EXCEPTION.getCode()).errorMsg("获取netcraft证据文件失败").build();}outputStream.flush();fileBytes = outputStream.toByteArray();} catch (Exception e) {log.error("获取证据文件失败:" + e.getMessage());return BaseResponse.fail().errorCode(ErrorCode.BUSINESS_EXCEPTION.getCode()).errorMsg("获取netcraft证据文件失败").build();} finally {if(outputStream != null) {try {outputStream.close();} catch (IOException e1) {e1.printStackTrace();}}}NetCraftQueryEvidenceRsp rsp = new NetCraftQueryEvidenceRsp();if(Objects.nonNull(fileName)) {NetCraftErrorMessageRsp errorMessageRsp = JsonUtils.fromCamelJson(fileName, NetCraftErrorMessageRsp.class);if(Objects.nonNull(errorMessageRsp)&& Objects.nonNull(errorMessageRsp.getErrorCode())&& Objects.nonNull(errorMessageRsp.getErrorMessage())) {rsp.setErrorCode(errorMessageRsp.getErrorCode());rsp.setErrorMessage(errorMessageRsp.getErrorMessage());return BaseResponse.success(rsp).build();}rsp.setFileBytes(fileBytes);rsp.setFileName(fileName);return BaseResponse.success(rsp).build();}return BaseResponse.fail().errorCode(ErrorCode.BUSINESS_EXCEPTION.getCode()).errorMsg("获取netcraft证据文件失败").build();}public static String getFromOctetStream(String url, Map<String, String> headers, OutputStream outputStream) {return getFromOctetStream(url, headers, OK_HTTP_CLIENT_30s, outputStream);}public static String getFromOctetStream(String url, Map<String, String> headers, String client, OutputStream outputStream) {Request.Builder requestBuilder = new Request.Builder();requestBuilder.url(url);if (headers != null && headers.size() > 0) {for (String s : headers.keySet()) {requestBuilder.addHeader(s, headers.get(s));}}requestBuilder.get();Request req = requestBuilder.build();try (Response response = okHttpClientMap.get(client).newCall(req).execute()) {log.info("okhttp send get,resp:{}", JsonUtils.toJson(response));if (null != response.body()) {InputStream inputStream = response.body().byteStream();try {byte[] buffer = new byte[1024];int read = inputStream.read(buffer);while (read != -1) {outputStream.write(buffer, 0, read);read = inputStream.read(buffer);}} catch (Exception e) {log.error("处理返回值失败" + e.getMessage());return null;} finally {try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}String contentDisposition = response.header("Content-Disposition");if (Objects.isNull(contentDisposition)) {log.error("调用netcraft获取证据接口, 获取文件名失败");return outputStream.toString();}// 解析文件名return contentDisposition.substring(contentDisposition.indexOf("filename=") + 9);}

spring上传文件大小控制

在spring配置文件application.properties中,通过配置下面两个参数的值来限制文件的大小

spring.servlet.multipart.max-file-size=-1
spring.servlet.multipart.max-request-size=-1

spring.servlet.multipart.max-file-size配置限制上传单个文件的大小,为-1代表不限制
spring.servlet.multipart.max-request-size配置限制http中上传总文件的大小,为-1代表不限制

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/1149.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode36: 有效的数独(Java)

题目&#xff1a; 请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 &#xff0c;验证已经填入的数字是否有效即可。 数字 1-9 在每一行只能出现一次。数字 1-9 在每一列只能出现一次。数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。&#xff08;请参考示例…

一次Ambari安装记录

引言 Ambari是一个开源的Apache项目,它提供了一个直观易用的Web界面,用于管理、监控和配置Apache Hadoop集群。它是一个集群管理工具,可以帮助管理员轻松地部署、管理和监控Hadoop集群的各种组件,如HDFS、YARN、MapReduce、Hive、HBase等。通过Ambari,用户可以在集群中添…

OerOerlikonTCO1200欧瑞康LPCVD system操作使用说明

OerOerlikonTCO1200欧瑞康LPCVD system操作使用说明

DQ-DETR: DETR WITH DYNAMIC QUERY FOR TINY OBJECTDETECTION 学习笔记

论文地址&#xff1a;https://arxiv.org/pdf/2404.03507.pdf 此DQ-DETR与IDEA提出的同名&#xff0c;该文主要集中于小目标的检测 尽管之前的类似DETR的方法在通用目标检测中取得了成功&#xff0c;但在小目标检测方面仍然具有挑战性&#xff0c;因为目标 Query 的位置信息并未…

LWIP开启ARP之后进入硬件错误中断

遇到个很奇怪的问题&#xff0c;如下图只要开启ARP之后&#xff0c;就会进入硬件错误中断&#xff0c;关掉就好了。 而无法开启ARP&#xff0c;就不能ping 通&#xff0c;所以必须要解决这个问题。 最终debug发现死在memcpy函数位置 这样原因就很好分析了&#xff0c; 共4个拷…

通过linux工具iftop命令查看视频监控平台是否收到监控摄像头的视频流(视频监控平台接收和转发的视频流)

目录 一、需求描述 二、解决思路 &#xff08;一&#xff09;问题分析 &#xff08;二&#xff09;解决思路 1、通过抓包的方式 2、通过一些linux的网络监视工具 三、需求实现 &#xff08;一&#xff09;抓包工具 1、tcpdump 2、Wireshark 3、tcptrace &#xff0…

【刷题】 二分查找进阶

送给大家一句话&#xff1a; 你向神求助是因为相信神&#xff0c;神没有回应你是因为神相信你 ε≡٩(๑>₃<)۶ &#xfeff;ε≡٩(๑>₃<)۶ &#xfeff;ε≡٩(๑>₃<)۶ 一心向学 二分查找进阶 1 前言Leetcode 852. 山脉数组的峰顶索引题目描述算法思…

【EtherCAT】FMMU和SM简介

目录 一、简介 1、 FMMU 2、SM (1) 缓冲模式 (2)邮箱模式 3、FMMU将物理存储器映射到逻辑过程数据映射的配置原理 二、FMMU和SM在EtherCAT从站控制器的存储空间分配 三、FMMU和SM部分寄存器描述(LAN9253) 1、FMMU 2、SM 四、FMMU和SM的数据结构&#xff08;soem主站&…

什么是AIoT?

什么是AIoT? AIoT&#xff0c;即人工智能物联网&#xff0c;是一种将人工智能&#xff08;AI&#xff09;技术与物联网&#xff08;IoT&#xff09;相结合的新型应用形态。它不仅实现了设备之间的互联互通&#xff0c;还赋予了它们更智能化的特性。AIoT的核心在于通过AI的数据…

什么是知乎知+广告推广?

知乎作为中国领先的知识分享社区和高质量用户群体汇聚地&#xff0c;其广告价值日益凸显&#xff0c;其中&#xff0c;“知”作为知乎官方推出的创新广告形式&#xff0c;正逐渐成为品牌与消费者深度连接的重要桥梁。知广告推广不仅局限于传统意义上的硬性推广&#xff0c;更强…

解锁棋盘之谜:探索N皇后问题的全方位解决策略【python 力扣51题】

作者介绍&#xff1a;10年大厂数据\经营分析经验&#xff0c;现任大厂数据部门负责人。 会一些的技术&#xff1a;数据分析、算法、SQL、大数据相关、python 欢迎加入社区&#xff1a;码上找工作 作者专栏每日更新&#xff1a; LeetCode解锁1000题: 打怪升级之旅 python数据分析…

前后端跨域请求代码实战(vue3.4+springboot2.7.18)

前端代码 v3.4.21&#xff08;前端不是主业&#xff0c;所以就贴一贴代码&#xff0c;有疑问评论区见&#xff09;后端代码&#xff0c;springboot 2.7.18&#xff08;后端&#xff09; 文章内容&#xff1a; 一&#xff0c;后端代码 二&#xff0c;前端代码 三&#xff0c;后…

【ARM 裸机】I.MX 启动方式之启动头文件 1

接上一节&#xff1a;【ARM 裸机】I.MX 启动方式之启动设备的选择&#xff1b; 2、启动头文件 当 BOOT_MODE1 为 1&#xff0c;BOOT_MODE0 为 0 的时候此内部 BOOT 模式&#xff0c;在此模式下&#xff0c;芯片会执 行内部的 BOOT ROM 代码&#xff0c;这段 BOOT ROM 代码会进…

tensor是pytorch的核心,那torch.tensor和torch.Tensor区别是?

本文重点 从本节课程开始我们将正式开启pytorch的学习了&#xff0c;在深度学习框架中有一个重要的概念叫做张量&#xff0c;它是pytorch的基本操作单位&#xff0c;要想创建tensor有很多的方式&#xff0c;但是有两个torch.tensor和torch.Tensor容易混淆&#xff0c;本节课程…

javase__进阶 day13stream流和方法引用

1.不可变集合 1.1 什么是不可变集合 ​ 是一个长度不可变&#xff0c;内容也无法修改的集合 1.2 使用场景 ​ 如果某个数据不能被修改&#xff0c;把它防御性地拷贝到不可变集合中是个很好的实践。 ​ 当集合对象被不可信的库调用时&#xff0c;不可变形式是安全的。 简单…

大厂面试精华面试刷题

1.自定义unshift实现相同效果 2.数组去重 用vs2019来写这种练习题可以更直观的查看代码执行的效果&#xff0c;最后的代码是控制控制台执行完毕后不自动关闭 use strict;let arr [1, 1, 2, 2, 3, 3, 4, 5, 6, 7, 8, 9, 10] //1.//查重最简单的方法for循环结合splice从数组中…

【C++】飞机大战项目记录

源代码与图片参考自《你好编程》的飞机大战项目&#xff0c;这里不进行展示。 本项目是仅供学习使用的项目 飞机大战项目记录 飞机大战设计报告1 项目框架分析1.1 敌机设计&#xff1a;1.2 玩家飞机控制&#xff1a;1.3 子弹发射&#xff1a;1.4 游戏界面与互动&#xff1a;1.5…

解决Linux根分区空间不足的方法:利用Home分区进行扩容

前言 在进行系统安装时&#xff0c;一个常见的困扰是默认分区设置可能导致home分区拥有过多的空间&#xff0c;而root分区却显得十分紧缺。这种情况下&#xff0c;用户往往会陷入无法继续安装软件或存储文件的困境。本文将向您展示如何通过合理的调整&#xff0c;将home分区中多…

【6】mysql查询性能优化-关联子查询

【README】 0. 先说结论&#xff1a;一般用inner join来改写in和exist&#xff0c;用left join来改写not in&#xff0c;not exist&#xff1b;&#xff08;本文会比较内连接&#xff0c;包含in子句的子查询&#xff0c;exist的性能 &#xff09; 1. 本文总结自高性能mysql 6…

Python 面向对象——1.基本概念

本章学习链接如下&#xff1a; 基本概念与语法 类&#xff08;Class&#xff09;&#xff1a;定义了一组对象共有的属性和方法的蓝图。类是创建对象的模板。 对象&#xff08;Object&#xff09;&#xff1a;类的实例。对象包含实际的数据和操作数据的方法。 属性&#xff0…