1. Overview
1.概述
In this tutorial, we’ll look at various ways to inject the contents of a resource containing text as a String into our Spring beans.
在本教程中,我们将探讨各种方法,以将包含文本的资源内容作为字符串注入我们的Spring Bean。
We’ll look at locating the resource and reading its contents.
我们将看看如何定位资源并读取其内容。
Also, we’ll demonstrate how to share the loaded resources across several beans. We’ll show this through the use of annotations related to dependency injection, though the same can also be achieved by using XML-based injection and declaring the beans in the XML property file.
另外,我们将演示如何在几个Bean之间共享加载的资源。我们将通过使用与依赖性注入有关的注释来展示这一点,尽管同样可以通过使用基于XML的注入和在XML属性文件中声明bean来实现。
2. Using Resource
2.使用资源
We can simplify locating a resource file by using the Resource interface. Spring helps us find and read a resource using the resource loader, which decides which Resource implementation to pick depending on the path provided. The Resource is effectively a way of accessing the content of the resource, rather than the content itself.
我们可以通过使用Resource接口来简化对资源文件的定位。Spring通过资源加载器帮助我们找到并读取资源,该加载器根据提供的路径决定选择哪种Resource实现。Resource实际上是访问资源内容的一种方式,而不是内容本身。
Let’s see some ways to acquire a Resource instance for resources on the classpath.
让我们看看一些方法来为classpath上的资源获取一个Resource实例。
2.1. Using ResourceLoader
2.1.使用ResourceLoader
We can use the class ResourceLoader if we prefer to use lazy loading:
如果我们喜欢使用懒惰加载,我们可以使用ResourceLoader类。
ResourceLoader resourceLoader = new DefaultResourceLoader();
Resource resource = resourceLoader.getResource("classpath:resource.txt");
We can also inject the ResourceLoader into our bean with @Autowired:
我们也可以用@Autowired将ResourceLoader注入我们的Bean中。
@Autowired
private ResourceLoader resourceLoader;
2.2. Using @Value
2.2.使用@Value
We can inject a Resource directly into a Spring bean with @Value:
我们可以用@Value将一个Resource直接注入Spring Bean。
@Value("classpath:resource.txt")
private Resource resource;
3. Converting from Resource to String
3.从资源转换到字符串
Once we have access to the Resource we need to be able to read it into a String. Let’s create a ResourceReader utility class with a static method asString to do this for us.
一旦我们访问了Resource,我们需要能够将它读成String。让我们创建一个ResourceReader实用类,用一个静态方法asString来为我们做这个。
First, we have to acquire an InputStream:
首先,我们必须获得一个InputStream。
InputStream inputStream = resource.getInputStream();
Our next step is to take this InputStream and convert it to a String. We can use Spring’s own FileCopyUtils#copyToString method:
我们的下一步是把这个InputStream转换为String。我们可以使用Spring自己的FileCopyUtils#copyToString方法。
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
}
There are many other ways of achieving this, for example, using copyToString of Spring’s StreamUtils class
有许多其他方法来实现这个目的,例如,使用Spring的StreamUtils类的copyToString。
Let’s also create another utility method readFileToString, which will retrieve the Resource for a path, and call the asString method to convert it to a String.
让我们也创建另一个实用方法readFileToString,,它将检索一个路径的Resource,并调用asString方法将其转换成String。
public static String readFileToString(String path) {
ResourceLoader resourceLoader = new DefaultResourceLoader();
Resource resource = resourceLoader.getResource(path);
return asString(resource);
}
4. Adding a Configuration Class
4.添加一个配置类
If each bean had to inject resource Strings individually, there’s a chance of both code duplication and more use of memory by beans having their own individual copy of the String.
如果每个Bean都必须单独注入资源Strings,那么就有可能出现代码重复和Bean拥有自己的String的单独副本而更多地使用内存。
We can achieve a neater solution by injecting the resource’s content to one or multiple Spring beans upon loading the application context. In this way, we can hide the implementation details for reading the resource from the various beans which need to use this content.
我们可以通过在加载应用上下文时将资源的内容注入一个或多个Spring Bean来实现一个更整洁的解决方案。通过这种方式,我们可以从需要使用该内容的各种Bean那里隐藏读取资源的实现细节。
@Configuration
public class LoadResourceConfig {
// Bean Declarations
}
4.1. Using a Bean Holding the Resource String
4.1.使用持有资源字符串的 Bean
Let’s declare beans to hold the resource content in an @Configuration class:
让我们在一个@Configuration类中声明Bean来保存资源内容。
@Bean
public String resourceString() {
return ResourceReader.readFileToString("resource.txt");
}
Let’s now inject the registered beans to the fields by adding an @Autowired annotation:
现在让我们通过添加@Autowired注解,将注册的bean注入到字段中。
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);
}
}
In this case, we use the @Qualifier annotation and the name of the bean, as we may need to inject multiple fields of the same type – String.
在这种情况下,我们使用@Qualifier注解和Bean的名字,因为我们可能需要注入相同类型的多个字段 – String。
We should note that the bean name used in the qualifier is derived from the name of the method that creates the bean in the configuration class.
我们应该注意到,限定符中使用的Bean名称是由配置类中创建Bean的方法名称衍生出来的。
5. Using SpEL
5.使用SpEL
Finally, let’s see how we can use the Spring Expression Language to describe the code needed to load a resource file directly into a field in our class.
最后,让我们看看如何使用Spring表达式语言来描述将资源文件直接加载到我们类中的一个字段所需的代码。
Let’s use the @Value annotation to inject the file content into the field resourceStringUsingSpel:
让我们使用@Value注解,将文件内容注入字段resourceStringUsingSpel。
public class LoadResourceAsStringIntegrationTest {
private static final String EXPECTED_RESOURCE_VALUE = "..."; // The string value of the file content
@Value(
"#{T(com.baeldung.loadresourceasstring.ResourceReader).readFileToString('classpath:resource.txt')}"
)
private String resourceStringUsingSpel;
@Test
public void givenUsingSpel_whenConvertingAResourceToAString_thenCorrect() {
assertEquals(EXPECTED_RESOURCE_VALUE, resourceStringUsingSpel);
}
}
Here we have called ResourceReader#readFileToString describing the location of the file by using a “classpath:” –prefixed path inside our @Value annotation.
这里我们调用了ResourceReader#readFileToString,通过使用“classpath:” 来描述文件的位置。-在我们的@Value 注解中预设了路径。
To reduce the amount of code in the SpEL, we’ve created a helper method in the class ResourceReader which uses Apache Commons FileUtils to access the file from the path provided:
为了减少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. Conclusion
6.结语
In this tutorial, we’ve reviewed some of the ways to convert a resource to a String.
在本教程中,我们回顾了将资源转换为String的一些方法。
First of all, we saw how to produce a Resource to access the file, and how to read from Resource to String.
首先,我们看到如何产生一个Resource来访问文件,以及如何从Resource读到String.。
Next, we also showed how to hide the resource loading implementation, and allow the string contents to be shared across beans by creating qualified beans in an @Configuration, allowing the strings to be autowired.
接下来,我们还展示了如何隐藏资源加载实现,并通过在@Configuration中创建合格的Bean,让字符串内容在Bean之间共享,允许字符串被自动连接。
Finally, we used SpEL, which provides a compact and immediate solution, though it required a custom helper function to stop it from becoming too complex.
最后,我们使用了SpEL,它提供了一个紧凑而直接的解决方案,尽管它需要一个自定义的辅助函数来阻止它变得过于复杂。
As always, the code for the examples can be found over on GitHub
一如既往,可以在GitHub上找到的示例代码。