当前位置: 首页 > news >正文

SpringCloud 下 MultipartFile 序列化(JSON)出错的解决方案

1、需求

在SpringCloud架构下,用户向客户端上传文件,客户端调用文件处理微服务去处理文件

2、问题

客户端文件处理服务间传递文件时,想直接把 MultipartFile 转为 json,但出现异常。

在这里插入图片描述

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class java.io.FileDescriptor]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class java.io.FileDescriptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile["inputStream"]->java.io.FileInputStream["fd"])] with root cause

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class java.io.FileDescriptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile["inputStream"]->java.io.FileInputStream["fd"])

分析:客户端接收到的是 MultipartFile 文件;要把文件传给文件处理微服务,但直接把 MultipartFile 传给文件服务是不行的。 MultipartFile 不能序列化(或者比较麻烦);

有人说在实体类上加注解,忽略掉MultipartFile属性;@JSONField(serialize = false),但是我的实体类没有 MultipartFile 属性。

经过一番查找,找到了一个合适的解决方案。

3、解决方案

3.1、原理图

在这里插入图片描述

  • 客户端接收到 MultipartFile 文件

  • 通过 MultipartFilegetBytes() 方法转为 byte[] 数组

  • 通过 Base64 工具类把 byte[] 数组转为 Base64字符串,并发送给 文件处理服务

  • 文件处理服务收到 Base64字符串时,再用 Base64 工具类把 字符串转为 byte[] 数组

  • byte[] 作为输入流,从中读取数据,写入输出流,完成文件的存储

3.2、实现步骤

1)MultipartFile 转 byte[]

客户端接收到客户上传的MultipartFile文件

 @PostMapping("/add")
 public String add(
     @RequestParam("file") MultipartFile file
 ) {
     // ...
     byte[] bytes = file.getBytes();
     // 同时获取文件类型;实现步骤省略...
     String fileType = file.getOriginalFilename()...
     // ...
 }

2)byte[] 转 Base64 字符串

工具类 org.apache.tomcat.util.codec.binary.Base64

byte[] 转为字符串后,可以发送给 文件处理服务,同时把文件类型也一起发送;因为从 byte[] 中解析文件类型比较麻烦

String bytesStr = Base64.encodeBase64String(bytes);

3)Base64 字符串 转 byte[]

文件处理服务 收到 字符串后,再转为 byte[]

byte[] bytes = Base64.decodeBase64(bytesStr);

4)从 byte[] 中读取文件并保存

    /**
     * 保存 byte[] 形式的文件
     * @param bytesOfFile 以 byte[] 形式存储的文件
     * @param fileType 文件类型
     * @param saveDir 存储目录
     * @return
     */
    public static String saveFileByBytes(
            byte[] bytesOfFile,
            String fileType,
            String saveDir){

        // 输入流
        BufferedInputStream bis = null;
        // 输出流
        BufferedOutputStream bos = null;

        String fileName = "";
        try {
            // 输入流
            bis = new BufferedInputStream(new ByteArrayInputStream(bytesOfFile));
            // 输出流
            // --- 新文件(名 + 类型);雪花算法省略...
            fileName = SnowflakeUtil.getInstance().nextId() + "." + fileType;
            bos = new BufferedOutputStream(new FileOutputStream(new File(saveDir, fileName)));
            int readLen;
            byte[] buf = new byte[8192];
            while ((readLen = bis.read(buf)) > -1) {
                bos.write(buf, 0, readLen);
            }
        } catch (IOException e) {
            e.printStackTrace();
            log.info("文件存储异常!");
            return "_err";
        } finally {
            // 关闭
            try {
                if (bis != null) {
                    bis.close();
                }
                if (bos != null) {
                    bos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        // 返回保存后的文件名
        return fileName;
    }

相关文章:

  • MIKE水动力笔记12_数字化海图1之提取确值水深点
  • 【CSDN创作话题 】丨 竞赛那些事
  • 2022年S1000D和ATA用户大会资料
  • Vulnhub Empire Lupin One渗透测试
  • java教程之高性能并发计数器之巅峰对决
  • 机器学习实战(6)——决策树
  • 第二十四节 SpringBoot使用spring.factories
  • 产业互联网,正在进入到深水区,人们对于产业互联网的认识才能够全面
  • Vite创建Vue2项目
  • 瑞芯微 Rockchip RKNN-Toolkit 环境搭建
  • python 函数相关概念
  • 为何海量计算机系毕业生“负债”报IT培训班?高校IT教育该如何变革?
  • 超详细Redis入门教程二
  • Java_网络多线程
  • Ubuntu系统启动异常【ACPI Error或重启黑屏或启动异常】
  • JS 中的深拷贝与浅拷贝
  • 2017-08-04 前端日报
  • centos安装java运行环境jdk+tomcat
  • JavaScript学习总结——原型
  • Java多态
  • Java新版本的开发已正式进入轨道,版本号18.3
  • Laravel5.4 Queues队列学习
  • linux安装openssl、swoole等扩展的具体步骤
  • oldjun 检测网站的经验
  • Vue.js 移动端适配之 vw 解决方案
  • 代理模式
  • 工作踩坑系列——https访问遇到“已阻止载入混合活动内容”
  • 互联网大裁员:Java程序员失工作,焉知不能进ali?
  • 基于OpenResty的Lua Web框架lor0.0.2预览版发布
  • 利用阿里云 OSS 搭建私有 Docker 仓库
  • 如何优雅的使用vue+Dcloud(Hbuild)开发混合app
  • 使用API自动生成工具优化前端工作流
  • 我这样减少了26.5M Java内存!
  • 携程小程序初体验
  • 新版博客前端前瞻
  • Spark2.4.0源码分析之WorldCount 默认shuffling并行度为200(九) ...
  • 微龛半导体获数千万Pre-A轮融资,投资方为国中创投 ...
  • ​人工智能之父图灵诞辰纪念日,一起来看最受读者欢迎的AI技术好书
  • #pragma data_seg 共享数据区(转)
  • #Z0458. 树的中心2
  • #我与Java虚拟机的故事#连载04:一本让自己没面子的书
  • $.extend({},旧的,新的);合并对象,后面的覆盖前面的
  • (16)Reactor的测试——响应式Spring的道法术器
  • (9)STL算法之逆转旋转
  • (附源码)spring boot公选课在线选课系统 毕业设计 142011
  • (附源码)springboot社区居家养老互助服务管理平台 毕业设计 062027
  • (经验分享)作为一名普通本科计算机专业学生,我大学四年到底走了多少弯路
  • (六)激光线扫描-三维重建
  • (删)Java线程同步实现一:synchronzied和wait()/notify()
  • (五)IO流之ByteArrayInput/OutputStream
  • (一)VirtualBox安装增强功能
  • (原創) 人會胖會瘦,都是自我要求的結果 (日記)
  • (转)Sublime Text3配置Lua运行环境
  • (转)人的集合论——移山之道
  • (最优化理论与方法)第二章最优化所需基础知识-第三节:重要凸集举例