SpringMVC | SpringMVC中的 “文件上传和下载”

目录:

作者简介 :一只大皮卡丘,计算机专业学生,正在努力学习、努力敲代码中! 让我们一起继续努力学习!

该文章参考学习教材 为:
《Java EE企业级应用开发教程 (Spring + Spring MVC +MyBatis)》 黑马程序员 / 编著

文章以课本知识点 + 代码为主线,结合自己看书学习过程中的理解和感悟 ,最终成就了该文章

文章用于本人学习使用 , 同时希望能帮助大家。

欢迎大家点赞👍 收藏⭐ 关注💖哦!!!

(侵权可联系我,进行删除,如果雷同,纯属巧合)


一、文件上传

1.1 文件上传"概述"

  • 上文件上传下载项目 开发中 最常用功能,例如图片的上传与下载邮件附件上传下载等。

1.2 文件上传"具体配置" :

"前端"中配置"文件上传" ( type="file" + 满足3个条件 )
  • 多数文件上传 都是通过 表单形式 提交给 后台服务器 的,因此,要实现文件上传功能 ,就需要提供一个 文件上传表单,而 该表单 必须 满足以下3个条件 :

    form表单method属性 设置为post
    form表单enctype属性 (编码方式 ) 设置为 multipart/form-data (多部分/表单数据)
    提供 <input type="file" name=filename" multiple="multiple"/>文件上传输入框

    ps
    multiple="multiple"可选属性 ,表示 可以 一次性选择多个文件来上传

  • 文件上传 表单的 示范代码 如下 : ("前端 "中配置"文件上传")

    html 复制代码
    <%-- 通过表单的方式进行文件上传--%>
    <form action="/uploadUrl" method="post" enctype="multipart/form-data">
    <%--  multiple="multiple 为可选属性,表示一次可以选择多个文件上传  --%>
        <input type="file" name="filename" multiple="multiple">
    </form>

    上述代码 中,除了满足上传表单必须的3个条件外 ,在 <input>元素 中还增加了一个 multiple属性,该属性HTML5新属性 ,如果使用了该属性,则可以 同时选择多个文件进行上传 ,即 "多文件上传"。

    客户端form表单enctype属性 (multipart/form-data)为 multipart/form-data 时,浏览器 就会采用 二进制流 的方式来 处理表单数据服务器端 就会对 文件上传请求进行解析处理

"后端"中配置"文件上传" ( 配置id为"CommonsMultipartResolver"的bean + 配置"文件上传"的"约束条件" + 通过"MultipartFile接口"参数接收"传来的文件")
  • Spring MVC 中为文件上传 提供了直接的支持,这种支持是通过 MultipartResolver (多部件解析器 ) 对象实现 的。MultipartResolver ( 多部件解析器 )是一个接口对象 ,需要通过它的 实现类 : CommonsMultipartResolver 来完成 文件上传工作。在Spring MVC中使用 MultipartResolver对象非常简单只需要配置文件 中定义MultipartResolver接口Bean 即可。

    (配置 id 为 "CommonsMultipartResolver "的bean )

  • 除了 配置 CommonsMultipartResolver类 之外,还可以通过 <property>元素 配置"文件上传 "的"约束条件" ,具体 "文件上传 "的"约束条件" 如下 :

约束条件 描述
<property name="defaultEncoding" value="xxx"/> 配置 "请求编码格式",必须JSP 中的 pageEncoding属性一致默认ISO-8859-1
<property name="maxUploadSize" value="xxx"/> 设置 上传文件最大长度单位 为 "字节"。
<property name="maxInMemorySize" value="xxx"/> 设置 "缓存中" 的 最大尺寸ps : maxInMemorySize最大内存大小
<property name="resolveLazily" value="xxx"/> 推迟文件解析以便Controller捕获文件大小异常

例子如 : ( springmvc-config.xml配置 "文件上传" )

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
	http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans.xsd">


