文件上传是项目开发中最常见的功能,springboot同样支持文件上传,需要使用到MultipartFile,MultipartFile是spring类型,代表HTML中form data方式上传的文件,包含二进制数据+文件名称。
下面具体实现以下文件上传的几种场景:
单文件上传
在springboot中我们实现文件上传,不需要我们添加额外的依赖,已经有默认的配置,我们只需要编写我们的上传逻辑即可,controller如下:
@RestController //这里用RestController的意思是我们不想返回一个页面,返回的是我们文件上传的路径
public class FileUploadController {
SimpleDateFormat sdf = new SimpleDateFormat("/yyyy/MM/dd/"); //这里使用SimpleDataFormat的意思是我们文件上传建议对文件分类,这里就使用日期分类
@PostMapping("/upload") //注意,文件上传必须是post请求
public String upload(MultipartFile file, HttpServletRequest req){//HttpServletRequest用了获取文件保存地址,这里简单处理,将文件保存在项目运行的路径下
String format = sdf.format(new Date());
String realPath = req.getServletContext().getRealPath("/img")+ format; //图片最终保存的位置
File folder = new File(realPath);//创建一个文件夹
if (!folder.exists()){ //如果文件夹不存在,就创建一个
folder.mkdirs();
}
//给上传的文件起一个不会重名的名字
String oldName = file.getOriginalFilename();//获取文件的原名
String newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."));//新文件名为UUID+文件后缀
//保存文件
try {
file.transferTo(new File(folder, newName));
//如果保存失败,我们返回文件的路径
//这里需要注意的是,我们不清楚请求是http还是https,所以不能写死,要动态地获取,其中:
//req.getScheme:返回当前链接使用的协议;比如,一般应用返回http;SSL返回https
//req.getServerName:返回请求网站的域名
//req.getSercerPort:返回请求网站的端口
String url = req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort() + "/img" + format + newName;
return url;
} catch (IOException e) {
e.printStackTrace();
}
return "error";//如果保存失败,返回提示
}
}
在resource/statics目录下创建一个index.html页面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
<!--注意:name="file"需要和后台参数名称对应-->
<input type="file" name="file">
<input type="submit" value="提交">
</form>
</body>
</html>
访问页面,上传一张图片:
上传成功,返回文件存放路径:
我们直接访问这个路径,可以看到图片直接访问到了:
那么,Springboot中有没有文件上传的一些配置呢?比如比如上传文件的大小限制等,那肯定是有的,Springboot中一直贯穿的一个思想就是,你没配置就用默认的,配置了就用配置的,实际上是有默认配置的,我们如果想要修改,直接在application.properties中配置,只需要搜索multipart就出来了,比如这里我们设置单个文件上传的大小为1KB:
#上传的单个文件的大小
spring.servlet.multipart.max-file-size=1KB
#上传的文件总大小
spring.servlet.multipart.max-request-size=10MB
重启项目,上传文件会报错:
报错也很明显,超过为文件大小限制。
Ajax实现文件上传
在Springboot中同样可以使用ajax实现文件的上传,后端代码基本不变,前端代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="jquery-3.3.1.js"></script>
</head>
<body>
<div id="result"></div>
<input type="file" id="file">
<input type="button" value="提交" onclick="fileupload()">
<script>
function fileupload(){
var file = $("#file")[0].files[0]; //这里是单文件上传去数组中的第一个
var formData = new FormData(); //FormData对象可以让我们组织一个使用XMLHttpRequest对象发送的键值对的集合。
// 它主要用于发送表单数据,但是可以独立于使用表单传输的数据。
formData.append("file", file);
$.ajax({
type:'post',
url:'/upload',
processData:false, //意为要不要把我们上传的数据处理为一个对象,默认为true,我们设置为false
contentType:false,//避免让jQuery设置请求头
data:formData,
success:function (msg) {
$("#result").html(msg);
}
})
}
</script>
</body>
</html>
请求效果如下:
图片上传成功,访问图片路径依然是成功的。
注意:
1、IDEA中导入js文件直接将文件拖入页面中,不用写代码导入,非常方便。
2、注意细节,错误地将Ajax中的“ processData”属性拼写成了“ processDate”,一个单词写错导致ajax请求失败,查找原因费了不少时间,罪过啊!
多文件上传
如果是多文件上传,前后台都需要修改一下:
前台:
<body>
<form action="/uploads" method="post" enctype="multipart/form-data">
<input type="file" name="files" multiple>
<input type="submit" value="提交">
</form>
</body>
多文件上传的话,input框要加上“multiple”,后台用一个数组接受,所以name值改为files。
后台代码修改如下:
@PostMapping("/uploads")
public String uploads(MultipartFile[] files, HttpServletRequest req){
String format = sdf.format(new Date());
String realPath = req.getServletContext().getRealPath("/img")+ format;
File folder = new File(realPath);
if (!folder.exists()){
folder.mkdirs();
}
for (MultipartFile file : files) { //使用数组接受,这里遍历一下就可以了,其他不用修改
String oldName = file.getOriginalFilename();
String newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."));
try {
file.transferTo(new File(folder, newName));
String url = req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort() + "/img" + format + newName;
System.out.println(url);
} catch (IOException e) {
e.printStackTrace();
}
}
return "success";
}
访问页面,选择两个文件,点击上传:
控制台打印的路径也能正常访问的。
、