SpringBoot(六)——文件上传
前言
总结一定要看
文件上传中并没有什么太多的知识点,因为SpringBoot中内嵌一个Tomcat,而且SpringBoot项目不仅可以打包成一个WAR包,还可以打包成JAR包。这个时候问题就来了,如果我们的项目被封装成一个Jar包,这样我们文件路径访问不到JAR包内部的路径,所以可能会出现问题。因为传统文件上传中我们时间文件最终存储在Tomcat中的项目目录中,所以我们为了避免上述情况出现,本篇笔记会简单说明传统的文件上传的逻辑以及代码。最后会更加细化一些小细节。
文件上传
前端页面
form表单提交文件需要加参数:
<%--
表单提交的方式必须是post类型
如果该form表单是用来上传文件的话,则enctype的类型必须为:multipart/form-data
后台接收变量的名称必须与前端所提交的名称必须一样
--%>
<form action="${pageContext.request.contextPath}/download.action" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit" value="上传">
</form>
- 注意提交的表单参数一定要为:
multipart/form-data
; - 填充文件的的
input
标签中的类型必须为file
。
控制器
控制器中我们接收文件的参数类型不是普通的File类型,具体如下:
private final Logger log = LoggerFactory.getLogger(DownLoadController.class);
// 文件上传控制器
@RequestMapping("download.action")
public String downLoad(MultipartFile file, HttpServletRequest request) throws IOException {
log.debug("文件名:{}",file.getOriginalFilename());
log.debug("文件大小:{}",file.getSize());
/*
* 将上传的文件保存在项目目录中,且为了在项目部署移植之后依然可以存入对应的目录文件中
* 我们会动态获取项目名
* */
String DOWNLOAD_PATH = request.getSession().getServletContext().getRealPath("/upload");
file.transferTo(new File(DOWNLOAD_PATH,file.getOriginalFilename()));
// 重定向到表单页面
return "redirect:/index.jsp";
}
但是现在这个文件上传仅能上传1MB大小的文件,因为Multipart默认的文件大小上限为1MB,超过之后会报500
异常,所以我们需要在配置文件中设置该参数:
spring:
# 设置文件上传大小的上限
servlet:
multipart:
# 文件上传大小上限
max-file-size: 10MB
# 最大请求大小
max-request-size: 10MB
文件上传细节
我们在上传文件的时候,传统的方式都是将上传的文件存入项目目录中,如果想将项目封装成Jar包或者War包时都可以正常运行(做到上传的文件和项目目录是分离存放),这样我们可以使用指定项目目录的方式来存储上传文件,但是如果在代码中将路径写死,不符合编程规范。所以我们将指定的目录书写到配置文件中,然后将配置问价哪种定义的路径值注入到类的成员变量中。:
upload:
file:
dir: d:/tmp/file/
@Value(${upload.file.dir})
private String dir;
这个样子虽然没有什么太大的技术性,但是SpringBoot可以加载外部(远程)配置文件来读取启动,这个样子我们可以根据不同需求,不同的系统来执行不同的配置来上传文件。
**【注】:**企业级开发的文件上传其实也不使用这种方式来进行文件的存储了,几年前的文件存储会使用FastDFS(分布式文件存储系统)来作为文件存储服务器;现在的话大厂一般会搭建自己的文件存储服务器,小厂的话一般会使用阿里旗下的OOS(对象存储)等相关技术产品来存储文件,所以FastDFS已经成为了某种程度的过去时了,大家可以尝试学习搭建服务器和阿里旗下的相关工具的使用。
文件下载
文件下载的本质其实就是文件的复制拷贝,这个时候我们需要得到的是被下载文件的绝对路径,也就是资源在服务器中的对应位置,然后将被下载的文件通过一些技术手段存到本地空间中。
@Request("download")
public void download(String fileName, HttpServletResponse) throws Exception {
File file = new File(fileName);
FileInputStream is = new FileInputStream(file);
ServletOutputStream os = response.getOutputStream();
// 下面的代码不对,领会精神,懒得写小车了。
FileUtils.copy(is,os);
}
- 上述代码中完成的是将资源响应到网页上(客户端中),我们可以在浏览器的页面中查看显示到页面的内容。
总结
文件上传和下载需要按照实际的业务需求来进行实现,所以在这里仅仅提供上传和下载的逻辑,具体的卢纶大家可以自行体会。
需要注意的是,Java中对文件进行相关操作的时候会因为字符编码集的不一致而出现文件损坏或者乱码,简单说明这个问题的成因:
Java语言在不同的版本以及不同的平台的编码集存在着不同,比如我们较早的版本中我们的Java字符编码集在MacOS的平台中因为系统环境的问题可能会导致Java默认字符编码集发生改变。而Java中关于文件类的相关方法中有很多方法不同于我们常见的String
类中的相关方法,File类中的一些方法没有设置字符编码集的属性,即:这些方法使用的是默认的字符编码集。
在这种情况下,需要思考一个问题,即:Java作为可移植、跨平台的语言,如果因为系统平台的不同(字符编码集不同),导致文件损坏或乱码,那么会发生很大的问题。
所以官方一共给出一个解决方法以及三个备选方案:
- 解决方案:在部署项目上线的时候一定要将字符编码集中的默认值更改为
UTF-8
,File类中无法自定义字符编码记得方法也会默认使用UTF-8
,这样可以直接杜绝这种问题; - 备选方法:
- 保持现状(个人觉得这句话就是一个废话);
- 弃用无法自定义字符编码集的方法,鼓励大家使用可自定义字符编码集的方法(官方的解释说会造成代码冗余,不过我感觉程序员的理论、技术水准可以有很大的提升);
- 平台直接将Java语言的默认字符编码集设置为
UTF-8
,这样的确可以完全解决这个问题,但是这项更改会导致兼容性出现很大问题,主要是新老系统对接和项目移植的时候。
**【注】:**本篇文章最后的总结中所说明的问题来自于JEP草案JEP 400:默认为 UTF-8中,大家感兴趣的话可以去看看。