1. Обзор
В этом руководстве мы рассмотрим различные способы внедрения содержимого ресурса, содержащего текст, в виде строки в наши bean-компоненты Spring .
Мы рассмотрим поиск ресурса и чтение его содержимого.
Кроме того, мы покажем, как разделить загруженные ресурсы между несколькими bean-компонентами. Мы покажем это с помощью аннотаций, связанных с внедрением зависимостей , хотя того же можно добиться с помощью внедрения на основе XML и объявления bean-компонентов в файле свойств XML.
2. Использование ресурса
Мы можем упростить поиск файла ресурсов, используя интерфейс ресурсов .
Spring помогает нам найти и прочитать ресурс с помощью загрузчика ресурсов, который решает, какую реализацию ресурса
выбрать в зависимости от предоставленного пути. Ресурс фактически является способом доступа к содержимому ресурса
, а не к самому содержимому.
Давайте рассмотрим несколько способов получения экземпляра Resource
для ресурсов в пути к классам .
2.1. Использование ResourceLoader
Мы можем использовать класс ResourceLoader
, если мы предпочитаем использовать ленивую загрузку:
ResourceLoader resourceLoader = new DefaultResourceLoader();
Resource resource = resourceLoader.getResource("classpath:resource.txt");
Мы также можем внедрить ResourceLoader
в наш компонент с помощью @Autowired
:
@Autowired
private ResourceLoader resourceLoader;
2.2. Использование @ресурса
Мы можем внедрить Resource
непосредственно в bean-компонент Spring с помощью @Value
:
@Value("classpath:resource.txt")
private Resource resource;
3. Преобразование из ресурса
в строку
Получив доступ к ресурсу
, мы должны иметь возможность прочитать его в строку
. Давайте создадим служебный класс ResourceReader
со статическим методом asString
, который сделает это за нас.
Во-первых, мы должны получить InputStream
:
InputStream inputStream = resource.getInputStream();
Наш следующий шаг — взять этот InputStream
и преобразовать его в String
. Мы можем использовать собственный метод FileCopyUtils#copyToString Spring
:
public class ResourceReader {
public static String asString(Resource resource) {
try (Reader reader = new InputStreamReader(resource.getInputStream(), UTF_8)) {
return FileCopyUtils.copyToString(reader);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
// more utility methods
}
Есть много других способов добиться этого , например, используя copyToString
класса Spring StreamUtils .
Давайте также создадим еще один служебный метод readFileToString,
который будет извлекать Resource
для пути и вызывать метод asString
для преобразования его в String
.
public static String readFileToString(String path) {
ResourceLoader resourceLoader = new DefaultResourceLoader();
Resource resource = resourceLoader.getResource(path);
return asString(resource);
}
4. Добавление класса конфигурации
Если бы каждый bean-компонент должен был вводить String
ресурсов по отдельности, существует вероятность как дублирования кода, так и большего использования памяти bean-компонентами, имеющими свою собственную индивидуальную копию String
.
Мы можем добиться более аккуратного решения, внедрив содержимое ресурса в один или несколько компонентов Spring при загрузке контекста приложения. Таким образом, мы можем скрыть детали реализации для чтения ресурса из различных bean-компонентов, которым необходимо использовать это содержимое.
@Configuration
public class LoadResourceConfig {
// Bean Declarations
}
4.1. Использование компонента, содержащего строку ресурса
Давайте объявим bean-компоненты для хранения содержимого ресурсов в классе @Configuration
:
@Bean
public String resourceString() {
return ResourceReader.readFileToString("resource.txt");
}
Давайте теперь внедрим зарегистрированные bean-компоненты в поля, добавив аннотацию @Autowired
:
public class LoadResourceAsStringIntegrationTest {
private static final String EXPECTED_RESOURCE_VALUE = "..."; // The string value of the file content
@Autowired
@Qualifier("resourceString")
private String resourceString;
@Test
public void givenUsingResourceStringBean_whenConvertingAResourceToAString_thenCorrect() {
assertEquals(EXPECTED_RESOURCE_VALUE, resourceString);
}
}
В этом случае мы используем аннотацию @Qualifier
и имя бина, так как нам может понадобиться внедрить несколько полей одного типа — String
.
Следует отметить, что имя компонента, используемое в квалификаторе, происходит от имени метода, который создает компонент в классе конфигурации.
5. Использование СПЭЛ
Наконец, давайте посмотрим, как мы можем использовать язык выражений Spring для описания кода, необходимого для загрузки файла ресурсов непосредственно в поле нашего класса.
Давайте используем аннотацию @Value
для вставки содержимого файла в поле resourceStringUsingSpel
:
public class LoadResourceAsStringIntegrationTest {
private static final String EXPECTED_RESOURCE_VALUE = "..."; // The string value of the file content
@Value(
"#{T(com.foreach.loadresourceasstring.ResourceReader).readFileToString('classpath:resource.txt')}"
)
private String resourceStringUsingSpel;
@Test
public void givenUsingSpel_whenConvertingAResourceToAString_thenCorrect() {
assertEquals(EXPECTED_RESOURCE_VALUE, resourceStringUsingSpel);
}
}
Здесь мы вызвали ResourceReader#readFileToString,
описывающую расположение файла, используя «classpath:» —
путь с префиксом внутри нашей аннотации @Value
.
Чтобы уменьшить объем кода в SpEL, мы создали вспомогательный метод в классе ResourceReader
, который использует Apache Commons FileUtils
для доступа к файлу по предоставленному пути:
public class ResourceReader {
public static String readFileToString(String path) throws IOException {
return FileUtils.readFileToString(ResourceUtils.getFile(path), StandardCharsets.UTF_8);
}
}
6. Заключение
В этом руководстве мы рассмотрели некоторые способы преобразования ресурса в String
.
Прежде всего, мы увидели, как создать ресурс
для доступа к файлу и как читать из ресурса
в строку.
Далее мы также показали, как скрыть реализацию загрузки ресурсов и разрешить совместное использование содержимого строки между bean-компонентами путем создания квалифицированных bean-компонентов в @Configuration
, позволяющих автоматически связывать строки.
Наконец, мы использовали SpEL, который обеспечивает компактное и быстрое решение, хотя и требует пользовательской вспомогательной функции, чтобы оно не стало слишком сложным.
Как всегда, код примеров можно найти на GitHub.