java 使用Spring将文本文件直接注入String

6yt4nkrj  于 2023-02-18  发布在  Java
关注(0)|答案(4)|浏览(208)

所以我有这个

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

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

我想知道的是,是否可以不使用readFile()方法,而使用sampleHtmlData来注入文件的内容,如果不行,我只能接受这个方法,但这将是一个很好的捷径。

zxlwwiss

zxlwwiss1#

从技术上讲,您可以使用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);
        }
    }
}

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

8ljdwjyq

8ljdwjyq2#

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

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

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

46qrfjad

46qrfjad3#

如果您希望每次进样减少到一行,您可以添加注解和条件转换器。这也将保留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 {
}
lbsnaicq

lbsnaicq4#

采用@Marcin Wisnicki,可以定义一个注解,如“StringResource”,默认值为空字符串,并定义实用程序类,如“StringResouceReader”,一个修改后的转换器,如下所示:
1.如果StringResource作为@StringResource @Value应用于字段(类路径:path),则path上的资源内容将作为字符串自动注入
1.如果StringResource作为@StringResource(限定符)应用于类,并将@Value(类路径:路径)应用于字段,并且如果字段或成员的名称限定符开头,则路径上的资源内容将作为字符串自动注入
这种方法的优点是,当在同一个类的不同字段中自动注入多个资源时,可以使代码更简洁。可以在类上指定@StringResource(限定符),并像往常一样在上使用@Value。
字符串资源类

import java.lang.annotation.*;

@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface StringResource {
    String value() default  "";
}

字符串资源渲染

@Service
public class StringResourceReader{

    @Cacheable
    public String getString(Resource resource){
        return readAsString(resource);
    }

    private static String readAsString(Resource resource){
        try {
            return StreamUtils.copyToString(resource.getInputStream(), StandardCharsets.UTF_8);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    private static boolean isJavaIdentifier(String name){
        if(name.isEmpty()){
            return false;
        }
        char[] chars = name.toCharArray();
        for(int i = 0;i<chars.length;i++){
            if(i==0&&!Character.isJavaIdentifierStart(chars[i])){
                return false;
            }else if(!Character.isJavaIdentifierStart(chars[i])){
                return false;
            }
        }
        return true;
    }
    public static void registerConvertor(ConfigurableEnvironment environment, ResourceLoader resourceLoader){
        environment.getConversionService().addConverter(new ConditionalGenericConverter() {
            @Override
            public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
                if(targetType.hasAnnotation(Value.class)){
                    if(targetType.hasAnnotation(StringResource.class)){
                        return true;
                    }else{
                        Object source = targetType.getResolvableType().getSource();
                        if(source instanceof Member) {
                            Member member = (Member) source;
                            StringResource stringResource = AnnotationUtils.findAnnotation(member.getDeclaringClass(), StringResource.class);
                            if (stringResource != null) {
                                String qualifier = stringResource.value().trim();
                                if(qualifier.length()==0){
                                    throw new IllegalStateException("Annotation StringResource must specify argument qualifier when used on a class");
                                }else if(!isJavaIdentifier(qualifier)){
                                    throw new IllegalStateException("Qualifier must be java identifier");
                                }else{
                                    return member.getName().startsWith(qualifier);
                                }
                            } else {
                                return false;
                            }
                        }else {
                            return false;
                        }
                    }
                }else{
                    return false;
                }
            }

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

            @Override
            public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
                return readAsString(resourceLoader.getResource(source.toString()));
            }
        });
    }
}

然后在SpringApplication构造函数中注册转换器

@SpringBootApplication
public class SomeApplicationApplication {

    public SomeApplicationApplication(ConfigurableEnvironment environment, ResourceLoader resourceLoader){
        StringResourceReader.registerConvertor(environment, resourceLoader);
    }
    public static void main(String[] args) {
        SpringApplication.run(SomeApplicationApplication.class, args);
    }

}

相关问题