Carregar um recurso como uma string no Spring

Carregar um recurso como uma string no Spring

1. Visão geral

Neste tutorial, veremos várias maneiras deinject the contents of a resource containing text as a String into our Spring beans.

Veremos como localizar o recurso e ler seu conteúdo.

Além disso, demonstraremos como compartilhar os recursos carregados em vários beans. Mostraremos isso por meio do uso deannotations related to dependency injection, embora o mesmo também possa ser obtido usandoXML-based injectione declarando os beans no arquivo de propriedade XML.

2. UsandoResource

Podemos simplificar a localização de um arquivo de recurso usando a interfaceResource. O Spring nos ajuda a encontrar e ler um recurso usando o carregador de recursos, que decide qual implementaçãoResource escolher, dependendo do caminho fornecido. OResource é efetivamente uma forma de acessar o conteúdo do recurso, ao invés do conteúdo em si.

2.1. UsandoResourceLoader

Podemos usar a classeResourceLoader se preferirmos usar o carregamento lento:

ResourceLoader resourceLoader = new DefaultResourceLoader();
Resource resource = resourceLoader.getResource("classpath:resource.txt");

Também podemos injetarResourceLoader em nosso bean com@Autowired:

@Autowired
private ResourceLoader resourceLoader;

2.2 Using @Resource

Podemos injetar umResource diretamente em um bean Spring com@Value:

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

3. Convertendo deResource emString

Assim que tivermos acesso aResource, precisamos ser capazes de lê-lo emString. Vamos criar uma classe de utilitárioResourceReader com um método estáticoasString para fazer isso por nós.

Primeiro, temos que adquirir umInputStream:

InputStream inputStream = resource.getInputStream();

Nosso próximo passo é pegar esseInputStreame convertê-lo emString. Podemos usar o métodoFileCopyUtils#copyToString do próprio 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
}

are many other ways of achieving this, por exemplo, usandocopyToString da classeStreamUtils de Spring

Vamos também criar outro método utilitárioreadFileToString, que recuperaráResource para um caminho e chamará o métodoasString para convertê-lo emString.

public static String readFileToString(String path) {
    ResourceLoader resourceLoader = new DefaultResourceLoader();
    Resource resource = resourceLoader.getResource(path);
    return asString(resource);
}

4. Adicionando uma classeConfiguration

Se cada bean tivesse que injetar o recursoStrings individualmente, há uma chance de duplicação de código e mais uso de memória pelos beans tendo sua própria cópia individual deString.

Podemos alcançar uma solução mais limpa injetando o conteúdo do recurso em um ou vários beans Spring ao carregar o contexto do aplicativo. Dessa maneira, podemos ocultar os detalhes de implementação para ler o recurso dos vários beans que precisam usar esse conteúdo.

@Configuration
public class LoadResourceConfig {

    // Bean Declarations
}

4.1. Usando um Bean segurando a cadeia de recursos

Vamos declarar os beans para manter o conteúdo do recurso em uma classe@Configuration:

@Bean
public String resourceString() {
    return ResourceReader.readFileToString("resource.txt");
}

Vamos agora injetar os beans registrados nos campos adicionando uma anotação@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);
    }
}

Nesse caso, usamos a anotação@Qualifier e o nome do bean, comowe may need to inject multiple fields of the same type -String.

Devemos observar que o nome do bean usado no qualificador é derivado do nome do método que cria o bean na classe de configuração.

5. Usando o SpEL

Finalmente, vamos ver como podemos usar a linguagem Spring Expression para descrever o código necessário para carregar um arquivo de recurso diretamente em um campo em nossa classe.

Vamos usar a anotação@Value para injetar o conteúdo do arquivo no camporesourceStringUsingSpel:

public class LoadResourceAsStringIntegrationTest {
    private static final String EXPECTED_RESOURCE_VALUE = "..."; // The string value of the file content

    @Value(
      "#{T(com.example.loadresourceasstring.ResourceReader).readFileToString('classpath:resource.txt')}"
    )
    private String resourceStringUsingSpel;

    @Test
    public void givenUsingSpel_whenConvertingAResourceToAString_thenCorrect() {
        assertEquals(EXPECTED_RESOURCE_VALUE, resourceStringUsingSpel);
    }
}

Aqui chamamosResourceReader#readFileToString descrevendo a localização do arquivo usando um caminho corrigido“classpath:” –dentro de nossa anotação@Value.

Para reduzir a quantidade de código no SpEL, criamos um método auxiliar na classeResourceReader que usa Apache CommonsFileUtils para acessar o arquivo a partir do caminho fornecido:

public class ResourceReader {
    public static String readFileToString(String path) throws IOException {
        return FileUtils.readFileToString(ResourceUtils.getFile(path), StandardCharsets.UTF_8);
    }
}

6. Conclusão

Neste tutorial, revisamos algumas das maneiras deconvert a resource to a String.

Em primeiro lugar, vimos como produzir umResource para acessar o arquivo e como ler deResource paraString.

A seguir, também mostramos como ocultar a implementação do carregamento de recursos e permitir que o conteúdo da string seja compartilhado entre os beans criando beans qualificados em um@Configuration, permitindo que as strings sejam autowired.

Por fim, usamos o SpEL, que fornece uma solução compacta e imediata, embora exigisse uma função auxiliar personalizada para impedir que se tornasse muito complexo.

Como sempre, o código dos exemplos pode ser encontradoover on GitHub