SpringBoot中的上传文件接口

SpringBoot中的上传文件

上传文件的操作在有些功能中属于比较常用的环节,这里整理下SpringBoot环境中上传文件的实现方式。

这里实现的是上传文件的后台接口,前端部分可以用测试工具模拟实现,就先不在这里表述了。

Dto层

使用MultipartFile类型的变量来接收文件

package com.bbzd.business.file.entity.fileService.dto;

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.web.multipart.MultipartFile;

import javax.validation.constraints.*;

/**
 * Description:
 * Copyright: Copyright (c) 2013
 * Company: www.bbzd.com
 *
 * @author wangjianzhong
 * @version 1.0
 */
@Data
public class UploadFileDto {

    /**
     * 文件组令牌
     */
    @ApiModelProperty(value = "文件组令牌")
    @NotBlank(message = "文件组令牌不能为空")
    private String token;

    /**
     * 文件
     */
    @ApiModelProperty(value = "文件")
    @NotNull(message = "文件不能为空")
    private MultipartFile file;

    /**
     * 用户代码
     */
    @ApiModelProperty(value = "用户代码")
    @NotBlank(message = "用户代码不能为空")
    private String userCode;

    /**
     * 用户名
     */
    @ApiModelProperty(value = "用户名")
    @NotBlank(message = "用户名不能为空")
    private String userName;

    /**
     * 搜素标识符
     */
    @ApiModelProperty(value = "搜素标识符")
    private String searchIdentifier;

    /**
     * 备注
     */
    @ApiModelProperty(value = "备注")
    private String remark;
}
Controller层

请求类型 POST
参数类型 MediaType.MULTIPART_FORM_DATA_VALUE

package com.bbzd.business.file.controller;

import com.bbzd.business.file.entity.fileService.dto.UploadFileDto;
import com.bbzd.business.file.service.FileService;
import com.bbzd.common.annotation.LogAnnotation;
import com.bbzd.common.base.Result;
import com.bbzd.common.enums.LogOperateTypeEnum;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * Title: FileServiceController
 * Description:
 * Copyright: Copyright (c) 2013
 * Company: www.bbzd.com
 *
 * @author wangjianzhong
 * @version 1.0
 */
@RestController
@RequestMapping("/webApi/file/fileService")
@Api(tags = "file-fileService-文件服务")
public class FileServiceController {

    @Resource
    FileService fileService;

    /**
     * @method: 查询文件信息列表
     * @author wangjianzhong
     * @date 2024/03/05
     */
    @PostMapping(value = "/upload",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    @ApiOperation(value = "上传文件", notes = "上传文件")
    @LogAnnotation(operationType = LogOperateTypeEnum.ADD, operateContent = "上传文件")
    public Result<?> pageData(@Validated UploadFileDto dto){
        return fileService.saveFile(dto);
    }
}

Service层

代码有些臃肿,有时间再简化下,本质就是:
将文件转换为字节,再用输出流输出下就可以了

package com.bbzd.business.file.service.impl;

import com.bbzd.business.bsi.audao.MbgBsiParamMapper;
import com.bbzd.business.bsi.model.auGened.MbgBsiParam;
import com.bbzd.business.file.audao.MbgBsiFileGroupMapper;
import com.bbzd.business.file.audao.MbgBsiFileMapper;
import com.bbzd.business.file.entity.fileService.dto.UploadFileDto;
import com.bbzd.business.file.model.auGened.MbgBsiFile;
import com.bbzd.business.file.model.auGened.MbgBsiFileExample;
import com.bbzd.business.file.model.auGened.MbgBsiFileGroup;
import com.bbzd.business.file.model.auGened.MbgBsiFileGroupExample;
import com.bbzd.business.file.service.FileService;
import com.bbzd.business.utils.DateUtils;
import com.bbzd.business.utils.FileTokenUtils;
import com.bbzd.business.utils.StringUtils;
import com.bbzd.common.base.Result;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.stream.Collectors;

/**
 * Description: 文件服务实现
 * Copyright: Copyright (c) 2013
 * Company: www.bbzd.com
 *
 * @author wangjianzhong
 * @version 1.0
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class FileServiceImpl implements FileService {

    @Value("${constant.file.saveRootPath}")
    private String fileSaveRootPath;
    @Value("${constant.file.commonFileDir}")
    private String commonFileDir;
    @Value("${constant.file.bigFileDir}")
    private String bigFileDir;


    private final String fileSeparator= File.separator;

    @Resource
    MbgBsiFileGroupMapper mbgBsiFileGroupMapper;
    @Resource
    MbgBsiFileMapper mbgBsiFileMapper;
    @Resource
    private MbgBsiParamMapper mbgBsiParamMapper;

    private Set<String> suffixSet=new ConcurrentSkipListSet<>();



    public FileServiceImpl(@Qualifier("mbgBsiParamMapper") MbgBsiParamMapper mbgBsiParamMapper) {
        MbgBsiParam param = mbgBsiParamMapper.selectByPrimaryKey("file_bigFile_suffix");
        if(param!=null&&param.getValue()!=null){
            String[] suffixArr=param.getValue().split("\\|");
            Collections.addAll(suffixSet,suffixArr);
        }
    }

    @Scheduled(cron="0 */1 * * * ?")
    public void fresh(){
        MbgBsiParam param = mbgBsiParamMapper.selectByPrimaryKey("file_bigFile_suffix");
        if(param!=null&&param.getValue()!=null){
            suffixSet.clear();
            String[] suffixArr=param.getValue().split("\\|");
            Collections.addAll(suffixSet,suffixArr);
        }
    }

