解决项目打包后获取文件报错问题

项目在本地可以获取到classpath下的文件,但是打包发布到服务器(Linux)上后,就会报错cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/srv/project.jar!/BOOT-INF/classes!/static/json/14.json

代码如下

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;

/**
* 等待spring容器都加载完再执行
*/
@Service
@Slf4j
public class LoadFileHandler implements ApplicationListener<ContextRefreshedEvent> {

public static final String JSON_FILE_SIZE = "json_file_size";
private static final String JSON_FILE_PATH = "classpath:static/json/*.json";

@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
loadJsonFIleToCache();
}

/**
* 读取json文件到缓存
*/
public void loadJsonFIleToCache() {
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
try {
Resource[] resources = resolver.getResources(JSON_FILE_PATH);
for (Resource resource : resources) {
if (resource.isFile()) {
String filename = resource.getFilename();
JSONObject json = JSONUtil.readJSONObject(resource.getFile(), StandardCharsets.UTF_8);
CacheUtils.put(filename,json);
}
}
//缓存中存入文件数量,方便遍历
CacheUtils.put(JSON_FILE_SIZE,resources.length);
} catch (Exception e) {
log.info("LoadJson文件失败:{}",e.getMessage());
}

}
}

resource.getFile()在本地上测试是没问题的,因为是直接运行的SpringBoot项目,但是打成jar包之后就会报错cannot be resolved to absolute file path...。跟到源码org.springframework.util.ResourceUtils#getFile(java.net.URL, java.lang.String)中之后,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/** URL protocol for a file in the file system: "file". */
public static final String URL_PROTOCOL_FILE = "file";

public static File getFile(URL resourceUrl, String description) throws FileNotFoundException {
Assert.notNull(resourceUrl, "Resource URL must not be null");
if (!URL_PROTOCOL_FILE.equals(resourceUrl.getProtocol())) {
throw new FileNotFoundException(
description + " cannot be resolved to absolute file path " +
"because it does not reside in the file system: " + resourceUrl);
}
try {
return new File(toURI(resourceUrl).getSchemeSpecificPart());
}
catch (URISyntaxException ex) {
// Fallback for URLs that are not valid URIs (should hardly ever happen).
return new File(resourceUrl.getFile());
}
}

resourceUrl.getProtocol()返回的是jar,不是上面定义的file,所以会报错

解决方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public void loadJsonFIleToCache() {
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
try {
Resource[] resources = resolver.getResources(JSON_FILE_PATH);
log.info("加载json文件数量:{}",resources.length);
for (Resource resource : resources) {
byte[] bytes = FileCopyUtils.copyToByteArray(resource.getInputStream());
String filename = resource.getFilename();
String jsonString = new String(bytes, StandardCharsets.UTF_8);
JSONObject json = JSONUtil.parseObj(jsonString);
CacheUtils.put(filename,json);
log.info("加载json文件{}到缓存中",filename);
}
//缓存中存入文件数量,方便遍历
CacheUtils.put(JSON_FILE_SIZE,resources.length);
} catch (Exception e) {
log.info("LoadJson文件失败:{}",e.getMessage());
}

}

通过resource.getInputStream()是可以获取到jar下的文件流,通过转成byte[] -> String后,再转成JSONObject存到缓存中


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!