<!--  配置Springmvc的"文件上传"  -->
<!--   配置id为CommonsMultipartResolver的bean -->
<!--
因为实现类CommonsMultipartResolver的内部是引用multipartResolver的知识点来获取"该实现类对象"并完成"文件解析"的,所以该bean的id名必须为: multipartResolver
-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 配置"请求编码格式",必须与JSP中的pageEncoding的属性一致,默认是ISO-8859-1 -->
<property name="defaultEncoding" value="UTF-8"/>
<!-- 设置上传文件的最大长度,单位为字节  -->
<!-- 1MB = 1024KB ,1KB = 1024B ,2MB = 2X1024X1024 = 2097152B(字节)-->
<property name="maxUploadSize" value="2097152"/>
</bean>

</beans>

上述配置代码 中,配置了 CommonsMultipartResolver类 外,还通过 <property>元素 配置了 编码格式允许上传文件的大小

注意 :

因为MuliparResolver接口实现类CommonsMulipartResolver 内部是引用muliparReolver字符
获取该实现类对象完成文件解析的,所以在配置CommonsMulipartResolver 时必须指定该BeanidmulipartResolver

  • 由于 CommonsMultipartResolverSpringMVC内部 通过 Apache Commons FileUpload 技术实现的,所以 SpringMVC文件上传需要依赖Apache Commons FileUpload的组件,即需要导入支持文件上传相关JAR包具体如下 :

    commons-fileupload-1.3.2.jar
    commons-io-2.5.jar
    SpringMVC所需JAR
    SpringMVC中"文件上传"和"下载"所需JAR

  • 后端处理器方法 中是通过 "MultipartFile接口 "类型参数接收前端传来文件 的,例子如下

    java 复制代码
    package com.myh.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.multipart.MultipartFile;
    
    @Controller //将该被设置为"处理器"类
    public class FileUploadController { //文件上传的"控制器类"
    
        @RequestMapping("/fileUpload")
        //使用@RequestParam("前端参数名")注解注解"前后端参数名不一致的问题",让数据之间能够完成映射/赋值
        //通过"MultipartFile接口"来接受前端传来的文件
        public String handlerFormUpload(@RequestParam("filename") MultipartFile file) { //MultipartFile 是一个接口
            if (!file.isEmpty()) { //如果文件不为空
               //具体的执行方法
                ...
                return "uploadSuccess";
            }
            return "uploadFailure";
    
        }
    }

    上述代码 中,包含一个 MultipartFile接口类型 的参数file ,(前端 )上传到程序中的文件 就是被封装在该参数中 ( MultipartFile接口 )的。org.springframework. web mutipart.MultipartFile接口提供获取上传文件文件名称等方法,这些方法 及其说明如下表示 :

    MultipartFile接口 中的主要方法 :

    方法 说明
    byte[ ] getBytes( ) 字节数组 形式 返回文件内容
    String getContentType( ) 返回 文件内容类型
    InputStream getInputStream( ) 读取文件内容返回 一个InputStream流
    String getName( ) 获取 多部件form表单参数名称
    String getOriginalFilename( ) 获取 上传文件初始化名
    long getSize( ) 获取 上传文件大小单位字节
    boolean isEmpty( ) 判断 上传的文件是否为空
    void transferTo( File file ) 上传的文件 保存目标目录下ps : 该 方法 中的 File参数本质 为 "上传文件 "的"存储地址信息",因为 MultipartFile接口代表" 上传文件本身"。

1.3 文件上传"应用案例" :

