上传文件
最近在学习springboot的文件上传过程中遇到一些问题,后来结合一些帖子,发现一个比较方便的解决方法。
很多资料上的例子都是将文件存放在tomcat的临时文件目录之类的位置,访问时只需要在浏览器输入localhost:8080/xxx/xxx.xxx
即可。但是由于某种需求,或者避免文件存在特殊位置会被误删,导致后续相关操作出错。
我们需要将文件存放在指定位置,例如:D:/file
或者/home/root/file
。很显然,这时使用localhost:8080/D:/file/xxx.xxx
或者localhost:8080/xxx.xxx
等都是无法正确访问的。
这里我是通过配置虚拟路径来解决的,例如:将/files/**
映射为D:/file
。配置完成后,上传文件完毕,再输入localhost:8080/files/xxx.xxx
就可查看该文件了。
上传方法
首先使用一个比较简单的方法用于上传文件。
@RestController
public class FileController {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy/MM/dd/");
@PostMapping("/upload")
public String upload(MultipartFile file, HttpServletRequest req) {
String realPath=req.getSession().getServletContext().getRealPath("/uploadFile/");
String format=sdf.format(new Date());
File folder=new File(realPath+format);
if(!folder.isDirectory()){
if(!folder.mkdirs()){
return "文件夹创建失败";
}
}
String oldName=file.getOriginalFilename();
String newName= UUID.randomUUID().toString()+oldName.substring(oldName.lastIndexOf("."),oldName.length());
try {
file.transferTo(new File(folder,newName));
String filePath=req.getScheme()+"://"+req.getServerName()+":"+req.getServerPort()+"/uploadFile/"+format+newName;
return filePath;
}catch (IOException e){
e.printStackTrace();
}
return "上传失败!";
}
}
这里面的:
String realPath=req.getSession().getServletContext().getRealPath("/uploadFile/");
是用来获取工程的绝对路径,得到的值是这种形式(示例为linux下):
/tmp/tomcat-xxx.xxxxxxxxxxxxxx.8080/uploadFile/
后面再拼接日期2020/07/19/
。文件夹创建完成后,就可以将文件写入相应位置了。
这里还要注意一下folder.mkdirs()
和folder.mkdir()
的区别。
代码中的文件名以随机生成的UUID+后缀名构成。所有操作完成后,便返回该文件的url值。
前端页面
接着,在/resources/static
下写一个简单的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">
<input type="file" name="file" value="请选择文件">
<input type="submit" value="上传">
</form>
</body>
</html>
注意name
的名字要和前面方法接收的MultipartFile
的参数名一样,这里统一用file
。
运行测试
做完这些我们直接在浏览器中进入前端测试页面,看到的是这个样子:
选择一个图片进行上传后,浏览器会接收到上传成功的图片链接:
复制这个链接并访问,即可查看上传的图片:
修改为自定义路径
下面我们要将文件保存的位置设在另外的地方,这里改为自己喜欢的位置/home/root/Documents/WebFiles/test/pic/
。需要修改folder
的路径还有返回的filePath
路径。realPath
这个参数已经用不上了,我们可以把它删掉。
这里要注意folder
的路径,要确保那个位置你的应用是有权限进行操作的,否则会创建文件夹失败。
@PostMapping("/upload")
public String upload(MultipartFile file, HttpServletRequest req) {
// 删除 String realPath=req.getSession().getServletContext().getRealPath("/uploadFile/");
// 省略部分内容
File folder=new File("/home/root/Documents/WebFiles/test/pic/"+format);
// 省略部分内容
try {
// 省略部分内容
String filePath=req.getScheme()+"://"+req.getServerName()+":"+req.getServerPort()+"/test/pic/"+format+newName;
return filePath;
}catch (IOException e){
e.printStackTrace();
}
return "上传失败!";
}
通过代码不难看出,如果我们按照这里返回的路径去查看图片,肯定是出错的。这里就不进行测试了,大家可以自行尝试。
配置虚拟路径
这里采用实现WebMvcConfigurer
接口并重写addResourceHandlers
的方法,还有一种通过继承WebMvcConfigurerAdapter
的方法,已经被废弃了。
为了方便,示例代码直接在当前类中实现了WebMvcConfigurer
接口。不知道这样算不算正规的写法,请大家谨慎参考。
我们将/files/**
映射为/home/root/Documents/WebFiles/
,这时,浏览器只需要输入localhost:8080/files/
便可以访问/home/root/Documents/WebFiles/
下的文件。
重写完方法后,前面的upload
方法需要修改一下返回路径,在原路径前增加/files
即可返回正确的路径.
@RestController
public class FileController implements WebMvcConfigurer{
SimpleDateFormat sdf=new SimpleDateFormat("yyyy/MM/dd/");
@PostMapping("/upload")
public String upload(MultipartFile file, HttpServletRequest req) {
// 省略部分内容
String filePath=req.getScheme()+"://"+req.getServerName()+":"+req.getServerPort()+"/files/test/pic/"+format+newName;
// 省略部分内容
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/files/**").addResourceLocations("file:/home/root/Documents/WebFiles/");
WebMvcConfigurer.super.addResourceHandlers(registry);
}
}
最终测试
我们再次进入浏览器上传图片,得到如下链接:
复制链接并打开,图片显示正常,这里不放全图了:
可以看到,图片真正所在位置是位于/home/root/Documents/WebFiles/test/pic/2020/07/19
即我们设置/files
映射的位置+/test/pic/2020/07/19
。
到这里,修改基本完成了,最后放上修改完成后的完整代码:
@RestController
public class FileController implements WebMvcConfigurer{
SimpleDateFormat sdf=new SimpleDateFormat("yyyy/MM/dd/");
@PostMapping("/upload")
public String upload(MultipartFile file, HttpServletRequest req) {
String format=sdf.format(new Date());
File folder=new File("/home/root/Documents/WebFiles/test/pic/"+format);
if(!folder.isDirectory()){
if(!folder.mkdirs()){
return "文件夹创建失败";
}
}
System.out.println(folder.getPath());
String oldName=file.getOriginalFilename();
String newName= UUID.randomUUID().toString()+oldName.substring(oldName.lastIndexOf("."),oldName.length());
try {
file.transferTo(new File(folder,newName));
String filePath=req.getScheme()+"://"+req.getServerName()+":"+req.getServerPort()+"/files/test/pic/"+format+newName;
return filePath;
}catch (IOException e){
e.printStackTrace();
}
return "上传失败!";
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/files/**").addResourceLocations("file:/home/root/Documents/WebFiles/");
WebMvcConfigurer.super.addResourceHandlers(registry);
}
}