SPRINGBOOT上传文件到自定义路径并查看

Posted by Sunfy on 2023-05-12
Words 1.4k and Reading Time 6 Minutes
Viewed Times
Viewed Times
Visitors In Total

上传文件

最近在学习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就可查看该文件了。

上传方法

首先使用一个比较简单的方法用于上传文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@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 "上传失败!";
}
}

这里面的:

1
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页面用于测试。

1
2
3
4
5
6
7
8
9
10
11
12
13
<!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

运行测试

做完这些我们直接在浏览器中进入前端测试页面,看到的是这个样子:

image-20230512112843766

image-20230512113040896
选择一个图片进行上传后,浏览器会接收到上传成功的图片链接:
![](https://www.freesion.com/images/87/f9ef1acdbe3b3fd787691835592abeb7.png

修改为自定义路径

下面我们要将文件保存的位置设在另外的地方,这里改为自己喜欢的位置/home/root/Documents/WebFiles/test/pic/。需要修改folder的路径还有返回的filePath路径。realPath这个参数已经用不上了,我们可以把它删掉。

这里要注意folder的路径,要确保那个位置你的应用是有权限进行操作的,否则会创建文件夹失败。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@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即可返回正确的路径.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@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);
}
}

最终测试

我们再次进入浏览器上传图片,得到如下链接:
image-20230512113209010
复制链接并打开,图片显示正常,这里不放全图了:
![显示结果](https://www.freesion.com/images/335/71db8e30ea0dcb9f4bd8ab248c67f03f.png
可以看到,图片真正所在位置是位于/home/root/Documents/WebFiles/test/pic/2020/07/19即我们设置/files映射的位置+/test/pic/2020/07/19

到这里,修改基本完成了,最后放上修改完成后的完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@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);
}
}

Copyright 2021 sunfy.top ALL Rights Reserved

...

...

00:00
00:00