上传文件
最近在学习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
。
运行测试
做完这些我们直接在浏览器中进入前端测试页面,看到的是这个样子:
选择一个图片进行上传后,浏览器会接收到上传成功的图片链接:
![](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) { 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); } }
|
最终测试
我们再次进入浏览器上传图片,得到如下链接:
复制链接并打开,图片显示正常,这里不放全图了:
![显示结果](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