文件的上传和下载的实现原理的简单介绍
表单的构成
首先,我们先来介绍我们的需要用到的表单,在这个表单中,首先值得我们注意的就是,在type为file的input标签中.这个控件是我们主要用来选择上传的文件的, 除此之外,我们要想实现文件的上传,还需要将method的属性的值设置为post,只有当请求方式为post的时候才能携带数据.以及enctype属性的值设置为multipart/form-data, 表示告诉浏览器以流的方式来处理我们的数据,这样在后台才能进行解析. 简单来说,在页面中,要想实现文件的上传需要进行必要的三个设置:
- 将input标签的type属性设置为file
- 将form标签的method的属性的值设置为post
- 将form标签的enctype属性的值设置为multipart/form-data
还有一点就是在H5之后,出现了一个新的属性叫做multiple,这个属性用在文件上传框中,可以一次上传多个文件.
然后,就是用来展示已经上传的文件的列表 列表的实现非常的简答,我们只只需要在页面加载的时候向后台发送一个请求,向负责文件读取的控制器请求一下文件列表,然后将获取的文件列表追加到表格中, 这个文件的编写比较重要的就是from属性的配置,以及在追加文件列表的时候注意标签和变量的拼接
页面代码:
<%--
Created by IntelliJ IDEA.
User: 33680
Date: 2023/3/29
Time: 8:25
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<html>
<head>
<title>文件的上传和下载</title>
<script src="${pageContext.request.contextPath}/js/jquery-3.6.4.min.js"
type="text/javascript">
</script>
<style>
table{
border: 2px solid black;
}
td{
border: 1px solid black;
}
</style>
</head>
<body>
<form action="${pageContext.request.contextPath}/fileUplode" method="post" enctype="multipart/form-data">
<table>
<tr>
<td width="200" align="center">文件上传${msg}</td>
<td width="200" align="center">下载列表</td>
</tr>
<tr>
<td>
<input type="file" name="files" multiple="multiple">
<input type="reset" value="清空">
<input type="submit" value="提交">
</td>
<td id="files"></td>
</tr>
</table>
</form>
<script>
$(document).ready(function (){
var url = "${pageContext.request.contextPath}/getFileName";
$.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>
</body>
</html>
文件上传
在文件的上传这部分,首先我们需要获取文件的列表,所以我们需要使用SpringMVC的MultipartFile类来封装,要使用这个类,我们首先需要在配置文件中配置多部件解析器
多部件解析器
多部件解析器就是一个JavaBean,所以我们需要在spring-mvc.xml文件中进行配置,需要注意的是,这个JavaBean的id的值是固定的,所以我们在配置的时候需要注意 然后我们就可以配置其他属性了,我们使用依赖注入的方式向里面注入配置参数:
- defaultEncoding:这个属性是配置请求的编码格式,一般为UTF-8
- maxUploadSize:这个属性是限制上上传的文件的大小,单位是字节
在配置完成多部件解析器之后,我们就可以顺利的使用SpringMVC的MultipartFile类来处理上传的文件了. 对于这个类的使用,我们使用最频繁的方法主要有两个:
- isEmpty():这个方法用来判断上传的文件是否为空
- transferTo(File file):这个方法的功能是保存文件
文件上传的基本流程是:首先,我们从页面中上传文件到后台,然后后台使用MultipartFile类来封装文件,如果文件不为空,则将其使用transferTo()方法保存到我们设置的路径中.
在上传文件时对重名文件的处理
在我们上传文件的时候,可能会遇到重名的文件,对于重名的文件,我们要做一些设置改变他原有的名字.首先,我们要创建一个文件叫做files.json文件这个文件的作用是存放我们的文件名字. 在我们保存文件之前,我们要先读取这个文件,对于这个文件的读写操作,我们都封装进了一个工具类中,可以方便我们对文件信息类的操作, 之后,判断读取到的文件内容,如果内容为空,则表示是第一个文件,直接保存.如果文件中有内容,我们就将数据信息文件中的内容读取出来,并且封装进一个类中,更加方便我们在Java中操作这个数据信息. 然后我们会判断文件名是否重名,如果重名了,则将原来的文件名以”.”进行分割,然后在中间拼接上一个”(1)”,变成一个新的文件名进行保存.
文件下载
对于文件的下载就比较简单了,基本的格式都是固定的
- 首先我们设置被下载的文件所在的文件夹的路径
- 一般,我们要下载文件的时候会携带一个下载文件的请求,我们就可以使用文件夹路径和请求中携带的文件名参数拼接成唯一的文件路径,然后通过文件路径创建文件对象
- 创建响应头对象,然后设置响应头,告诉浏览器我要对文件进行下载,并且以流的形式处理文件
- 最后,我们使用Spring的ResponseEntity类对下载的文件进行处理操作,直接返回ResponseEntity类的对象,流处理的文件,响应头对象和响应状态码
文件名的的编码转换
我们接收到的文件的编码可能会导致出错,所以我们可能需要对文件名进行转码,转码的方式也很简单:
- 首先我们要判断发送请求的浏览器是否为火狐,如果是火狐我们需要按照火狐的方式修改编码
- 然后就是判断如果不是火狐,则直接使用普通的方式修改文件编码即可
文件列表的展示
在之前我们上传文件的时候,我们会将上传的文件的文件名写入到一个json文件中,一个是用来判断文件是否重名,另一个作用是我们可以读取里面的信息, 传递到页面中形成一个列表,让我们的对文件有一个更直观的了解. 对于列表的展示,我们只需要获取json文件的路径,然后使用我们之前创建的JSON文件读取写入工具类,将我们的JSON文件的内容读取到页面中,然后在页面中对读取的数据进行处理之后展示出来即可
JSON文件操作工具类:
package SpringMVC.Upload_and_download.utils;
//这个包是在之前我们学过的方便我们对文件的读写操作的类
import org.apache.commons.io.IOUtils;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
//这个类的作用是方便我们对JSON文件的读取操作
public class JSONFileUtils {
// 读取文件中的内容
public static String readFile(String filepath) throws IOException {
// 根据传递进来的参数,创建文件输出流,将文件中的内容输出获取出来
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);
}
}
JSON文件映射类:
package SpringMVC.Upload_and_download;
//这个类的作用是为了方便Json内容的读取,我们创建与Json内容对应的实体类方便我们在Java代码中的操作
public class Resource {
private String name;
@Override
public String toString() {
return "Resource{" +
"name='" + name + '\'' +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Resource(String name) {
this.name = name;
}
public Resource() {
}
}
文件上传下载控制器:
package SpringMVC.Upload_and_download.utils;
import SpringMVC.Upload_and_download.Resource;
import com.fasterxml.jackson.databind.ObjectMapper;
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 com.fasterxml.jackson.core.type.TypeReference;
import sun.misc.BASE64Encoder;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
//这个类的作用是实现文件的上传和下载
@Controller
public class FileController {
/**
*
* @param files 保存上传的多个文件列表
* @param request 当前请求的信息
* @return 返回的是响应的页面,以请求转发的方式
* @throws Exception 抛出多个异常,直接抛出最大的异常
*/
// 文件的上传
@RequestMapping("/fileUplode")
public String fileUplode(MultipartFile[] files , HttpServletRequest request) throws Exception {
//存放文件存放的路径
String path = request.getServletContext().getRealPath("/") + "files/";
// 创建JSON转换类的对象
ObjectMapper om = new ObjectMapper();
// 判断上传的文件是否为空
if(files!=null && files.length>0){
// 如果文件列表不为空,并且长度大于零,则表示有文件上传,正常进行处理
for(MultipartFile file : files){
//首先获取上传文件的文件名,创建一个列表存放文件信息
// getOriginalFilename()方法是用来获取上传时的文件名
String filename = file.getOriginalFilename();
List<Resource> list = new ArrayList<>();
// 读取文件files.json文件中的数据,判断上传的文件名是否重名
String json = JSONFileUtils.readFile(path+"/files.json");
// 先判断JSON文件中是否有数据,如果没有数据就表示这是第一个上传的文件,肯定不会重名
System.out.println(json.length());
if(json.length()!=0){
// 将JSON文件中的数据转换成集合,方便我们的判断操作
list = om.readValue(json, new TypeReference<List<Resource>>() {
});
for(Resource resource : list){
// 进行判断
if (filename != null && filename.equals(resource.getName())) {
String []strings = filename.split("\\.");
filename = strings[0]+"(1)."+strings[1];
System.out.println(filename);
}
}
}
// 文件保存的完整路径
String Filepath = path+filename;
// 开始保存文件
file.transferTo(new File(Filepath));
list.add(new Resource(filename));
// 将集合中的数据转换成json
json = om.writeValueAsString(list);
// 将上传的文件名称保存在file.json中
JSONFileUtils.writeFile(json,path+"/files.json");
System.out.println(json);
System.out.println(list.toString());
}
// 将文件的上传状态传递到页面中
request.setAttribute("msg","上传成功");
return "forward:/SpringMVC/pages/FIle.jsp";
}
// 当我们没有进入第一个if时,则表示所有的状态都是失败状态,所以我们此处返回失败的状态信息
request.setAttribute("msg","上传失败");
return "forward:/SpringMVC/pages/FIle.jsp";
}
// 实现文件列表的功能
@ResponseBody
@RequestMapping(value = "/getFileName" , produces = "text/html;charset=utf-8")
public String getFileName(HttpServletRequest request) throws IOException {
// 获取项目的路径
String path = request.getServletContext().getRealPath("/")+"files/files.json";
return JSONFileUtils.readFile(path);
}
// 在实现文件下载之前,我们需要先去实现一个解决文件乱码的问题
public String getFileName(HttpServletRequest request,String filename)throws Exception{
// 由于各浏览器支持的编码格式转换的方式不一样,主要体现在火狐浏览器的配置不一样,所以这里需要获取请求头中携带的浏览器型号是不是火狐
BASE64Encoder base64Encoder = new BASE64Encoder();
String agent = request.getHeader("User-Agent");
if(agent.equals("Firefox")){
// 如果是火狐,则需要使用火狐规则的浏览器转码格式
filename = "=?UTF-8?B?"+ base64Encoder.encode(filename.getBytes(StandardCharsets.UTF_8)) +"?=";
}else {
// 其他的就使用统一的转码方式
filename = URLEncoder.encode(filename,"UTF-8");
}
// 最后将转码之后的文件名返回即可
return filename;
}
// 实现文件的下载
@RequestMapping("/download")
public ResponseEntity<byte[]> fileDownload(HttpServletRequest request, String filename)throws Exception{
// 需要下载的文件的根路径
String path = request.getServletContext().getRealPath("/files/");
// filename = new String(filename.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
// 根据传递进来的数据不同下载不同的文件
File file = new File(path+File.separator+filename);
// 创建设置响应头的对象
HttpHeaders headers = new HttpHeaders();
// 将文件名进行转码处理
filename = this.getFileName(request,filename);
// 告诉浏览器我要对这个文件进行下载处理
headers.setContentDispositionFormData("attachment",filename);
// 以流的形式处理文件
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
// 最后返回读取到的文件,在浏览器中就可以显示为下载
// 使用SpringMVC的ResponseEntity处理封装的数据
return new ResponseEntity<>(FileUtils.readFileToByteArray(file), headers, HttpStatus.OK);
}
}
文件目录结构:
注意点
对于文件的上传和下载,我们主要知道大概的流程,和我们需要做的事情即可,可以看到大部分的流程都是固定的,并且大部分都是工具类的使用,所以我们如果实在记不住具体的操作可以随时来复制就可以.
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/153272.html