文件上传 (存储在"相对路径")
  • 第一步导入依赖
    SpringMVC所需JAR
    SpringMVC中"文件上传"和"下载"所需JAR

  • 第二步配置具体操作代码文件

    web.xml

    xml 复制代码
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
             version="4.0">
    
    
        <!-- 配置"前端过滤器"-->
        <servlet>
            <servlet-name>dispatcherServlet</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <!--  配置springmvc-config.xml配置文件的位置 (上下文配置位置) -->
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:springmvc-config.xml</param-value>
            </init-param>
            <!--  配置启动服务器时加载此配置文件,加载此servlet -->
            <load-on-startup>1</load-on-startup>
        </servlet>
    
        <!--  配置Servlet的Mapper映射  -->
        <servlet-mapping>
            <servlet-name>dispatcherServlet</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    
    </web-app>

    springmvc-config.xml

    xml 复制代码
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
    	http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
    
        <!--  定义"组件扫描",指定需要扫描的包,让注解生效 -->
        <mvc:component-scan base-package="com.myh.controller"/>
    
        <!--  配置"视图解析器" : 对于"返回视图"的操作有便利  -->
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <!--  设置前缀   -->
            <property name="prefix" value="/WEB-INF/jsp/"/>
            <!--  设置后缀   -->
            <property name="suffix" value=".jsp"/>
        </bean>
    
    
        <!--  配置文件上传解析器 : 多部件解析器 : MultipleResolver  -->
        <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
            <!--  设置请求编码格式   -->
            <property name="defaultEncoding" value="UTF-8"/>
        </bean>
    
    </beans>

    FileUploadController.java

    java 复制代码
    package com.myh.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.multipart.MultipartFile;
    
    import javax.servlet.http.HttpServletRequest;
    import java.io.File;
    import java.io.IOException;
    import java.util.List;
    import java.util.UUID;
    
    /**
     * 文件上传 (相对路径)
     */
    @Controller
    public class FileUploadController {
    
        /**
         * 执行文件上传
         */
        @RequestMapping("/fileUpload")
        public String handldFormUpload(@RequestParam("username") String username , @RequestParam("file") List<MultipartFile> uploadfiles,
                                       HttpServletRequest request) {
            //判断所上传的文件是否存在
            if (!uploadfiles.isEmpty() && uploadfiles.size() > 0) {
                //循环输出上传的文件
                for (MultipartFile multipartFile : uploadfiles) {
                    //获得上传文件的原始名
                    String originalFilename = multipartFile.getOriginalFilename();
                    /**
                     * 设置上传文件的"保存地址"
                     */
                    //从HTTP请求对象中获取ServletContext对象,然后使用ServletContext对象的.getRealPath()方法来获得"真实路径"。
                    String dirPath = request.getServletContext().getRealPath("/upLoadFile/"); //会在out目录下的打包的项目的"根目录"下创建该文件夹,用于存储文件
                    File filePath = new File(dirPath);
                    //如果保存文件的地址不存在,则先创建目录
                    if (!filePath.exists()) {
                        filePath.mkdirs(); //创建目录(创建文件夹)
                    }
                    //使用UUID重新命名上传的文件名称(上传人_uuid_原始文件名称)
                    /*
                      UUID.randomUUID() 是Java中的一个方法,用于生成一个随机的、唯一的标识符(Universally Unique Identifier,简称UUID)
                     */
                    String newFilename = username + UUID.randomUUID() + originalFilename;
                    try {
                        //使用MultipartFile接口的 transferTo()方法将文件上传到指定位置
                        /*
                            transferTo(File file) : 该方法中的参数本质上为"上传文件"的存储地址信息,因为multipartFile接口就代表"上传文件本身"
                         */
                        multipartFile.transferTo(new File(dirPath + newFilename));
                        System.out.println(new File(dirPath + newFilename));
                    } catch (IOException e) {
                        e.printStackTrace();
                        return "error"; //返回错误页面
                    }
                }
                //跳转成功页面
                return "success";
            } else {
                return "error";
            }
        }
    }

    上述代码 中,使用注解方式 定义了一个控制器类 ,并在类中定义了执行文件上传方法 :
    handleFormUpload( )在handleFormUpload( )方法参数 中使用了List<MultipartFile>集合类型

    接收用户上传的文件 ,然后判断所上传文件是否存在 。如果存在 ,则继续执行上传操作 ,在通过MultipartFile接口transferTo( )方法将上传文件保存用户指定的目录位置 ,会跳转到success.jsp 页面;如果文件不存在 或者上传失败 ,则跳转到error.jsp页面

    注意点

    此处 文件 存储的路径 为 "相对路径" ,即 /upLoadFile/ : 如果该文件夹还没存在,会先在 "项目打包后根目录 创建一个 文件夹 : upLoadFile, 然后将 "上传的文件" 存储到该文件夹中 ) ,upLoadFile文件夹 (是 相对路径 ) 位置展示如下图所示


    FileUpload.jsp

    html 复制代码
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>文件上传</title>
        <script>
            //判断是否填写上传人并已选择上传文件
            function check() {
                var username = document.getElementById("username").value;
                var file = document.getElementById("file").value;
                if (username == "") {
                    alert("请填写上传人!");
                    return false;
                }
                if (file.length == 0 || file == "") {
                    alert("请选择上传文件!");
                    return false;
                }
                return true;
            }
        </script>
    </head>
    <body>
    <%--
       οnsubmit="return check()" : 只有check()方法的返回值为true,才会正常提交表单(才会访问url)
    --%>
    <form action="${pageContext.request.contextPath}/fileUpload" enctype="multipart/form-data" method="post" onsubmit="return check()">
        上传人:<input type="text" id="username" name="username"></br>
        请选择文件:<input type="file" id="file" name="file" multiple="multiple"></br>
        <input type="submit" value="上传">
    
    </form>
    </body>
    </html>

    文件 中,编写了一个用于文件上传fom表单 ,该表单 可以填写上传人上传文件 ,当单击"上传" 按钮 时,会先执行ceck方法检查上传 人文本框文件选择框 中内容是否为空只有填写了 上传人并选择了需要上传的文件后,才能正常提交表单 ;否则表单将不会提交 ,并给相应提示信息οnsubmit="return check() : 只有方法中返回值为true才会提交表单)。 提交表单后 ,会以POST方式 提交到一个以"/fileUpload "结尾的请求中。


    error.jsp

    xml 复制代码
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>error页面</title>
    </head>
    <body>
    error!
    </body>
    </html>

    success.jsp

    html 复制代码
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>success页面</title>
    </head>
    <body>
    ok!
    </body>
    </html>

    项目发布Tomcat服务器中并启动,在浏览器中访问地址 : http://localhost:8080/FileUpload.jsp显示效果如下图所示 :

    在上面的 "上传页面" 中,填写 上传人 并选择所要 上传的文件,单击 "上传" 按钮后就可向后台 发送上传请求信息



    单击 "上传 "按钮 ,程序在正确执行后浏览器 就会跳转到 success.jsp 页面,此时查看 项目发布项目 ,即 可发现 在:
    S:\2024项目\SpringMVC中的"文件上传"和"下载"\out\artifacts\SpringMVC_Web_exploded 下 ( 能 在idea找到该文件夹,所以 属于"相对路径") 创建了一个名字 为 :upLoadFile文件夹,同时 "前端上传的文件" 则 存储该文件夹 中。在IDEA中查看存储 "上传文件 "的upLoadFile文件夹:


    注意点

    需要注意 的是 ,upLoadFile文件夹 是在项目的 发布路径 / 打包路径 中,而不是创建的项目所在目录 中 :

