Spring ClassPathResource - не может быть открыт, потому что он не существует

ОБНОВЛЕНИЕ: я по-прежнему оставлю ответ Артема Билана помеченным как правильный, но я все еще чувствовал, что должен указать на это будущим читателям. Кажется, я неправильно понял концепцию «значения по умолчанию» для аннотации @Value. Функциональность, которую я надеялся достичь с помощью

@Value("${someProp:defaultFilePath}")
private Resource resourcefilePath;

заключалась в том, что если путь к файлу, определенный в application.properties, выдает исключение (т. е. файл не найден), он попытается использовать defaultFilePath (т. е. указанный выше). На самом деле определение значения по умолчанию заключается в том, что если само свойство (someProp) не существует (не определено или не закомментировано) в файле application.properties, оно пытается вместо этого использовать значение по умолчанию.


Я использую Spring Integration Sftp для передачи файлов SSH. Использование Spring Boot, поэтому нет файлов xml. Перед настройкой объекта DefaultSftpSessionFactory я определяю ресурс, который содержит файл .txt с закрытым ключом, необходимым для аутентификации sFtp.

Раньше я использовал FileSystemResource вот так:

Resource resource = new FileSystemResource("C:/absolute/path/to/my/private/key/privateKey.txt");

Это сработало просто отлично. Однако это приложение в конечном итоге будет помещено в облачную среду, а это означает, что такие абсолютные пути больше не будут работать. Вместо этого я пытаюсь использовать ClassPathResource, но он не работает, что бы я ни пытался. До сих пор я пробовал следующее:

Resource resource = new ClassPathResource("privateKey.txt");
Resource resource = new ClassPathResource("privateKey.txt", SomeClassInClassPath.class);
Resource resource = new ClassPathResource("com/my/package/name/privateKey.txt");

Моя структура каталогов выглядит примерно так:

ProjectFolder -> src -> main -> java -> com -> my -> package -> name -> various java classes
                                                                        privateKey.txt
                             -> resources -> etc...

Есть еще, но это упрощенная версия. Может ли кто-нибудь помочь понять, как я могу заставить его распознать путь к моему .txt? Я продолжаю получать java.io.FileNotFoundException: class path resource [resource] cannot be opened because it does not exist независимо от того, что я пытаюсь.

EDIT: структура WAR:

ProjectFolder -> META-INF -> maven -> etc..
              -> org -> springframework -> boot -> etc..
              -> WEB-INF -> classes -> com
                                    -> public
                                    -> application.properties
                                    -> privateKey.txt

person bscott    schedule 12.05.2016    source источник
comment
Вы пытались переместить свой privateKey.txt в каталог ресурсов? resources -> com -> my -> package -> name -> privateKey.txt   -  person dnault    schedule 13.05.2016
comment
1. Убедитесь, что ваш окончательный файл war/jar содержит «privateKey.txt» в пути к классу. 2 Вы можете использовать конструкцию @Value("classpath:privateKey.txt") Resource privateKey.   -  person Boris Treukhov    schedule 13.05.2016


Ответы (1)


Вы показываете src -> main -> и т. д., но это не имеет значения для времени выполнения.

Если вы действительно собираетесь использовать этот файл в конечном приложении (jar? war?), убедитесь, что вы действительно упаковали этот файл как часть конечного приложения.

И поделитесь этой структурой здесь.

С Spring Java & Annotation Configuration вам не нужно беспокоиться об объекте ClassPathResource. Достаточно просто объявить это в соответствующем @Configuration:

@Value("com/my/package/name/privateKey.txt")
private Resource privateKey;
person Artem Bilan    schedule 12.05.2016
comment
Я обновил свой вопрос, чтобы показать структуру WAR. Кажется, что даже после того, как я поместил файл privateKey.txt в свой путь к классам (com/my/package/name/privateKey.txt), он оказался в папке классов в WAR. Любая идея, как я буду ссылаться на этот путь? - person bscott; 13.05.2016
comment
Что ж, в итоге он работал с @Value("WEB-INF/classes/privateKey.txt"), но это работает только в облачной среде. Есть ли способ, которым я могу относительно определить путь для этого ключа, когда я работаю локально? Независимо от того, какой путь я пытаюсь указать @Value(), я получаю java.io.FileNotFoundException: Could not open ServletContext resource [resource] - person bscott; 14.05.2016
comment
Попробуйте это @Value("${my.local.path.to.privateKey:WEB-INF/classes/privateKey.txt}"), где my.local.path.to.privateKey вы можете указать любой возможный внешний способ, например. как вариант -D Java. - person Artem Bilan; 14.05.2016
comment
Извините, я все еще новичок в Spring, поэтому убедитесь, что я правильно понимаю. Всякий раз, когда я использую @Value с синтаксисом ${}, он ищет свойство, которое я определил в своем файле application.properties. Я пошел и создал свойство с именем privateKeyPath=local.path.to.privateKey и попробовал то, что вы написали, и я все еще получаю java.io.FileNotFoundException: Could not open ServletContext resource [resource]. Думаю, я мог бы просто вернуться к использованию абсолютного системного пути к файлу с FileSystemResource, начинающимся с C:, если ничего не помогает. - person bscott; 14.05.2016
comment
М-м-м. попробуйте префикс file: в вашем определении privateKeyPath. Без префикса ti пытается разрешить ресурс от поставщика контекста. В вашем случае это ServletContext. Таким образом, принудительное включение его в file: заставляет приложение выбирать FileSystemResourceLoader: docs.spring.io/spring/docs/current/spring-framework-reference/ - person Artem Bilan; 14.05.2016
comment
Спасибо, это сработало! Таким образом, сделав его @Value(${privateKeyPath:WEB-INF/classes/privateKey.txt}), по сути означает, что он попытается выполнить поиск в обоих местах? Я имею в виду, что мне не придется вручную редактировать эту аннотацию @Value каждый раз, когда мне нужно переключаться между моей локальной рабочей станцией и облачной средой, верно? - person bscott; 14.05.2016
comment
Ну, синтаксис выглядит как ${properties.key:defaultValue}. Если он не может разрешить первое, он возвращается к значению по умолчанию. И только после этого он переходит к разрешению Resource по финальному String. - person Artem Bilan; 14.05.2016
comment
Хорошо, спасибо, имеет смысл. Локально он никогда не должен возвращаться к пути defaultValue, потому что properties.key должен работать. Когда WAR будет развернут на нашем облачном сервере, путь, указанный в properties.key, явно не будет разрешен. Затем он проверит значение defaultValue, которое будет успешно разрешено. Я должен взглянуть на эту документацию. Но спасибо, отметив это как правильное! - person bscott; 14.05.2016