    /**
     * 存储文件
     *
     * @param dto 输入参数
     * @return 结果
     */
    @Override
    public Result saveFile(UploadFileDto dto) {

        //检查输入参数
        String groupToken= dto.getToken();
        MbgBsiFileGroup fileGroup=null;
        MbgBsiFileGroupExample fileGroupExample=new MbgBsiFileGroupExample();
        MbgBsiFileGroupExample.Criteria fileGroupCriteria=fileGroupExample.createCriteria();
        fileGroupCriteria.andGroupNoEqualTo(groupToken);
        List<MbgBsiFileGroup> fileGroupList=mbgBsiFileGroupMapper.selectByExample(fileGroupExample);
        if(!CollectionUtils.isEmpty(fileGroupList)){
            fileGroup=fileGroupList.get(0);
        }
        if(fileGroup==null){
            return Result.fail("无效令牌,禁止操作");
        }

        MultipartFile file=dto.getFile();
        if(file.isEmpty()){
            return Result.fail("文件为空,禁止操作");
        }
        System.out.println("文件名1:"+file.getName());
        System.out.println("文件名2:"+file.getOriginalFilename());
        System.out.println("文件名类型:"+file.getContentType());
        System.out.println("文件大小:"+file.getSize());

        //检查文件空间大小是否满足
        MbgBsiFileExample fileExample=new MbgBsiFileExample();
        MbgBsiFileExample.Criteria fileCriteria=fileExample.createCriteria();
        fileCriteria.andGroupNoEqualTo(fileGroup.getGroupNo());
        List<MbgBsiFile> fileList=mbgBsiFileMapper.selectByExample(fileExample);

        long fileSizeSum=0L;
        if(!CollectionUtils.isEmpty(fileList)){
            fileSizeSum=fileList
                    .stream()
                    .mapToLong(MbgBsiFile::getSize).sum();
        }
        long currFileSize=fileSizeSum+file.getSize();
        if(currFileSize>fileGroup.getMaxFileSize()){
            return Result.fail("文件组空间不够容纳本次上传文件,禁止操作");
        }

        String suffix=StringUtils.getFileSuffix(file.getOriginalFilename());
        String dirTypePath="";
        if(suffixSet.contains(suffix.toUpperCase())){
            dirTypePath=bigFileDir;
        }else{
            dirTypePath=commonFileDir;
        }

        Date now=new Date();
        String dateDir=
            DateUtils.getYearStr(now)+fileSeparator+
            DateUtils.getMonthStr(now)+fileSeparator+
            DateUtils.getDateStr(now);

        String dirPath=fileSaveRootPath+fileSeparator+dirTypePath+fileSeparator+dateDir;

        File dir=new File(dirPath);
        if(!dir.exists()){
            dir.mkdirs();
        }

        String fileName=file.getOriginalFilename();
        String filePath=dirPath+fileSeparator+fileName;

        boolean f=false;
        FileOutputStream out=null;
        try {
            out=new FileOutputStream(filePath);
            out.write(file.getBytes());
            out.flush();
            f=true;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally{
            if(out!=null){
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        if(f){
            MbgBsiFile mbgBsiFile=new MbgBsiFile();
            mbgBsiFile.setFileNo(FileTokenUtils.getFileGroupToken());
            mbgBsiFile.setFileId(FileTokenUtils.getFileGroupToken());
            mbgBsiFile.setPath(filePath);
            mbgBsiFile.setEn(1);
            mbgBsiFile.setFileName(file.getOriginalFilename());
            mbgBsiFile.setVersion(1);
            mbgBsiFile.setUserCode(dto.getUserCode());
            mbgBsiFile.setUserName(dto.getUserName());
            mbgBsiFile.setDateTime(now);
            mbgBsiFile.setUrl("http://XXXXXXXXXXXXX");
            mbgBsiFile.setGroupNo(fileGroup.getGroupNo());
            mbgBsiFile.setSuffix(suffix);
            mbgBsiFile.setSearchIdentifier(dto.getSearchIdentifier());
            mbgBsiFile.setSize(file.getSize());
            mbgBsiFile.setRemark(dto.getRemark());
            mbgBsiFileMapper.insertSelective(mbgBsiFile);

            MbgBsiFileGroup udpFileGroup=new MbgBsiFileGroup();
            udpFileGroup.setId(fileGroup.getId());
            udpFileGroup.setCurrFileSize(currFileSize);
            mbgBsiFileGroupMapper.updateByPrimaryKeySelective(udpFileGroup);
        }


        return Result.success("OK");
    }
}

前端测试

实用工具模拟前端发起请求,工具PostMan
比较简单,截图备忘,记录些要点吧:
请求类型 POST
参数类型 form-data
参数名要与dto中的参数名一致,参数类型是file

在这里插入图片描述

SpringBoot 上传文件大小限制问题及处理

原理:
SpringBoot默认限制单个上传文件的大小为10MB。如果不在项目中作特殊配置的话,当上传的文件超过这个大小时就会报错。

报错示例:

2024-03-07 10:47:35.167 ERROR 44368 --- [nio-8530-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.multipart.MaxUploadSizeExceededException: Maximum upload size exceeded; nested exception is java.lang.IllegalStateException: org.apache.tomcat.util.http.fileupload.impl.SizeLimitExceededException: the request was rejected because its size (40487302) exceeds the configured maximum (10485760)] with root cause

两种解决办法:
1.在配置文件中添加对上传文件大小的配置

spring:
  servlet:
    multipart:
      max-file-size: 500MB
      max-request-size: 500MB

在这里插入图片描述

maxFileSize 是单个文件大小
maxRequestSize 是设置总上传的数据大小

只能是MB和KB两种类型,字母大小写随意,Long类型可以的

参数说明:

# 是否开启文件上传,默认true
spring.servlet.multipart.enabled=true
# 写入磁盘的阈值,默认0
spring.servlet.multipart.file-size-threshold=0
# 上传文件的临时保存位置
spring.servlet.multipart.location=E:\\Gitee\\my-work-space\\chapter01\\tmp
# 单文件上传大小限制
spring.servlet.multipart.max-file-size=1MB
# 多文件上传大小限制
spring.servlet.multipart.max-request-size=10MB
# 文件是否延迟解析,默认false
# 当前文件和参数被访问时是否再解析成文件
spring.servlet.multipart.resolve-lazily=false
  1. 在启动文件中配置上传文件的大小
/**
 * 配置上传文件的最大值
 * @return
 */
@Bean
public MultipartConfigElement multipartConfigElement() {
    MultipartConfigFactory factory = new MultipartConfigFactory();
    //单个文件最大
    factory.setMaxFileSize(DataSize.ofBytes(200*1024*1024));
    //设置总上传数据总大小
   factory.setMaxRequestSize(DataSize.ofBytes(200*1024*1024));
    return factory.createMultipartConfig();
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++】类和对象(六个默认成员函数)

文章目录 类的六个默认成员函数**构造函数****构造函数的目的****构造函数的特性** 析构函数析构函数概念析构函数处理的顺序析构函数清理细节 拷贝构造函数拷贝构造函数典型调用场景 赋值运算符重载运算符重载赋值运算重载前置和后置 重载 const成员函数再提权限的问题: 取地址…

Guiding Large Language Models viaDirectional Stimulus Prompting

1. 通过定向刺激提示指导大语言模型 论文地址&#xff1a;[2302.11520] Guiding Large Language Models via Directional Stimulus Prompting (arxiv.org) 源码地址&#xff1a;GitHub - Leezekun/Directional-Stimulus-Prompting: [NeurIPS 2023] Codebase for the paper: &qu…

目标检测论文模型笔记——RCNN系列

RCNN系列模型&#xff08;two-stages、基于区域的)主要包括以下几种&#xff0c;按发布时间排序&#xff1a; RCNN&#xff08;2014年&#xff09;&#xff1a;首次将深度学习应用于目标检测&#xff0c;通过选择性搜索Selective Search提出候选区域&#xff0c;然后使用CNN&am…

章六、集合(1)—— 概念、API、List 接口及实现类、集合迭代

零、 关闭IDEA调试时自动隐藏空元素 一、 集合的概念 存储一个班学员信息&#xff0c;假定一个班容纳20名学员 当我们需要保存一组一样&#xff08;类型相同&#xff09;的元素的时候&#xff0c;我们应该使用一个容器来存储&#xff0c;数组就是这样一个容器。 数组有什么缺…

9. 内核、文件系统加载工具

内核、文件系统加载工具 内核、文件系统加载工具是嵌入式开发必备的工具 1. 烧写BootLoader 1.1 通过超级终端方式 烧写 Bootloader 可以使用超级终端的“传送” |“发送文件”命令进入发送文件对话框&#xff0c;使用 Xmodem 协议和 Kermit 协议发送 Bootloader 的各个文件…

《计算机网络》考研:2024/3/9 2.1.7-数据交换方式;2.2-物理层传输介质;2.3-物理层设备

2024/3/9 2.1.7、2.2、2.3 2.1.7 数据交换方式 电路交换存储转发方式 报文交换分组交换&#xff1a; 数据报方式虚电路方式 电路交换 报文交换 分组交换 2.2 物理层传输介质 物理层的主要任务 物理层设备 中继器&#xff1a; 集线器&#xff08;多口中继器&#xff09;…

如何获取用户请求的真实ip,并返回访问者的ip地理位置?node,vue

一、获取真实IP 方式1、前端调用免费公共接口获取 前端获取访问者的真实的外网ip,可以通过调用接口https://api.ipify.org/来获取。你也可以直接在网页上访问它来看自己的外网ip。 ipify介绍&#xff1a; ipify是一个免费的公共 API&#xff0c;用于获取设备的公共 IP 地址。…

Claude3横空出世:颠覆GPT-4,Anthropic与亚马逊云科技共启AI新时代

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

exceljs解析和生成excel文件

安装 npm install exceljs解析excel 通过 Workbook 的 readFile 方法可以拿到workbook对象, workbook对象包含的概念有 worksheet(工作表) --> row(行) --> cell(单元格).于是可以通过依次遍历 worksheet, row, cell来拿到单元格的数据直接通过 worksheet.getSheetValue…

从零学习Linux操作系统 第三十五部分 Ansible中的角色

一、理解roles在企业中的定位及写法 #ansible 角色简介# Ansible roles 是为了层次化&#xff0c;结构化的组织Playbookroles就是通过分别将变量、文件、任务、模块及处理器放置于单独的目录中&#xff0c;并可以便捷地include它们roles一般用于基于主机构建服务的场景中&…

Springboot 集成kafka 消费者实现ssl方式连接监听消息实现消费

证书准备&#xff1a;springboot集成kafka 消费者实现 如何配置是ssl方式连接的时候需要进行证书的转换。原始的证书是pem, 或者csr方式 和key方式的时候需要转换&#xff0c;因为kafka里面是jks 需要通过openssl进行转换。 证书处理&#xff1a; KeyStore 用于存储客户端的证…

Java多线程实战-实现多线程文件下载,支持断点续传、日志记录等功能

&#x1f3f7;️个人主页&#xff1a;牵着猫散步的鼠鼠 &#x1f3f7;️系列专栏&#xff1a;Java全栈-专栏 &#x1f3f7;️个人学习笔记&#xff0c;若有缺误&#xff0c;欢迎评论区指正 目录 前言 1 基础知识回顾 1.1 线程的创建和启动 1.2 线程池的使用 2.运行环境说…

k8s架构浅析

Node 节点&#xff08;物理主机或虚拟机&#xff09;&#xff0c;它们共同组成一个分布式集群&#xff0c;并且这些节点中会有一个 Master 节点&#xff0c;由它来统一管理 Node 节点。 Pod &#xff0c;在 K8S 中&#xff0c;Pod 是最基本的操作单元&#xff0c;它与 docker …

Linux之selinux详解

华子目录 概念作用selinux与传统的权限区别selinux工作原理名词解释主体&#xff08;subject&#xff09;目标&#xff08;object&#xff09;策略&#xff08;policy&#xff09;&#xff08;多个规则的集合&#xff09;安全上下文&#xff08;security context&#xff09; 文…

三栏布局的实现方法

1. 什么是三栏布局 常见的一种页面布局方式&#xff0c;将页面分为左栏、中栏和右栏左右两侧的盒子宽度固定&#xff0c;中间的盒子会随屏幕自适应一般中间放主体内容&#xff0c;左右两边放辅助内容 2. 如何实现三栏布局 2.1 弹性布局 将最外层盒子设为弹性布局&#xff0…

练习题-14

问题&#xff1a;已知函数 f : R → R f: \mathbb{R} \to \mathbb{R} f:R→R满足 f ( x y ) − f ( x − y ) f ( x ) f ( y ) , ∀ x , y ∈ R . f(xy)-f(x-y)f(x)f(y), \forall x, y \in \mathbb{R}. f(xy)−f(x−y)f(x)f(y),∀x,y∈R. 求 f f f. 提示&#xff1a;如果 f …

基于PBS向超算服务器队列提交任务的脚本模板与常用命令

本文介绍在Linux服务器中&#xff0c;通过PBS&#xff08;Portable Batch System&#xff09;作业管理系统脚本的方式&#xff0c;提交任务到服务器队列&#xff0c;并执行任务的方法。 最近&#xff0c;需要在学校公用的超算中执行代码任务&#xff1b;而和多数超算设备一样&a…

基于美洲狮优化算法(Puma Optimizar Algorithm ,POA)的无人机三维路径规划(提供MATLAB代码)

一、无人机路径规划模型介绍 无人机三维路径规划是指在三维空间中为无人机规划一条合理的飞行路径&#xff0c;使其能够安全、高效地完成任务。路径规划是无人机自主飞行的关键技术之一&#xff0c;它可以通过算法和模型来确定无人机的航迹&#xff0c;以避开障碍物、优化飞行…

第十五届蓝桥杯模拟考试III_物联网设计与开发

编程题 一、基本要求 使用大赛组委会提供的四梯/国信长天物联网省赛套装&#xff08;基于STM32L071KBU微控制器设计&#xff09;&#xff0c;完成本试题的程序设计与调试。程序编写、调试完成后&#xff0c;选手需提交两个LoRa终端对应的hex文件&#xff0c;LoRa终端A对应的文…

【Week Y1】调用官方权重进行检测

YOLO白皮书之调用官方权重进行检测 一、下载yolo-v5s源码&#xff0c;并配置编译环境二、输入本地图片查看检测结果三、输入本地视频查看检测结果 &#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项…