文件上传 (存储在"绝对路径")
  • 文件上传 (存储在"绝对路径") 的 实现: 除了 FileUploadController.java 这个文件有不同之外其他的 都是相同的 。(替换以下代码 就是将"文件 "存储在"绝对路径")

    java 复制代码
    /**
    * 存储的是"绝对路径",将上传的文件存储在D盘下的upLoadFile3文件夹下
    */
    String dirPath = "D:/upLoadFile3/";

    FileUploadController.java :

    java 复制代码
    package com.myh.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.multipart.MultipartFile;
    
    import javax.servlet.http.HttpServletRequest;
    import java.io.File;
    import java.io.IOException;
    import java.util.List;
    import java.util.UUID;
    
    /**
     * 文件上传 (绝对路径)
     */
    @Controller
    public class FileUploadController2 {
    
        /**
         * 执行文件上传( 文件存储在"绝对路径")
         */
        @RequestMapping("/fileUpload3")
        public String handldFormUpload(@RequestParam("username") String username , @RequestParam("file") List<MultipartFile> uploadfiles,
                                       HttpServletRequest request) {
            //判断所上传的文件是否存在
            if (!uploadfiles.isEmpty() && uploadfiles.size() > 0) {
                //循环输出上传的文件
                for (MultipartFile multipartFile : uploadfiles) {
                    //获得上传文件的原始名
                    String originalFilename = multipartFile.getOriginalFilename();
                    
                    /**
                     * 存储的是"绝对路径",将上传的文件存储在D盘下的upLoadFile3文件夹下
                     */
                    String dirPath = "D:/upLoadFile3/";
                    File filePath = new File(dirPath);
                    //如果保存文件的地址不存在,则先创建目录
                    if (!filePath.exists()) {
                        filePath.mkdirs(); //创建目录(创建文件夹)
                    }
                    //使用UUID重新命名上传的文件名称(上传人_uuid_原始文件名称)
                    /*
                      UUID.randomUUID() 是Java中的一个方法,用于生成一个随机的、唯一的标识符(Universally Unique Identifier,简称UUID)
                     */
                    String newFilename = username + UUID.randomUUID() + originalFilename;
                    try {
                        //使用MultipartFile接口的 transferTo()方法将文件上传到指定位置
                        /*
                            transferTo(File file) : 该方法中的参数本质上为"上传文件"的存储地址信息,因为multipartFile接口就代表"上传文件本身"
                         */
                        multipartFile.transferTo(new File(dirPath + newFilename));
                        System.out.println(new File(dirPath + newFilename));
                    } catch (IOException e) {
                        e.printStackTrace();
                        return "error"; //返回错误页面
                    }
                }
                //跳转成功页面
                return "success";
            } else {
                return "error";
            }
        }
    }

