Spring Boot 文件上传、文件下载(批量压缩)、url 映射虚拟路径、解决下载文件名称乱码、MultipartConfigElement

目录

嵌入式 Tomcat 文件上传

url 映射虚拟路径需求分析

url 映射虚拟路径配置

文件上传

spring.servlet.multipart.location 临时目录

Web 网络文件下载(批量压缩)

解决下载文件名称乱码


嵌入式 Tomcat 文件上传

url 映射虚拟路径需求分析

1、Java web 应用开发完成后如果是导入外置的 Tomcat 的 webapps 目录的话,那么上传的文件可以直接的放在应用的 web 目录下去就好了,浏览器可以很方便的进行访问。

2、Spring Boot 默认使用嵌入式 Tomcat ,将来打包成可执行 Jar 文件进行部署,显然打成 jar 包后,总不可能再将上传的文件放在 resources 目录下去了,肯定是放在其它的磁盘目录下。

3、Spring Boot 于是提供了 url 地址匹配本地虚拟路径的功能:

1)上传文件到服务器,服务器将文件保存到了本地,如:E:\wmx\uploadFiles\222.png
2)用户访问应该是服务器地址,如:http://localhost:9393/fileServer/uploadFiles/222.png
3)于是通过配置资源映射,使 url 中的 /uploadFiles/ 映射到本地的 E:\wmx\uploadFiles\ 即可,E:\wmx\uploadFiles 则为虚拟路径。

4、url 映射虚拟路径主要是针对网络访问和下载,与文件上传关系不大。

url 映射虚拟路径配置

1、使用资源映射虚拟路径很简单,使用 WebMvcConfigurer 扩展配置即可,可参考自定义资源映射虚拟路径

2、全局配置文件自定义配置:

uploadFile:
  resourceHandler: /uploadFiles/**   #请求 url 中的资源映射
  location: E:/wmx/uploadFiles/ #自定义上传文件本地保存路径

src/main/resources/application.yml · 汪少棠/fileServer - Gitee.com

3、WebMvcConfigurer 扩展 webMvc 配置,设置资源映射

/**
 * WebMvc 扩展配置类,应用一启动,本类就会执行
 * url 映射虚拟路径配置
 *
 * @author wangMaoXiong
 * Created by Administrator on 2019/3/17 0017.
 */
