Springboot项目再打成jar包发布的时候,如果图片是存储在项目里面的话会出现部署时候访问不到图片的问题,所以我们需要讲图片存储的位置外部化。
思路
通过Spring提供的Enviroment
类获取系统的环境变量,我们可以用它作如下事情:
获取操作系统,如:getProperty("os.name")
获取不同操作系统的上传路径,如:
upload.os.win.path=D:\
Demo
一、创建一个上传工具类
用于实现功能
WebUploadUtil
,代码如下:
package com.wanju.util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collection;
import java.util.Objects;
/**
* 上传工具类
*
* @author : lzx
* created on 2019/3/21
*/
@Slf4j
public class WebUploadUtil {
public static final String UPLOAD_DIRECTORY = "/upload/";
/**
* @param file 上传文件
* @return 文件依据项目的相对路径+文件名
*/
public static String upload(MultipartFile file) throws IOException {
return upload(file, null, null);
}
/**
* @param file 上传文件
* @param directory 自定义上传目录(为空则使用时间格式yyyy/MM/dd生成目录)
* @return 文件依据项目的相对路径+文件名
*/
public static String upload(MultipartFile file, String directory) throws IOException {
return upload(file, directory, null);
}
/**
* @param file 上传文件
* @param extensionList 需要过滤的文件后缀名
* @return 文件依据项目的相对路径+文件名
*/
public static String upload(MultipartFile file, Collection extensionList) throws IOException {
return upload(file, null, extensionList);
}
/**
* @param file 上传文件
* @param directory 自定义上传目录(为空则使用时间格式yyyy/MM/dd生成目录)
* @param extensionList 需要过滤的文件后缀名
* @return 文件依据项目的相对路径+文件名
*/
public static String upload(MultipartFile file, String directory, Collection extensionList) throws IOException {
if (file.isEmpty()) {
throw new RuntimeException("文件不能为空");
}
String originalFilename = Objects.requireNonNull(file.getOriginalFilename(), "文件名不存在");
int position = originalFilename.lastIndexOf(".");
if (position <= 0) {
throw new RuntimeException("文件名中无文件类型扩展名");
}
//获取文件扩展名(转换小写)
String extension = originalFilename.substring(position + 1).toLowerCase();
if (!CollectionUtils.isEmpty(extensionList) && !extensionList.contains(extension)) {
throw new RuntimeException("上传文件只接受" + String.join("/", extensionList) + "类型,当前文件类型为:" + extension);
}
//若directory为空,则按照时间生成文件目录(按照日期yyyy/MM/dd)
if (StringUtils.isEmpty(directory)) {
directory = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd/"));
}
//拼接系统上传目录
directory = UPLOAD_DIRECTORY + directory;
//生成UUID文件名
String fileName = UUIDUtil.generateUUID() + "." + extension;
String realDirectory = directoryConditionalOS(directory);
//创建目录
Files.createDirectories(Paths.get(realDirectory));
//保存文件
file.transferTo(Paths.get(realDirectory, fileName));
return directory + fileName;
}
private WebUploadUtil() {
}
/**
* 添加路径前缀,根据系统
* @param directory 上传文件相对路径
* @return 真实路径
*/
private static String directoryConditionalOS(String directory) {
ApplicationContext context = SpringUtil.getApplicationContext();
String realDirectory = "";
Environment environment = context.getEnvironment();
String os = environment.getProperty("os.name");
if (os.toUpperCase().contains("WIN") || os.toUpperCase().contains("win")) {
String win = environment.getProperty("upload.os.win");
realDirectory = win + directory;
} else {
String linux = environment.getProperty("upload.os.linux");
realDirectory = linux + directory;
}
return realDirectory;
}
}
二、创建SpringUtil类
方便获取Spring上下文,和环境变量。
创建SpringUtil
类,代码如下:
package com.wanju.util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class SpringUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext(){
return applicationContext;
}
}
三、Controller层
外部访问接口。
创建WebController
类,代码如下:
@RestController
@Slf4j
public class WebController {
@PostMapping("/upload")
@SneakyThrows
public Result uploadApk(MultipartFile file) {
String uri = WebUploadUtil.upload(file);
log.info("上传uri为:{}", uri);
return Result.ok(uri);
}
}
四、配置文件
参数化配置不同系统下的上传根路径
在application.yml
中添加如下代码:
# 上传根路径
upload:
os:
win: D:\
linux: /opt/wanju/
测试结果
我们利用POSTMAN等工具调用上传API,如:localhost:8080/upload
,会返回如下参数:
{
"data": "/upload/2020/03/03/eafbdfde17bf412cae5864bdd3b7fc0c.png",
"message": "操作成功",
"status": 0,
"success": true
}
返回模型可以根据实际情况变更,其中最重要的参数是data的值
我们获取到的/upload/2020/03/03/eafbdfde17bf412cae5864bdd3b7fc0c.png
就是上传的相对路径,由于我们在配置文件中指定了根路径,例如在linux系统下,文件的绝对路径就为:/opt/wanju/upload/2020/03/03/eafbdfde17bf412cae5864bdd3b7fc0c.png
。获取到了文件根路径后,我们只需要配nginx作为静态代理即可以IP+路径
的方式访问到图片。
nginx的配置
nginx配置文件中只需要指定静态文件的目录即可,如将root指向/opt/wanju
,那么我们就可以IP+/upload/2020/03/03/eafbdfde17bf412cae5864bdd3b7fc0c.png
访问到图片了。
nginx.conf
配置如下:
server {
listen 80;
server_name localhost www.wanjutown.com wanjutown.com;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root /opt/wanju/;
index index.html index.htm;
}
}
修改完nginx,需要重启。命令(
./nginx -s reload
)
这时候我们可以访问:www.wanjutown.com/upload/2020/03/03/eafbdfde17bf412cae5864bdd3b7fc0c.png
获取图片