二、文件下载

2.1 实现"文件下载" ( "不可"下载"非中文名称"文件 )

文件下载 就是将 文件服务器 中的 文件下载到本机上。在SpringMVC 环境中,实现文件下载 大致可分为 如下两个步骤

客户端页面 使用一个 文件下载超链接,该链接href属性 要指定后台文件下载方法 以及 文件名 (需要先在文件下载目录中添加了一个名称 为 "1.jpg "的文件 ),具体代码示例如下 :

html 复制代码
<a href="${pageContext.request.contextPat}/download?filename=1.jpg"> 
   文件下载
</a>

在后台 Controller类 中,使用 SpringMVC 提供的 文件下载方法 进行 文件下载SpringMVC 提供了一个 ResponseEntity类型对象,使用它可以很方便地定义返回HttpHeaders对象HttpStatus对象,通过对这两个对象的设置 ,即 可完成下载文件所需的配置信息

文件下载示例代码 如下所示 :

java 复制代码
package com.myh.controller;

import org.apache.commons.io.FileUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;

/**
   * 文件下载
*/
@Controller
public class FileDownLoadController {

   @RequestMapping("/download")
   public ResponseEntity<byte[]> fileDownload(HttpServletRequest request,String filename) throws IOException {
       //指定要下载的文件所在的路径 (即存储文件的路径) --此时用的是"相对路径"
       String path = request.getServletContext().getRealPath("/upLoadFile/");
       //创建该对象
       File file = new File(path + File.separator + filename);
       //设置"响应头"
       HttpHeaders headers = new HttpHeaders();
       //通知浏览器"以下载的方式"打开文件
       headers.setContentDispositionFormData("attachment", filename);
       //定义"以流的形式下载"返回文件数据
       headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
       //使用Spring MVC框架的 ResponseEntity对象封装"下载数据"
       ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(FileUtils.readFileToByteArray(file), headers, HttpStatus.OK);
       return responseEntity;
   }
}

