21

所以我有这个

@Value("classpath:choice-test.html")
private Resource sampleHtml;
private String sampleHtmlData;

@Before
public void readFile() throws IOException {
    sampleHtmlData = IOUtils.toString(sampleHtml.getInputStream());
}

我想知道的是,是否可以不使用 readFile() 方法并让 sampleHtmlData 注入文件的内容。如果不是,我将不得不忍受这个,但这将是一个不错的捷径。

4

3 回答 3

40

从技术上讲,您可以使用 XML 以及工厂 bean 和方法的笨拙组合来做到这一点。但是,当您可以使用 Java 配置时,为什么还要麻烦呢?

@Configuration
public class Spring {

    @Value("classpath:choice-test.html")
    private Resource sampleHtml;

    @Bean
    public String sampleHtmlData() {
        try(InputStream is = sampleHtml.getInputStream()) {
            return IOUtils.toString(is, StandardCharsets.UTF_8);
        }
    }
}

请注意,我还sampleHtml.getInputStream()使用try-with-resources习惯用法关闭了返回的流。否则你会得到内存泄漏。

于 2012-12-06T08:54:23.667 回答
1

据我所知,没有内置功能,但你可以自己做,例如:

<bean id="fileContentHolder">
  <property name="content">
    <bean class="CustomFileReader" factory-method="readContent">
      <property name="filePath" value="path/to/my_file"/>
    </bean>
   </property>
</bean>

其中 readContent() 返回从 path/to/my_file 上的文件读取的字符串。

于 2012-12-06T08:54:34.840 回答
0

如果您希望每次注入减少到一行,您可以添加注释和条件转换器。这还将在 IntelliJ 中保留 ctrl-click 导航和自动完成功能。

@SpringBootApplication
public class DemoApplication {

    @Value("classpath:application.properties")
    @FromResource
    String someFileContents;

    @PostConstruct
    void init() {
        if (someFileContents.startsWith("classpath:"))
            throw new RuntimeException("injection failed");
    }

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

    DemoApplication(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
        // doing it in constructor ensures it executes before @Value injection in application
        // if you don't inject values into application class, you can extract that to separate configuration
        environment.getConversionService().addConverter(new ConditionalGenericConverter() {
            @Override
            public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
                return targetType.hasAnnotation(FromResource.class);
            }

            @Override
            public Set<GenericConverter.ConvertiblePair> getConvertibleTypes() {
                return Set.of(new GenericConverter.ConvertiblePair(String.class, String.class));
            }

            @Override
            public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
                try (final var stream = resourceLoader.getResource(Objects.toString(source)).getInputStream()) {
                    return StreamUtils.copyToString(stream, StandardCharsets.UTF_8);
                } catch (IOException e) {
                    throw new IllegalArgumentException(e);
                }
            }
        });
    }
}

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface FromResource {
}
于 2021-07-22T02:09:25.603 回答