一、先说默认的静态资源路径
下面截取了一段ResourceProperties类的源码,可以看到定义了一个final数组CLASSPATH_RESOURCE_LOCATIONS并初始化了一些值,这些值就是默认的静态资源路径,这些文件夹下的文件可以直接访问。
@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
public class ResourceProperties {
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
"classpath:/META-INF/resources/", "classpath:/resources/",
"classpath:/static/", "classpath:/public/" };
/**
* Locations of static resources. Defaults to classpath:[/META-INF/resources/,
* /resources/, /static/, /public/].
*/
private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
}
- classpath:/META-INF/resources/
- classpath:/resources/
- classpath:/static/
- classpath:/public/
这几个路径分别对应项目中的如下文件夹
二、覆盖默认配置 or 增加静态资源路径
目前我只知道两种覆盖默认配置的方式
Ⅰ、使用 spring.resources.static-locations配置
其中的classpath:/my-path/是自定义的路径,其他的是SpringBoot默认的路径,当然也可以不加默认路径。
application.properties如下:
# 项目路径
server.servlet.context-path=/test-demo
# 静态资源配置
spring.resources.static-locations=
classpath:/META-INF/resources/,
classpath:/resources/,
classpath:/static/,
classpath:/public/,
classpath:/templates/,
classpath:/my-path/
这样配置,除了可以直接访问spring默认的路径下的静态资源,也可以直接访问classpath:my-path下的静态资源。
Ⅱ、使用spring.mvc.static-path-pattern配置
aplication.properties如下:
# 项目路径
server.servlet.context-path=/test-demo
# 静态资源配置
spring.mvc.static-path-pattern=/static/**
敲黑板:
当使用上面第Ⅱ种配置方式时,只能指定一个静态资源的路径,且访问时url必须含有路径名称如static,比如http://ip:port/test-demo/static/xxx.txt。而当使用上面第Ⅰ种配置方式时,可以配置多个静态资源路径,不能加路径名称,正常url应该例如http://ip:port/test-demo/xxx.txt。否则都不能达到预期结果。那你可能要问第Ⅰ中方式既然不能指定要访问那个静态资源路径,那么怎么去找到文件,springboot会按照配置的路径顺序依次检索,找到了就返回。
三、自定义静态资源映射
在实际的开发中,有可能我们会上传文件到服务器,然后返回一个url直接访问这个文件。但是当文件比较多,体积也比较大时,不可能将这些文件全部存放在jar服务中。这个时候,这种方式就特别有用,因为我们可以把磁盘上的一个位置映射为静态资源访问路径,通过访问静态资源路径就可以直接访问到磁盘上的资源,当文件保存在磁盘上时,就可以给jar服务减轻很大的压力。
那么。。。怎么做?
如下创建一个配置类并且重写addResourceHandlers方法。
- addResourceHandler("/customer-path/**")是添加url匹配规则,只要是以http://ip:port/test-demo/customer-path/开头的url都会被认为是访问静态资源的url。
- addResourceLocations("file:"+"D:/data/")是指定静态资源映射的位置,file表示这是磁盘路径,如果把file改成classpath那就是类路径,但是我们就是不能存到jar服务中去了,所有这里用file而不用classpath,D:/data/就是路径了。
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author chenzhiyuan
* @date 2020-01-03 18:00
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
/**
* 自定义静态资源映射
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/customer-path/**")
.addResourceLocations("file:"+"D:/data/");
}
}
如图2,我在D:/data下放了一张图片12345.jpg作为静态资源。
如图3,项目启动后访问 http://localhost:9000/test-demo/customer-path/12345.jpg,就访问到了静态资源。
下面记一下项目中的实际使用,方便日后再次遇到使用CV大法。
需求:上传图片并返回url
需要考虑到的问题:映射路径,磁盘路径什么的都别写死了,需要支持可配置;另外需要考虑到在windows和非window(linux,mac)下都顺利启动应用,所以搞了一个WebAppDataProperties类,其中WebAppData是有业务含义的,并不是指当前应用是个web应用。
1.WebAppDataProperties
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.io.File;
/**
* @author chenzhiyuan
* @date 2020-01-03 14:08
* 作用: 用于配置静态资源映射的一些属性
* accessPath: 访问静态资源时的路径,如访问ip:port/visual/webappdata/xxx/xxx,其中visual是项目路径,webappdata便是accessPath
* mappingLocationWindows: 指明在windows下运行时accessPath映射到服务器磁盘的绝对路径,比如映射到D:/data
* mappingLocationNotWindows: 指明在Linux或Mac下运行时accessPath映射到服务器磁盘的绝对路径,比如映射到/usr/data
* pathPattern: 配置静态资源映射时的参数,表示路径匹配规则,如/webappdata/**表示以ip:port/visual/webappdata/开头的url
* 都会认为是访问静态资源,然后到mappingLocation指定的路径下去寻找资源
* resourceLocation: 配置静态资源映射时的参数,表示磁盘的绝对路径,如file:/usr/webappdata/,必须加上file。
*/
@Data
@Component
@ConfigurationProperties(prefix = "webapp.data")
public class WebAppDataProperties {
private String accessPath;
private String pathPattern;
private String mappingLocationWindows;
private String mapperLocationNotWindows;
public String getMappingLocation() {
String os = System.getProperty("os.name");
return (os.toLowerCase().startsWith("win")) ? mappingLocationWindows : mapperLocationNotWindows;
}
public String getResourceLocation() {
String os = System.getProperty("os.name");
if (os.toLowerCase().startsWith("win")) {
File file = new File(mappingLocationWindows);
if (!file.exists()) {
file.mkdirs();
}
return "file:" + mappingLocationWindows;
} else {
File file = new File(mapperLocationNotWindows);
if (!file.exists()) {
file.mkdirs();
}
return "file:" + mapperLocationNotWindows;
}
}
}
2.具体配置内容
webapp:
data:
access-path: /webappdata
path-pattern: ${webapp.data.access-path}/**
mapping-location-windows: D:/visual_webappdata/
mapping-location-not-windows: /usr/visual_webappdata/
3.WebMvcConfig配置
@Slf4j
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
@Autowired
private WebAppDataProperties webAppDataProperties;
/**
* 自定义静态资源映射
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler(webAppDataProperties.getPathPattern())
.addResourceLocations(webAppDataProperties.getResourceLocation());
}
}
4.最后贴一下上传图片的代码,controler如下
/**
* 为某个WebApp上传图片
*
* @param srcImage
* @param appId
* @return 返回图片的url
*/
@PostMapping("/uploadImage")
public String uploadImageForWebApp(@RequestParam("file") MultipartFile srcImage,
@RequestParam(name = "appId") String appId) {
log.info("upload image for webapp start: {}", appId);
String url = webAppService.uploadImage(srcImage, appId);
log.info("upload image for webapp end: {}", url);
return url;
}
5.service实现
@Override
public String uploadImage(MultipartFile srcImage, String appId) {
// 图片的存储路径
File imagePath = UploadUtils.getWebAppImagePath(webAppDataProperties.getMappingLocation(), appId);
// 获取上传时的文件名
String imageName = srcImage.getOriginalFilename();
// 截取后缀
String imageSuffix = imageName.substring(imageName.lastIndexOf("."));
// 使用UUID作为保存时的文件名
String newImageName = UUID.randomUUID().toString().replaceAll("-", "") + imageSuffix;
File destImage = new File(imagePath, newImageName);
try {
srcImage.transferTo(destImage);
} catch (IOException e) {
e.printStackTrace();
}
StringBuilder imageUrl = new StringBuilder().append(serverConfig.getEndpoint())
.append("/visual")
.append(webAppDataProperties.getAccessPath())
.append("/")
.append(appId)
.append("/images/")
.append(newImageName);
return imageUrl.toString();
}
6.其中getWebAppImagePath方法如下,其实也就是构建一个文件夹路径,不存在就mkdirs
public static File getWebAppImagePath(String root, String appId) {
String imageDir = root + "/" + appId + "/images";
File imageDirFile = getOrCreate(imageDir);
return imageDirFile;
}
private static File getOrCreate(String path) {
File file = new File(path);
if (!file.exists()) {
file.mkdirs();
}
return file;
}