目录:
作者简介 :一只大皮卡丘,计算机专业学生,正在努力学习、努力敲代码中! 让我们一起继续努力学习!
该文章参考学习教材 为:
《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 时必须指定该Bean 的id 为mulipartResolver。
由于 CommonsMultipartResolver 是SpringMVC内部 通过 Apache Commons FileUpload 技术实现的,所以 SpringMVC 的文件上传 还 需要依赖Apache Commons FileUpload的组件,即需要导入支持文件上传 的相关JAR包 ,具体如下 :
commons-fileupload-1.3.2.jar
commons-io-2.5.jar
SpringMVC所需JAR
SpringMVC中"文件上传"和"下载"所需JAR后端处理器方法 中是通过 "MultipartFile接口 "类型参数 来 接收前端传来 的文件 的,例子如下 :
javapackage 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 :
javapackage 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 :
javapackage 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对象,通过对这两个对象的设置 ,即 可完成下载文件 时所需的配置信息。
文件下载 的示例代码 如下所示 :
javapackage 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 :
javapackage 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中 的关键字。
再次进行中文名 的文件下载测试,如下图所示 :