• 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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    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);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    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");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    前端测试

    实用工具模拟前端发起请求,工具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

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

    spring:
      servlet:
        multipart:
          max-file-size: 500MB
          max-request-size: 500MB
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
  • 相关阅读:
    HTML5简明教程系列之HTML5 表格与表单(二)
    D Mocha and Railgun
    Redis学习笔记:Redis五种常用数据类型及其基本操作
    hdu 3549 a flow problem 的多种解法
    Json(一种数据格式,key:value)
    【项目】Http服务器
    java毕业设计Vue框架校园相约健康运动平台源码+系统+数据库+lw文档+调试运行
    端口映射与容器互联
    AI新工具 百分50%算力确达到了GPT-4水平;将音乐轨道中的人声、鼓声、贝斯等音源分离出来等
    【面试常考的网络编程之Socket、短连接与长连接、客户端与服务端网络通讯流程、Java网络编程之BIO、JDK网络编程BIO案例实战演练】
  • 原文地址:https://blog.csdn.net/wjzh2008/article/details/136610521