@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {

    private static final Logger logger = LoggerFactory.getLogger(MyWebMvcConfigurer.class);

    /**
     * 请求 url 中的资源映射,不推荐写死在代码中,最好提供可配置,如 /uploadFiles/**
     */
    @Value("${uploadFile.resourceHandler}")
    private String resourceHandler;

    /**
     * 上传文件保存的本地目录,使用@Value获取全局配置文件中配置的属性值,如 E:/wmx/uploadFiles/
     */
    @Value("${uploadFile.location}")
    private String location;
    /**
     * 如果上传文件保存的本地目录不存在,则创建,否则后期保存文件时,容易出现找不到路径的错误
     */
    @PostConstruct
    public void init() {
        File file = new File(location);
        if (!file.exists()) {
            file.mkdirs();
            logger.debug("服务器文件存在目录={},已经不存在,进行新建。", location);
        } else {
            logger.debug("服务器存储目录已经存在={}", location);
        }
    }
    /**
     * 配置静态资源映射
     *
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        //就是说 url 中出现 resourceHandler 匹配时,则映射到 location 中去,location 相当于虚拟路径
        //映射本地文件时,开头必须是 file:/// 开头,表示协议
        registry.addResourceHandler(resourceHandler).addResourceLocations("file:///" + location);
    }
}

src/main/java/com/wmx/www/config/MyWebMvcConfigurer.java · 汪少棠/fileServer - Gitee.com

文件上传

1、Java JDK 1.8 + Spring Boot 2.3.5 新建 web 项目,spring boot 版本不同,可能略有差异。

2、spring boot 的 web 组件中的 org.springframework:spring-web 已经集成了文件上传功能,无需再导入以前的 commons-io、commons-fileupload 了,使用方式和之前的 commons-fileupload 完全一样。

一:pom.xml 内容如下,为了页面写起来方便,使用了 Thymeleaf 模板引擎,java web 应用,自然需要导入 web 组件。

         <!-- thymeleaf 模板引擎-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!-- web 组件-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

二:application.yml 全局配置文件内容如下:

#配置服务器
server:
  port: 8080 #服务器端口
  servlet:
    context-path: /fileServer #应用上下文路径

spring:
  servlet:
    multipart: #配置文件上传
      max-file-size: 1000MB #设置上传的单个文件最大值,单位可以是 MB、KB,默认为 1MB
      max-request-size: 1024MB #设置多文件上传时,单次内多个文件的总量的最大值,单位可以是 MB、KB,默认为 10 M
      #文件上传的临时存储目录(1、默认为系统临时目录;2、目录不存在时会自动创建)
      location: E:/wmx/uploadTemps/

uploadFile:
  resourceHandler: /uploadFiles/**   #请求 url 中的资源映射
  location: E:/wmx/uploadFiles/ #自定义上传文件本地保存路径

src/main/resources/application.yml · 汪少棠/fileServer - Gitee.com

1、上传文件存放的目录,不应该写死在代码中,所以上面提供了在配置文件中配置 uploadFile.location 属性,将来类中使用 @Value 取值即可。

2、文件上传官网介绍:Handling Multipart File Uploads,除了配置上面的单个文件最大值已经单次上传总量以外,官网还提供了如下配置:

# MULTIPART (MultipartProperties)
spring.servlet.multipart.enabled=true # 是否启用上传支持.
spring.servlet.multipart.file-size-threshold=0B #将文件写入磁盘的阈值.
spring.servlet.multipart.location= # 上传文件的临时存储目录(默认为系统临时目录).
spring.servlet.multipart.max-file-size=1MB # 单个文件支持的最大大小.
spring.servlet.multipart.max-request-size=10MB # 单次请求时,全部文件的不能超过的总大小.
spring.servlet.multipart.resolve-lazily=false # 是否在访问文件或参数时延迟解析多部分请求.

三:文件上传后台控制台层代码如下:

    /**
     * 请求 url 中的资源映射,不推荐写死在代码中,最好提供可配置,如 /uploadFiles/**
     */
    @Value("${uploadFile.resourceHandler}")
    private String resourceHandler;
    /**
     * 上传文件保存的本地目录,使用 @Value获 取全局配置文件中配置的属性值,如 E:/wmx/uploadFiles/
     */
    @Value("${uploadFile.location}")
    private String uploadFileLocation;
    /**
     * http://localhost:8080/fileServer/uploadFile
     * 文件上传,因为只是演示,所以使用 @ResponseBody 将结果直接返回给页面
     *
     * @param singleFile :上传的文件对象
     * @param request    :请求对象
     * @return :返回的是文件名称,将来客户端可以用来下载
     * @throws IOException
     */
    @PostMapping("uploadFile")
    @ResponseBody
    public String uploadFile(MultipartFile singleFile, HttpServletRequest request) throws IOException {
        if (singleFile == null || singleFile.isEmpty()) {
            logger.debug("上传文件为空...");
            return "上传文件为空...";
        }
        //basePath拼接完成后,形如:http://192.168.1.20:8080/fileServer
        String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath();
        String fileName = singleFile.getOriginalFilename();
        String fileServerPath = basePath + resourceHandler.substring(0, resourceHandler.lastIndexOf("/") + 1) + fileName;
        logger.debug("文件访问路径:{}", fileServerPath);

        File saveFile = new File(uploadFileLocation, fileName);
        /**
         * 文件保存,注意目的文件夹必须事先存在,否则保存时报错
         * 在{@link MyWebMvcConfigurer}中已经处理了,如果不存在,自动新建存储目录
         */
        singleFile.transferTo(saveFile);
        logger.info("文件保存路径:{}", saveFile.getPath());
        return "<a target='_blank' href='" + fileServerPath + "'>" + fileServerPath + "</a>";
    }

src/main/java/com/wmx/www/controller/UploadFileController.java · 汪少棠/fileServer - Gitee.com

四:前端文件上传 form 表单如下:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>文件服务器</title>
</head>
<body>
<h3>单文件上传,成功后返回访问地址,可以查看并下载</h3>
<form method="post" target="_blank" action="/fileServer/uploadFile" enctype="multipart/form-data">
    <input type="file" name="singleFile" style="font-size: 20px"/><br>
    <input type="submit" id="singleFileUploadButton1" value="上传" style="font-size: 30px">
</form>
</body>
</html>

src/main/resources/templates/index.html · 汪少棠/fileServer - Gitee.com

spring.servlet.multipart.location 临时目录

1、Spring boot 文件上传时有时候会出现此错误(临时上传存储位置无效或者是不存在):Caused by: java.io.IOException: The temporary upload location [/tmp/tomcat.2877894020006618597.7030/work/Tomcat/localhost/ROOT] is not validSpring boot 默认会使用系统的临时目录,然而服务运行过程中,人为删除了临时目录,或者系统自动删除了临时目录(比如Linux系统有时会自动清理长时间未使用的临时目录),当服务再次使用时临时目录时就会报错。

2、解决办法

方式1)使用默认临时目录时,可以重启项目,此时会自动重新生成临时存储路径

