阅读量:0
一、案例的功能需求
接下来将文件上传和下载的相关知识结合起来,实现一个文件上传和下载的案例。在实现案例之前,首先分析案例的功能需求。本案例要实现的功能为,将文件上传到项目的文件夹下,文件上传成功后将上传的文件名称记录到一个文件中,并将记录的文件列表展示在页面,单击文件列表的链接实现文件下载。
二、实现文件上传和下载案例的思路
• 搭建文件上传和下载的环境。• 实现文件上传功能。• 实现获取文件列表功能。• 编写文件上传和下载页面。• 实现文件下载。
接下来按照分析思路实现文件上传和下载,具体步骤如下所示。
1、搭建文件上传和下载的环境:在项目的pom.xml中引入commons-fileupload的依赖,具体代码如下所示。
<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.4</version> </dependency>
在spring-mvc.xml中配置多部件解析器,具体配置如下所示。
<bean id="multipartResolver" class= "org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="defaultEncoding" value="UTF-8" /> <property name="maxUploadSize" value="2097152" /> </bean>
2、实现文件上传功能
(1)创建一个名称为files.json的记录文件。
为了便于对files.json文件内容的存取,创建和files.json内容对应的资源类Resource,Resource类的具体代码如下所示。
public class Resource { private String name; //name属性表示文件名称 public Resource() { } public Resource(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
(2)创建名称为JSONFileUtils的工具类。
import org.apache.commons.io.IOUtils; import java.io.FileInputStream; import java.io.FileOutputStream; public class JSONFileUtils { public static String readFile(String filepath) throws Exception { FileInputStream fis = new FileInputStream(filepath); return IOUtils.toString(fis); } public static void writeFile(String data, String filepath) throws Exception { FileOutputStream fos = new FileOutputStream(filepath); IOUtils.write(data, fos); } }
(3)创建名称为FileController的控制器类,在FileController类中定义处理文件上传的方法fileUpLoad(),fileUpLoad()方法用于保存客户端上传的文件和文件的名称。保存上传的文件之前,先将上传文件的名称和files.json文件中的文件名称进行比较,如果files.json文件中已经有同名文件,则将上传文件的名称与字符串("1")拼接,生成新的文件名称并保存。上传文件保存成功后,将保存的文件的名称存入到files.json中。
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.itheima.pojo.Resource; import com.itheima.utils.JSONFileUtils; 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 org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import sun.misc.BASE64Encoder; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; @Controller public class FileController { /** * 文件上传 */ @RequestMapping("fileload") public String fileLoad(MultipartFile[] files, HttpServletRequest request) throws Exception { //设置上传的文件所存放的路径 String path = request.getServletContext().getRealPath("/") + "files/"; ObjectMapper mapper = new ObjectMapper(); if (files != null && files.length > 0) { //循环获取上传的文件 for (MultipartFile file : files) { //获取上传文件的名称 String filename = file.getOriginalFilename(); ArrayList<Resource> list = new ArrayList<>(); //读取files.json文件中的文件名称 String json = JSONFileUtils.readFile(path + "/files.json"); if (json.length() != 0) { //将files.json的内容转为集合 list = mapper.readValue(json, new TypeReference<List<Resource>>() { }); for (Resource resource : list) { //如果上传的文件在files.json文件中有同名文件,将当前上传的文件重命名,以避免重名 if (filename.equals(resource.getName())) { String[] split = filename.split("\\."); filename = split[0] + "(1)." + split[1]; } } } // 文件保存的全路径 String filePath = path + filename; // 保存上传的文件 file.transferTo(new File(filePath)); list.add(new Resource(filename)); json = mapper.writeValueAsString(list); //将集合中转换成json //将上传文件的名称保存在files.json文件中 JSONFileUtils.writeFile(json, path + "/files.json"); } request.setAttribute("msg", "(上传成功)"); return "forward:fileload.jsp"; } request.setAttribute("msg", "(上传失败)"); return "forward:fileload.jsp"; } }
3、实现获取文件列表功能
在FileController中新增获取文件列表的方法getFilesName(),getFilesName()方法获取files.json文件中的内容,并且以JSON格式返回数据。
@ResponseBody @RequestMapping(value = "/getFilesName", produces = "text/html;charset=utf-8") public String getFilesName(HttpServletRequest request, HttpServletResponse response) throws Exception { String path = request.getServletContext(). getRealPath("/") + "files/files.json"; String json = JSONFileUtils.readFile(path); return json; }
4、编写文件上传和下载页面
(1)创建名称为fileupload.jsp的文件,在fileupload.jsp文件中创建一个文件上传表单,文件上传表单可以发起多文件上传请求。
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>文件上传和下载</title> <script src="${ pageContext.request.contextPath }/js/jquery-3.6.0.js" type="text/javascript"></script> </head> <body> <table border="1"> <tr> <td width="200" align="center">文件上传${msg}</td> <td width="300" align="center">下载列表</td> </tr> <tr> <td height="100"> <form action="${pageContext.request.contextPath}/fileload" method="post" enctype="multipart/form-data"> <input type="file" name="files" multiple="multiple"><br/> <input type="reset" value="清空"/> <input type="submit" value="提交"/> </form> </td> <td id="files"></td> </tr> </table> </body> </html>
(2)fileupload.jsp加载完成,自动发起异步请求获取文件下载列表并且展示在页面中。
<script> $(document).ready(function () { var url = "${pageContext.request.contextPath }/getFilesName"; $.get(url, function (files) { var files = eval('(' + files + ')'); for (var i = 0; i < files.length; i++) { $("#files").append("<li>" + "<a href=${pageContext.request.contextPath }" + "" + "\\" + "download?filename=" + files[i].name + ">" + files[i].name + "</a></li>"); } }) }) </script>
5、启动chapter13项目,在浏览器中访问fileupload.jsp页面,访问地址为http://localhost:8080/chapter13/fileload.jsp。单击所示的“浏览...”按钮,弹出“文件上传”对话框。
6、在“文件上传”对话框中,选择需要上传的文件进行上传,在此,选中2个同时上传的文件。 单击所示对话框的右下角“打开”按钮,完成上传文件的选择。完成文件选择之后,“文件上传”对话框自动关闭。
7、在fileupload.jsp页面显示中,“浏览...”按钮后面显示选择了2个文件。单击“提交”按钮向服务端发送上传请求。左侧栏显示文件上传成功信息,右侧的栏中展示了刚上传成功的文件列表。
三、中文乱码问题
在实现文件下载的功能时,还需要注意文件中文名称的乱码问题。在使用Content-Disposition设置参数信息时,如果Content-Disposition中设置的文件名称出现中文字符,需要针对不同的浏览器设置不同的编码方式。目前Content-Disposition支持的编码方式有UrlEncode编码、Base64编码、RFC2231编码和ISO编码。本案例不对全部浏览器的编码方式进行设置,只对FireFox浏览器和非FireFox浏览器(如IE)分别进行编码设置。
8、在文件FileController.java中新增一个方法getFilename(),根据浏览器进行编码设置,并返回编码后的文件名。 新增一个方法fileDownload(),用于下载文件。方法getFilename()的核心代码如下。
/** * 根据浏览器的不同进行编码设置,返回编码后的文件名 */ public String getFileName(HttpServletRequest request, String filename) throws Exception { BASE64Encoder base64Encoder = new BASE64Encoder(); String agent = request.getHeader("User-Agent"); if (agent.contains("Firefox")) { // 火狐浏览器 filename = "=?UTF-8?B?" + new String (base64Encoder.encode(filename.getBytes("UTF-8"))) + "?="; } else { // IE及其他浏览器 filename = URLEncoder.encode(filename, "UTF-8"); } return filename; }