引言:
在springboot文件上传应用中,用的最多的就是将文件保存到系统的绝对路径中,这种方式对于系统的移植部署很不友好,而且需要更改大量的路径。这里本人总结出一种相对好移植部署的动态文件夹保存上传文件的方式。
一、配置springboot文件上传临时文件夹
说是临时文件夹,只要我们自定义该文件夹不在系统的临时文件夹如Tmp文件夹就可以永久保存。这里本人将该文件夹定义在和项目同级别的文件夹中uploadTmp中。具体配置如下:
@Configuration
public class UploadFileConfig {
@Bean
public MultipartConfigElement multipartConfigElement() {
MultipartConfigFactory factory = new MultipartConfigFactory();
// tmp.dir参数在启动脚本中设置
String path = System.getProperty("user.dir");
String location = path + "/uploadTmp";
File tmpFile = new File(location);
// 如果临时目录不存在则创建
if (!tmpFile.exists()) {
tmpFile.mkdirs();
}
// 明确指定上传文件的临时目录
factory.setLocation(location);
//文件最大
factory.setMaxFileSize(DataSize.parse("50MB")); //KB,MB
/// 设置总上传数据总大小
factory.setMaxRequestSize(DataSize.parse("1024MB"));
return factory.createMultipartConfig();
}
}
这里通过String path = System.getProperty("user.dir");来动态的获取当前项目所在的目录,而不是写死成绝对路径,这样,以后移植也是零更改。
二、在文件上传处理Controller中保存文件
@PostMapping("/photoUpload")
@ResponseBody
public Map<String, Object> postPhotoUpload(
HttpServletRequest request
){
Map<String, Object> map = new HashMap<>();
MultipartHttpServletRequest params = ((MultipartHttpServletRequest)request);
List<MultipartFile> files = params.getFiles("photos");
// String contextPath = request.getSession().getServletContext().getRealPath("uploadPhotoGallery");
//String contextPath = this.getClass().getClassLoader().getResource("static").getFile();
//System.out.println(contextPath);
String path = System.getProperty("user.dir");
String contextPath = path + "/uploadTmp";
File folder = new File(contextPath,"uploadPhotoGallery");
if(!folder.isDirectory() || !folder.exists()){
folder.mkdirs();
}
List<String> photoUrls = new ArrayList<>();
for(MultipartFile file : files){
System.out.println(file.getOriginalFilename());
String fileType = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."), file.getOriginalFilename().length());
String newName = UUID.randomUUID().toString()+fileType;
try {
file.transferTo(new File(folder,newName));
// String photoUrl = request.getScheme() + "://"+request.getServerName() + ":" + request.getServerPort()+"/uploadPhotoGallery/" + newName;
// String photoUrl = request.getScheme() + "://"+request.getServerName() + ":" + request.getServerPort()+"/uploadPhotoGallery/" + newName;
String photoUrl = "/uploadTmp/uploadPhotoGallery/" + newName;
photoUrls.add(photoUrl);
} catch (IOException e) {
e.printStackTrace();
}
}
map.put("code", 0);
map.put("urls",photoUrls);
return map;
}
这里本人也是疯狂尝试啊,各种方法都用过,其他方法大多都是IDEA中一点问题没有,但是一旦打包成jar包运行后就各种报错。
到这一步就可以实现动态的将文件保存到和项目同级别的uploadTmp/uploadPhotoGallery中了。但是现在因为和项目同级别的文件夹并不在项目的classpath中,所以是无法直接通过路径访问到的,所以还需要进行一项路径的映射。
三、文件路径映射
/**
* 资源映射路径
*/
@Configuration
public class MyWebAppConfigurer implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/uploadTmp/**").addResourceLocations("file:"+System.getProperty("user.dir")+"/uploadTmp/");
System.out.println("file:"+System.getProperty("user.dir")+"/uploadTmp/");
}
}
这里映射依旧是通过System.getProperty("user.dir");来获取当前项目路径的,所以不管你移植时候是在D盘还是F盘或者Linux中的/home文件夹,都无所谓。举个例子:这里我这个系统将/D/file_admin/uploadTmp/文件夹映射成/uploadTmp/。这样就可以直接通过路径访问了。
Note:这里的路径和Controller中的:
...
String photoUrl = "/uploadTmp/uploadPhotoGallery/" + newName;
photoUrls.add(photoUrl);
...
相对应,这样返回给前端的路径就是:
然后加上自己的主机ip和端口就可以访问文件啦!
演示:
1、上传文件
2、上传成功,返回前端图片的url
3、拿到url加上自己的ip:端口+url访问文件
这里之所以不在controller中直接加上ip和端口也是为了方便以后移植后需要更改文件路径的麻烦,因为可能后续这些url是需要保存到数据库中的,如果把ip和端口写死了,那么移植又会出现问题。如果不考虑移植,可以直接在controller返回url地方写成:
String photoUrl = request.getScheme() + "://"+request.getServerName() + ":" + request.getServerPort()+"/uploadTmp/uploadPhotoGallery/" + newName;
这样返回的就是完整的图片URL,可以直接复制URL进行访问或者进行后续的开发工作。
如果有更好的解决方案,欢迎评论区进行讨论!