fileDownload( )方法 中,首先根据 文件路径 和需要下载的 文件名创建文件对象,然后对 响应头文件下载时的打开方式 以及 下载方式 进行了设置,最后返回 ResponseEntity封装下载结果对象

ResponseEntity对象 有些 类似 前面章节介绍的 @ResponseBody注解,它用于 直接返回结果对象。上面示例中,设置 响应头信息MediaType 代表的是Interner Media Type (即互联网媒体类型 ),也叫作MIME类型 , MediaType.APPLICATION_OCTET_STREAM 的值为 application/octet-stream,即表示以 二进制流形式下载数据
HttpStatus 类型 代表的是Http协议中的状态,示例中的 HttpStatus.OK 表示 200 ,即服务器 已成功处理了请求


启动服务器后访问网址http://localhost:8080/FileDownLoad.jsp ,其显示效果如下图所示

点击"文件下载 "链接后,会出现下载提示弹窗如下图所示

此时,点击"下载 "即可下载该文件

2.2 "中文名称"的文件下载 ( "可"下载"中文名称"文件 )

  • 虽然在 实现"文件下载"案例 中能通过 Spring MvC 实现了文件下载功能,但 此案例代码 只适用非中名称的文件进行下载,当对中文名称文件进行下载 时,因为各个浏览器内部转码机制的不同,就会出现 不同的乱码 以及解析异常问题。例如在文件下载目录 中添加一个名称为"壁纸.jpg " 的文件 ,当通过浏览器下载该文件 时,下载弹出窗口显示如下图 所示 :

    上图可以看出 ,所要下载的文件名称不是壁纸.jpg , 而是"_.jpg ", 这就表示 中文文件名称 出现了乱码。那么我们要如何 解决这种乱码问题呢?

  • 为了 解决浏览器中文件下载中文名称的乱码问题,可以在 前端页面发送请求前对中文名进行统一编码,然后在 后台控制器类对文件名称 进行相应的转码,其 具体实现步骤如下 :

    • 下载页面 中对中文文件名编码。可以使用ServletAPI中提供的 URLEncoder类 ( URL编码器 )中的 encoder ( String s, String enc )方法将中文转为UTF-8编码 。该方法中 第一个参数表示 需要转码的字符串
      第二个参数表示 编码格式,其具体实现方式如下代码所示

      FileDownLoad.jsp :

      html 复制代码
      <%@ page import="java.net.URLEncoder" %>
      <%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
      <html>
      <head>
          <title>文件下载(下载中文名称文件)</title>
      </head>
      <body>
      <%--
        <%= URLEncoder.encode("壁纸.jpg","UTF-8") %> : 其作用为:通过URLEncoder(URL编码器)的,encode()方法来对"中文文件名称"进行"转码"
      --%>
      <a href="${pageContext.request.contextPath}/download2?filename=<%= URLEncoder.encode("壁纸.jpg","UTF-8") %>">
          "中文名称"文件下载
      </a>
      </body>
      </html>
    • 修改控制器类FileUploadController 中的fileDownload( )方法 ,并 增加对文件名 进行编码方法,其代码如下所示 :

      FileDownLoadController2.java

      java 复制代码
      package com.myh.controller;
      
      import org.apache.commons.io.FileUtils;
      import org.springframework.http.HttpHeaders;
      import org.springframework.http.HttpStatus;
      import org.springframework.http.MediaType;
      import org.springframework.http.ResponseEntity;
      import org.springframework.stereotype.Controller;
      import org.springframework.web.bind.annotation.RequestMapping;
      
      import javax.servlet.http.HttpServletRequest;
      import java.io.File;
      import java.io.IOException;
      import java.io.UnsupportedEncodingException;
      import java.net.URLEncoder;
      
      /**
       * 文件下载 (下载中文名称文件)
       */
      @Controller
      public class FileDownLoadController2 {
      
          @RequestMapping("/download2")
          public ResponseEntity<byte[]> fileDownload(HttpServletRequest request,String filename) throws IOException {
              //指定要下载的文件所在的路径 (即存储文件的路径) --此时用的是"相对路径"
              String path = request.getServletContext().getRealPath("/upLoadFile/");
              //创建该文件对象
              File file = new File(path + File.separator + filename);
      
              /**
               * 对文件名编码,防止中文文件乱码
               */
              filename = this.getFilename(request,filename);
      
              //设置"响应头"
              HttpHeaders headers = new HttpHeaders();
              //通知浏览器"以下载的方式"打开文件
              headers.setContentDispositionFormData("attachment", filename);
              //定义以流的形式下载返回文件数据
              headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
              //使用Spring MVC框架的 ResponseEntity对象封装"下载数据"
              ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(FileUtils.readFileToByteArray(file), headers, HttpStatus.OK);
              return responseEntity;
          }
      
          /**
           *  根据浏览器的不同编码进行设置,返回编码后的文件名
           */
          private String getFilename(HttpServletRequest request, String filename) throws UnsupportedEncodingException {
              //IE不同版本User-Agent中出现的关键词
              String[] IEBrowserKeyWords = {"MSIE", "Trident", "Edge"};
              //获取请求头代理信息
              String userAgent = request.getHeader("User-Agent");
              for (String keyWord : IEBrowserKeyWords) {
                  if (userAgent.contains(keyWord)) {
                      //IE内核浏览器,统一为UTF-8编码显示
                      return URLEncoder.encode(filename, "UTF-8");
                  }
              }
              
              //火狐等其他浏览器统一为ISO-8859-1编码显示
              return new String(filename.getBytes("UTF-8"), "ISO-8859-1");
          }
      }

      在方法getFilename( )中,由于IE浏览器文件编码上其他浏览器的方式不同 ,所以在中文编码设置上IE浏览器 设置为UTF-8编码 ,而火狐等其他浏览器设置ISO-8859-1编码 。另外由于不同版本IE浏览器 ,请求代理User-Agent中的关键字也略有不同 ,所以在判断IE浏览器 时,需要特别意User-Agent中关键字

      再次进行中文名文件下载测试如下图所示

相关推荐
bingbingyihao2 分钟前
Linux安装ftp、Java的FTP上传下载文件工具类
java·linux·centos
u0104058369 分钟前
如何利用Java Stream API简化集合操作?
java·开发语言
G皮T11 分钟前
【MyBatis】MyBatis 理论 40 问(二)
java·数据库·spring boot·spring·mybatis·关系映射
小羊子说19 分钟前
Android 开发中 C++ 和Java 日志调试
android·java·c++
TechQuester24 分钟前
解决GPT-4o耗电难题!DeepMind新算法训练效率提升13倍,能耗降低10倍!
java·c++·人工智能·python·算法·chatgpt
球球King34 分钟前
工厂模式之简单工厂模式
java·jvm·简单工厂模式
续亮~39 分钟前
6、Redis系统-数据结构-06-跳表
java·数据结构·数据库·redis·后端·缓存
不决问春风1 小时前
102.二叉树的层序遍历——二叉树专题复习
java·算法·leetcode
哎呦没1 小时前
MOJO编程语言的编译与执行:深入编译器与解释器的工作原理
java·开发语言·mojo
得不到的更加爱1 小时前
Java多线程不会?一文解决——
java·开发语言