知识点
文件上传(File Upload):
- 创建一个控制器方法,使用 MultipartFile 参数来接收上传的文件。
- 在 Spring 配置文件中配置一个 MultipartResolver,常用的实现类是 CommonsMultipartResolver。
- 在 MultipartResolver 的配置中设置最大允许上传文件的大小。
- 在控制器方法中,使用 MultipartFile 的方法获取上传文件的信息,如文件名、大小、内容等。
- 使用 MultipartFile 的 transferTo() 方法将上传的文件保存到指定位置。
文件下载(File Download):
- 创建一个控制器方法,返回类型为 ResponseEntity<byte[]>,表示要下载的文件。
- 使用 HttpHeaders 类设置响应的头信息,包括文件名、文件类型等。
- 使用 Java IO 或其他工具类读取要下载的文件,并将内容设置到 ResponseEntity<byte[]> 中的字节数组中。
- 将包含文件内容和响应头信息的 ResponseEntity<byte[]> 对象作为控制器方法的返回值。
实现步骤
首先,在前端需要定义一个HTML表单来实现上传文件的功能:
<form action="upload" method="post" enctype="multipart/form-data">
<input type="file" name="file"/>
<button type="submit">上传文件</button>
</form>
注意,表单的enctype
属性必须设置为multipart/form-data
,否则无法上传文件。
接下来,在后端需要编写控制器方法来处理上传文件的请求:
@Controller
public class FileController {
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public String upload(@RequestParam("file") MultipartFile file) throws IOException {
// 获取上传文件的名称
String fileName = file.getOriginalFilename();
// 文件保存路径
String filePath = "path/to/save/" + fileName;
// 将文件保存到磁盘上
file.transferTo(new File(filePath));
return "redirect:/success.html";
}
}
在上述代码中,@RequestParam("file")
注解表示获取名为file
的上传文件。MultipartFile
类是Spring提供的文件上传类,可以通过该类的方法获取上传文件的名称、大小等属性,并将文件保存到磁盘上。
在后端下载文件时,我们需要编写一个控制器方法来返回文件的字节数组:
@Controller
public class FileController {
@RequestMapping("/download")
public ResponseEntity<byte[]> download() throws IOException {
// 获取要下载的文件路径
String filePath = "path/to/download/file";
// 读取文件内容到字节数组中
byte[] bytes = Files.readAllBytes(Paths.get(filePath));
// 构造响应头部信息,包括下载文件名和文件类型
HttpHeaders headers = new HttpHeaders();
headers.setContentDispositionFormData("attachment", "filename.txt");
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
// 返回字节数组和响应头部信息
return new ResponseEntity<>(bytes, headers, HttpStatus.OK);
}
}
在上述代码中,通过Files.readAllBytes()
方法将文件内容读取到字节数组中,并使用ResponseEntity<byte[]>
类封装字节数组和响应头部信息,最终返回给客户端进行下载。
在前端需要定义一个下载链接,用于触发下载文件的操作:
<a href="download">下载</a>
当用户点击该链接时,浏览器会发送一个请求到服务器,调用上述控制器方法来返回文件内容。浏览器会根据响应头部信息,自动弹出保存文件的对话框,让用户选择保存文件的位置。
可直接使用的Demo示例
@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";
}
@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;
}
/**
* 根据浏览器的不同进行编码设置,返回编码后的文件名
*/
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;
}
/**
* 文件下载
*/
@RequestMapping("/download")
public ResponseEntity<byte[]> fileDownload(HttpServletRequest request,
String filename) throws Exception {
System.out.println("123");
System.out.println(filename);
filename = java.net.URLDecoder.decode(filename, "utf-8");
System.out.println(filename);
// 指定要下载的文件所在路径
String path = request.getServletContext().getRealPath("/files/");
// 创建该文件对象
System.out.println(filename);
File file = new File(path + File.separator + filename);
// 设置响应头
HttpHeaders headers = new HttpHeaders();
filename = this.getFileName(request, filename);
// 通知浏览器以下载的方式打开文件
headers.setContentDispositionFormData("attachment", filename);
// 定义以流的形式下载返回文件数据
System.out.println(filename);
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
// 使用Sring MVC框架的ResponseEntity对象封装返回下载数据
return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),
headers, HttpStatus.OK);
}
}
文件上传功能:
文件上传方法名为 fileLoad,通过 @RequestMapping 注解指定了请求地址为 "fileload"。该方法使用了 Spring 框架提供的 MultipartFile 类型来接收上传的文件,同时通过 HttpServletRequest 对象获取当前请求的上下文路径,并在该路径下创建一个名为 "files" 的文件夹用于保存上传的文件。该方法还使用了 Jackson 库中的 ObjectMapper 类将集合对象转化为 JSON 格式字符串,并通过封装好的 JSONFileUtils 工具类写入到 files.json 文件中保存。
文件下载功能:
文件下载方法名为 fileDownload,通过 @RequestMapping 注解指定了请求地址为 "download"。该方法通过 HttpServletRequest 对象获取当前请求的上下文路径,然后构造一个文件对象,通过 ResponseEntity 类型封装该文件返回给客户端进行下载。在该方法中还有一个 getFileName 方法,用于在不同浏览器中对文件名进行编码处理,避免出现乱码问题。
<%@ 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>
<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++) {
result=files[i].name
files[i].name=encodeURI(files[i].name);
files[i].name=encodeURI(files[i].name);
$("#files").append("<li>" +
"<a href=${pageContext.request.contextPath }" + "" +
"\\" + "download?filename=" + files[i].name + ">" +
result + "</a></li>");
}
})
})
</script>
</html>
页面包含一个表格,其中第一行为文件上传的部分,第二行为文件下载列表的部分。在文件上传的部分,用户可以选择要上传的文件,并通过提交按钮将文件上传到服务器。在文件下载列表的部分,页面通过 AJAX 异步请求获取服务器端返回的文件列表数据,并使用 jQuery 库对数据进行处理和展示。
在
<script>
标签中的 JavaScript 代码中,首先通过$.get()
方法发送 GET 请求获取服务器返回的文件列表数据,然后遍历文件列表,将每个文件的名称作为链接展示在页面上。点击链接时,会跳转到下载功能的地址,并将文件名作为参数传递给下载功能。需要注意的是,为了避免文件名中的特殊字符引起的问题,JavaScript 代码中使用了encodeURI()
方法对文件名进行编码处理。
演示具体: