# 在 Spring Boot 中加载资源

> 原文： [http://zetcode.com/springboot/loadresource/](http://zetcode.com/springboot/loadresource/)

在本教程中，我们将展示如何在 Spring Boot 应用中加载资源。

Spring 是用于创建企业应用的流行 Java 应用框架。 Spring Boot 是一种以最少的精力创建独立的，基于生产级别的基于 Spring 的应用的方法。

## Spring Boot 资源

资源是程序需要以与程序代码的位置无关的方式访问的数据，例如图像，音频和文本。

由于`java.net.URL`不足以处理各种低级资源，因此 Spring 引入了`org.springframework.core.io.Resource`。 要访问资源，我们可以使用`@Value`注解或`ResourceLoader`类。

## Spring Boot 加载资源示例

我们的应用是一个 Spring Boot 命令行应用，它可以计算文本文件中单词的出现次数。 该文件位于`src/main/resources`目录中，这是应用资源的标准 Maven 位置。

```java
pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           │   Application.java
│   │           │   MyRunner.java
│   │           └───service
│   │                   CountWords.java
│   └───resources
│           application.yaml
│           thermopylae.txt
└───test
    └───java

```

这是项目结构。

`pom.xml`

```java
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>springbootresource</artifactId>
    <version>1.0-SNAPSHOT</version>

    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
    </parent>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

```

这是 Maven 构建文件。 Spring Boot 启动器是一组方便的依赖项描述符，我们可以在我们的应用中包含这些描述符。 它们极大地简化了 Maven 配置。 `spring-boot-starter-parent`提供了 Spring Boot 应用的一些常见配置。 `spring-boot-starter`依赖性是一个核心启动器，其中包括自动配置支持，日志记录和 YAML。 `spring-boot-maven-plugin`在 Maven 中提供了 Spring Boot 支持，使我们可以打包可执行的 JAR 或 WAR 档案。 它的`spring-boot:run`目标运行 Spring Boot 应用。

`resources/application.yml`

```java
spring:
    main:
        banner-mode: "off"

logging:
    level:
        org:
            springframework: ERROR
        com:
            zetcode: INFO

```

`application.yml`文件包含 Spring Boot 应用的各种配置设置。 我们具有`banner-mode`属性，可在其中关闭 Spring 横幅。 另外，我们将 spring 框架的日志记录级别设置为`ERROR`，将我们的应用设置为 INFO。 该文件位于`src/main/resources`目录中。

`resources/thermopylae.txt`

```java
The Battle of Thermopylae was fought between an alliance of Greek city-states,
led by King Leonidas of Sparta, and the Persian Empire of Xerxes I over the
course of three days, during the second Persian invasion of Greece.
It took place simultaneously with the naval battle at Artemisium, in August
or September 480 BC, at the narrow coastal pass of Thermopylae.
The Persian invasion was a delayed response to the defeat of the first Persian
invasion of Greece, which had been ended by the Athenian victory at the Battle
of Marathon in 490 BC. Xerxes had amassed a huge army and navy, and set out to
conquer all of Greece.

```

这是我们在应用中读取的文本文件。 它也位于`src/main/resources`目录中。

`com/zetcode/service/CountWords.java`

```java
package com.zetcode.service;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

@Component
public class CountWords {

    public Map<String, Integer> getWordsCount(Resource res) throws IOException {

        Map<String, Integer> wordCount = new HashMap<>();

        List<String> lines = Files.readAllLines(Paths.get(res.getURI()),
                StandardCharsets.UTF_8);

        for (String line : lines) {

            String[] words = line.split("\\s+");

            for (String word : words) {

                if (word.endsWith(".") || word.endsWith(",")) {

                    word = word.substring(0, word.length() - 1);
                }

                if (wordCount.containsKey(word)) {

                    wordCount.put(word, wordCount.get(word) + 1);

                } else {

                    wordCount.put(word, 1);
                }
            }
        }

        return wordCount;
    }
}

```

`CountWords`是一个 Spring 托管的 bean，它执行给定文件中的单词计数。 文本从文件中读取到句子列表中。 句子被分成单词并计数。

```java
Map<String, Integer> wordCount = new HashMap<>();

```

`wordCount`是一个映射，其中键是单词，频率是整数。

```java
List<String> lines = Files.readAllLines(Paths.get(res.getURI()),
        StandardCharsets.UTF_8);

```

我们使用`Files.readAllLines()`方法一次读取所有内容。 `Files.readAllLines()`方法返回字符串列表。

```java
for (String line : lines) {

    String[] words = line.split(" ");
...

```

我们遍历这些线，将它们分成单词； 单词之间用空格隔开。

```java
if (word.endsWith(".") || word.endsWith(",")) {

    word = word.substring(0, word.length()-1);
}

```

我们删除尾随点和逗号。

```java
if (wordCount.containsKey(word)) {

    wordCount.put(word, wordCount.get(word) + 1);

} else {

    wordCount.put(word, 1);
}

```

如果单词已经在地图中，则增加其频率； 否则，我们将其插入地图并将其频率设置为 1。

`com/zetcode/MyRunner.java`

```java
package com.zetcode;

import com.zetcode.count.CountWords;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

@Component
public class MyRunner implements CommandLineRunner {

    @Value("classpath:thermopylae.txt")
    private Resource res;

    @Autowired
    private CountWords countWords;

    @Override
    public void run(String... args) throws Exception {

        Map<String, Integer> words =  countWords.getWordsCount(res);

        for (String key : words.keySet()) {

            System.out.println(key + ": " + words.get(key));
        }
    }
}

```

使用`CommandLineRunner`，Spring Boot 应用在终端上运行。

```java
@Value("classpath:thermopylae.txt")
private Resource res;

```

使用`@Value`注解，将文件设置为资源。

```java
@Autowired
private CountWords countWords;

```

我们注入了`CountWords` bean。

```java
Map<String, Integer> words =  countWords.getWordsCount(res);

for (String key : words.keySet()) {

    System.out.println(key + ": " + words.get(key));
}

```

我们调用`getWordsCount()`方法，并接收单词及其频率的映射。 我们遍历地图，并将键/值对打印到控制台。

`com/zetcode/Application.java`

```java
package com.zetcode;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

```

`Application`设置 Spring Boot 应用。 `@SpringBootApplication`启用自动配置和组件扫描。

## 使用`ResourceLoader`

以前，我们使用`@Value`注解来加载资源。 以下是`ResourceLoader`的替代解决方案。

`com/zetcode/MyRunner.java`

```java
package com.zetcode;

import com.zetcode.count.CountWords;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Component;

@Component
public class MyRunner implements CommandLineRunner {

    @Autowired
    private ResourceLoader resourceLoader;

    @Autowired
    private CountWords countWords;

    @Override
    public void run(String... args) throws Exception {

        Resource res = resourceLoader.getResource("classpath:thermopylae.txt");

        Map<String, Integer> words =  countWords.getWordsCount(res);

        for (String key : words.keySet()) {

            System.out.println(key + ": " + words.get(key));
        }
    }
}

```

或者，我们可以使用`ResourceLoader`加载资源。

```java
@Autowired
private ResourceLoader resourceLoader;

```

`ResourceLoader`被注入到现场。

```java
Resource res = resourceLoader.getResource("classpath:thermopylae.txt");

```

`Resource`是通过`getResource()`方法从资源加载器获得的。

## 运行应用

该应用在命令行上运行。

```java
$ mvn spring-boot:run -q
...
been: 1
Athenian: 1
alliance: 1
navy: 1
fought: 1
led: 1
delayed: 1
had: 2
during: 1
three: 1
second: 1
Greece: 3
...

```

使用`mvn spring-boot:run`命令，运行应用。 `-q`选项禁止 Maven 日志。

在本教程中，我们使用了 Spring Boot 应用中的资源。 我们使用`@Value`和`ResourceLoader`加载资源文件。

列出[所有 Spring Boot 教程](/all/#springboot)。