方式2)全局配置文件中配置(推荐方式):spring.servlet.multipart.location=上传文件的临时存储目录

2.1、当上传文件时,会先将文件上传到该目录下的临时文件夹中,成功后再移动到最终的目录中,这样可以保证在上传文件过程中出现异常时,临时文件被及时清理。

2.2、如果上传失败,临时文件会一直存在,直到被清理或重新上传。Spring提供了一个ScheduledExecutorService,用于在后台周期性地清理过期的临时文件。默认情况下,过期时间是1个小时。

2.3、亲测 Spring boot 2.3.5,当目录不存在时会自动创建,低版本可能不会自动创建此目录而报错:The temporary upload location [/xxx/xxx] is not valid

方式3)手动注入 MultipartConfigElement,设置临时存储路径,覆盖全局yml文件的配置,代码如下:

@Bean  
public MultipartConfigElement multipartConfigElement() {  
   MultipartConfigFactory factory = new MultipartConfigFactory();  
   factory.setLocation("d://temp");  
   return factory.createMultipartConfig();  
}

方式4:如果报错临时目录不存在了,直接登陆服务器给它手动创建,或者提供一个接口进行调用然后创建 createDirByPath

 3、MultipartConfigElement不仅可以手动注入用于覆盖配置,它本身默认也会自动注入到Spring容器中,可以直接获取对象,然后获取配置信息。或者运行期可以动态修改配置。

Web 网络文件下载(批量压缩)

1、单个文件下载,多个文件时压缩成一个文件下载。

    /**
     * 多个文件压缩成一个文件后下载.
     * 1、本方法使用原生API进行压缩。
     * 2、也可以使用第三方的解压库:
     * * Apache Commons Compress 文件解压缩库:https://wangmaoxiong.blog.csdn.net/article/details/103943688#文件压缩并提供网络下载
     *
     * @param fileId   :被下载的文件ID,多个时使用逗号分割,如 1,2,3,4
     * @param response
     * @throws Exception
     */
    @GetMapping("/zipDownload1")
    public void zipDownload1(String fileId, HttpServletResponse response) throws Exception {
        // 要下载的文件列表
        List<Path> listPath = this.listPath(fileId);
        String zipFileName = listPath.get(0).getFileName() + "等" + listPath.size() + "个.zip";
        // 设置发送到客户端的响应的内容类型
        response.setContentType("application/zip");
        // 设置返回的头信息(Content-Disposition),对文件名称进行编码,否则中文容易乱码。
        response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + URLEncoder.encode(zipFileName, "UTF-8"));
        // 压缩多个文件到zip文件中,并且响应给客户端
        try (ZipOutputStream zipOutputStream = new ZipOutputStream(response.getOutputStream())) {
            for (Path path : listPath) {
                try (InputStream inputStream = Files.newInputStream(path)) {
                    zipOutputStream.putNextEntry(new ZipEntry(path.getFileName().toString()));
                    StreamUtils.copy(inputStream, zipOutputStream);
                    zipOutputStream.flush();
                }
            }
        }
    }

https://gitee.com/wangmx1993/file-server/blob/master/src/main/java/com/wmx/www/controller/DownloadFileController.java

2、​Post 请求文件下载在线演示源码:后端导出接口、POI Word工具类、前端页面

3、Easyexcel  上传、下载:https://wangmaoxiong.blog.csdn.net/article/details/106978811#Easyexcel 上传、下载

4、web 下载 excel 文件:src/main/java/com/wmx/controller/ExcelController.java · 汪少棠/apache-poi-study - Gitee.com

解决下载文件名称乱码

https://wangmaoxiong.blog.csdn.net/article/details/106978811#t5

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蚩尤后裔-汪茂雄

芝兰生于深林,不以无人而不芳。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值