описание проблемы
В процессе разработки мы часто сталкиваемся с ситуациями, когда нам нужно получить файлы ресурсов в коде, и я недавно столкнулся с проблемой при переносе исходного нативного проекта Tomcat в проект SpringBoot, то есть при локальном запуске получить локальный файл xml файл ресурсов можно получить, но когда проект упакован как военный пакет, а затем развернут на Tomcat для запуска, возникает проблема, и сообщается об ошибке, что файл ресурсов не может быть найден. Затем после поиска и проверки было определено, что прошел следующий кодClassLoader
При получении пути произошла ошибка.
ExcelXmlModelFactory.class.getClassLoader().getResource("template/").getPath()
Мой путь к хранилищу файлов ресурсов выглядит следующим образом
Путь журнала, напечатанный в локальном файле,
/Users/hupengfei/git/lap/lap-service/out/production/resources/template
Но каталог, напечатанный, когда SpringBoot упакован как военный пакет и развернут на Tomcat,
/home/app/lap/app/lap-service-1.0.0-SNAPSHOT.war!/WEB-INF/classes!/template/
Видно, что к несжатым файлам нельзя получить прямой доступ в Linux, поэтому файлы не будут найдены.
Решение
пройти черезClassLoader
изgetResourceAsStream()
способ получить его поток, вы можете получить
Чтобы прочитать файлы в банке, мы можем использовать только поток для чтения, а не файл.
Два способа получить ресурсы
Обычно в процессе разработки возникает проблема чтения конфигурационных файлов, обычно есть два способа чтения. одинClass.getResource(String path)
, одинClassLoader.getResource(String path)
, хотя оба могут читать файлы, но вpath
Начинка немного другая.
Class.getResource
- путь начинается с
/
Начало: он получается из корня классов класса - ПУТЬ не
/
Начало: по умолчанию для получения ресурсов из пакета, где находится этот класс
Вот пример
public class Test {
public static void main(String[] args) {
System.out.println(Test.class.getResource("/"));
System.out.println(Test.class.getResource(""));
}
}
Вывод выглядит следующим образом
file:/Users/hupengfei/git/Test/out/production/classes/
file:/Users/hupengfei/git/Test/out/production/classes/Practice/Day13/
то если вresource
В разделе есть три файла ресурсов
Так как же получить эти три файла, ведь структура каталогов в папке класса следующая
-- classes
-- Convience
-- Practice
-- Test
Итак, если вы хотите получить файл ресурсов под тестом, вы можете получить его следующим образом.
System.out.println(Test.class.getResource("../../Test/1.xml"));
System.out.println(Test.class.getResource("/Test/1.xml"));
ClassLoader.getResource
ClassLoader.getResource
Путь не может начинаться с/
В начале путь по умолчанию читается из корневого каталога
Примеры следующие
System.out.println(Test.class.getClassLoader().getResource(""));
System.out.println(Test.class.getClassLoader().getResource("/"));
распечатать следующим образом
file:/Users/hupengfei/git/Test/out/production/classes/
null
Из приведенного выше примера мы видим, что
Test.class.getClassLoader().getResource("")=Test.class.getResource("/")
Разница между двумя файлами ресурсов приобретения
На самом деле проверитьClass.getResource
можно увидеть в
public java.net.URL getResource(String name) {
name = resolveName(name);
ClassLoader cl = getClassLoader0();
if (cl==null) {
// A system class.
return ClassLoader.getSystemResource(name);
}
return cl.getResource(name);
}
Последнее, что он звонил, былоClassLoader.getResource
этот метод, то почемуpath
отличие, потому что егоresolveName
передать метод/
анализируется, анализируется как пустая строка.
private String resolveName(String name) {
if (name == null) {
return name;
}
if (!name.startsWith("/")) {
Class<?> c = this;
while (c.isArray()) {
c = c.getComponentType();
}
String baseName = c.getName();
int index = baseName.lastIndexOf('.');
if (index != -1) {
name = baseName.substring(0, index).replace('.', '/')
+"/"+name;
}
} else {
name = name.substring(1);
}
return name;
}
Видно, что здесь надето/
исходящий