Lesen einer Liste aus der Eigenschaftendatei und Laden mit der Frühlingsanmerkung @Value

244

Ich möchte eine Liste von Werten in einer .properties-Datei haben, dh:

my.list.of.strings=ABC,CDE,EFG

Und um es direkt in meine Klasse zu laden, dh:

@Value("${my.list.of.strings}")
private List<String> myList;

Soweit ich weiß, besteht eine Alternative dazu darin, es in der Spring-Konfigurationsdatei zu haben und es als Bean-Referenz zu laden (korrigieren Sie mich, wenn ich falsch liege), d. H.

<bean name="list">
 <list>
  <value>ABC</value>
  <value>CDE</value>
  <value>EFG</value>
 </list>
</bean>

Aber gibt es eine Möglichkeit, dies zu tun? Verwenden Sie eine .properties-Datei? ps: Ich möchte dies nach Möglichkeit ohne benutzerdefinierten Code tun.

JackDev
quelle

Antworten:

453

Verwenden von Spring EL:

@Value("#{'${my.list.of.strings}'.split(',')}") 
private List<String> myList;

Angenommen, Ihre Eigenschaftendatei wird wie folgt korrekt geladen:

my.list.of.strings=ABC,CDE,EFG
Wilhelm Kleu
quelle
1
Ich habe es erneut mit derselben Version überprüft, die Sie verwenden. Kopierte die Spring EL genau wie in der Post und es funktioniert. Was jedoch anders ist, ist, wenn ich einen Fehler in meiner EL mache, bekomme ich eine org.springframework.expression.spel.SpelEvaluationExceptionAusnahme und nicht javax.el.ELException. Wird Ihr Objekt von Spring erstellt?
Wilhelm Kleu
1
Funktioniert perfekt mit Spring 3.2.
ehsanullahjan
17
Wie wäre es mit leerem Eigentum my.list.of.strings=? Ich würde erwarten, dass eine solche Funktionalität eine leere Liste neu ausführt, wo es sich hier um ein Element (leere Zeichenfolge) handelt, nicht wahr?
Jan Zyka
5
Beachten Sie auch, dass die vorgeschlagene Lösung kein Trimmen durchführt, sodass Werte wie item1, item2, item3möglicherweise zu Ergebnissen führen, die Sie nicht wirklich erwarten (Hinweis: Leerzeichen).
Jan Zyka
4
Wenn Sie Leerzeichen @Value("#{'${my.list.of.strings}'.split(',\\s*')}")
kürzen
88

Seit Spring 3.0 können Sie eine Zeile wie hinzufügen

<bean id="conversionService" 
    class="org.springframework.context.support.ConversionServiceFactoryBean" />

zu Ihrem applicationContext.xml(oder wo Sie Dinge konfigurieren). Wie Dmitry Chornyi in einem Kommentar hervorhebt, sieht die Java-basierte Konfiguration folgendermaßen aus:

@Bean public ConversionService conversionService() {
    return new DefaultConversionService();
}

Dadurch wird der neue Konfigurationsdienst aktiviert, der die Konvertierung unterstützt String in CollectionTypen unterstützt. Wenn Sie diesen Konfigurationsdienst nicht aktivieren, greift Spring auf seine älteren Eigenschafteneditoren als Konfigurationsdienste zurück, die diese Art der Konvertierung nicht unterstützen.

Das Konvertieren in Sammlungen anderer Typen funktioniert ebenfalls:

@Value("${my.list.of.ints}")
private List<Integer> myList

wird mit einer Linie wie arbeiten

 my.list.of.ints= 1, 2, 3, 4

Keine Probleme mit Leerzeichen da, das ConversionServiceFactoryBeankümmert sich darum.

Siehe http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#core-convert-Spring-config

In einer Spring-Anwendung konfigurieren Sie normalerweise eine ConversionService-Instanz pro Spring-Container (oder ApplicationContext). Dieser ConversionService wird von Spring übernommen und dann verwendet, wenn eine Typkonvertierung vom Framework durchgeführt werden muss. [...] Wenn kein ConversionService bei Spring registriert ist, wird das ursprüngliche PropertyEditor-basierte System verwendet.

Clemens Klein-Robbenhaar
quelle
6
Java-Konfiguration: @Bean public ConversionService convertService () {neuen DefaultConversionService () zurückgeben; }
Dmitry Chornyi
2
Abgesehen davon, dass Sie sich nicht split()in jedem Ausdruck wiederholen müssen , wird auch eine leere Liste ordnungsgemäß behandelt, anstatt Sie [null]
anzugeben
Es funktioniert nicht, wenn die Eigenschaft überschrieben wird (existiert in mehreren Eigenschaftsquellen.)
Daniel Hári
47

Wenn Sie dies lesen und Spring Boot verwenden , haben Sie 1 weitere Option für diese Funktion

Normalerweise sind durch Kommas getrennte Listen für den realen Anwendungsfall sehr ungeschickt (und manchmal nicht einmal machbar, wenn Sie in Ihrer Konfiguration Kommas verwenden möchten):

email.sendTo=somebody@example.com,somebody2@example.com,somebody3@example.com,.....

Mit Spring Boot können Sie es wie folgt schreiben (Index beginnt bei 0):

email.sendTo[0]=somebody@example.com
email.sendTo[1]=somebody2@example.com
email.sendTo[2]=somebody3@example.com

Und benutze es wie folgt:

@Component
@ConfigurationProperties("email")
public class EmailProperties {

    private List<String> sendTo;

    public List<String> getSendTo() {
        return sendTo;
    }

    public void setSendTo(List<String> sendTo) {
        this.sendTo = sendTo;
    }

}


@Component
public class EmailModel {

  @Autowired
  private EmailProperties emailProperties;

  //Use the sendTo List by 
  //emailProperties.getSendTo()

}



@Configuration
public class YourConfiguration {
    @Bean
  public EmailProperties emailProperties(){
        return new EmailProperties();
  }

}


#Put this in src/main/resource/META-INF/spring.factories
  org.springframework.boot.autoconfigure.EnableAutoConfiguration=example.compackage.YourConfiguration
Ng Sek Long
quelle
Ich habe ein Problem, bei dem die anderen hier beschriebenen Lösungen aufgrund von nicht erkannten Kommas nicht funktionieren. Gibt es eine Möglichkeit, diese Lösung mit Spring 4 durchzuführen?
Sandrozbinden
34

Durch Angabe der my.list.of.strings=ABC,CDE,EFGDatei in .properties und Verwendung

@Value("${my.list.of.strings}") private String[] myString;

Sie können die Arrays von Strings erhalten. Mit CollectionUtils.addAll(myList, myString)können Sie die Liste der Zeichenfolgen abrufen.

Mukesh Kumar
quelle
Ich bekomme nur den ersten String "ABC"
Osama Abdulsattar
19

Haben Sie darüber nachgedacht, @Autowiredden Konstrukteur oder einen Setter String.split()in den Körper zu bringen?

class MyClass {
    private List<String> myList;

    @Autowired
    public MyClass(@Value("${my.list.of.strings}") final String strs) {
        myList = Arrays.asList(strs.split(","));
    }

    //or

    @Autowired
    public void setMyList(@Value("${my.list.of.strings}") final String strs) {
        myList = Arrays.asList(strs.split(","));
    }
}

Ich bevorzuge es, mein Autowiring auf eine dieser Arten durchzuführen, um die Testbarkeit meines Codes zu verbessern.

nicholas.hauschild
quelle
14

Wenn Sie Spring Boot 2 verwenden, funktioniert es ohne zusätzliche Konfiguration unverändert.

my.list.of.strings=ABC,CDE,EFG

@Value("${my.list.of.strings}")
private List<String> myList;
Bienvenido David
quelle
hat bei mir nicht funktioniert, ich muss den Spring EL wie oben gezeigt verwenden.
Bilbo Beutlin
oder sogarprivate List<String> myList;
Halayem Anis
Ja, es hat auch bei mir funktioniert: Ich verwende Spring Boot 2.2.6
Ankit
8

Alle obigen Antworten sind richtig. Sie können dies jedoch in nur einer Zeile erreichen. Bitte versuchen Sie die folgende Deklaration und Sie erhalten alle durch Kommas getrennten Werte in einer String-Liste.

private @Value("#{T(java.util.Arrays).asList(projectProperties['my.list.of.strings'])}") List<String> myList;

Außerdem muss in Ihrer XML-Konfiguration die folgende Zeile definiert sein.

<util:properties id="projectProperties" location="/project.properties"/>

Ersetzen Sie einfach den Pfad und den Dateinamen Ihrer Eigenschaftendatei. Und du bist gut zu gehen. :) :)

Hoffe das hilft dir. Prost.

Japan Trivedi
quelle
1
Das hat bei mir funktioniert, aber ich musste die Anmerkung folgendermaßen formulieren:@Value("#{T(java.util.Arrays).asList('${my.list.of.strings}')}")
Steven
6

Wenn Sie die neueste Spring Framework-Version verwenden (Spring 3.1+, glaube ich), müssen Sie diese Zeichenfolgen in SpringEL nicht teilen.

Fügen Sie einfach PropertySourcesPlaceholderConfigurer und DefaultConversionService zu Ihrer Spring's Configuration-Klasse hinzu (die mit Configuration versehene Klasse), z.

@Configuration
public class AppConfiguration {

    @Bean
    public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }

    @Bean public ConversionService conversionService() {
        return new DefaultConversionService();
    }
}

und in deiner Klasse

@Value("${list}")
private List<String> list;

und in der Eigenschaftendatei

list=A,B,C,D,E

Ohne DefaultConversionService können Sie einen durch Kommas getrennten String nur dann in ein String-Array einfügen, wenn Sie den Wert in Ihr Feld einfügen. DefaultConversionService erledigt jedoch einige praktische Aufgaben für Sie und fügt diese in Collection, Array usw. hinzu (überprüfen Sie die Implementierung, wenn Sie dies möchten möchte mehr darüber wissen)

Mit diesen beiden werden sogar alle redundanten Leerzeichen einschließlich Zeilenumbruch verarbeitet, sodass Sie keine zusätzlichen Logiken hinzufügen müssen, um sie zu kürzen.

Wonhee
quelle
Das Hinzufügen dieser Konfiguration funktioniert, aber es passiert etwas Seltsames: Ich kann @Value nicht für den Dateityp verwenden, ich muss Datei mit Ressource ändern.
ad3luc
2

Sie können dies mit solchen Anmerkungen tun

 @Value("#{T(java.util.Arrays).asList('${my.list.of.strings:a,b,c}')}") 
    private List<String> mylist;

Hier wird my.list.of.strings aus der Eigenschaftendatei ausgewählt. Wenn es nicht vorhanden ist, werden die Standardeinstellungen a, b, c verwendet

und in Ihrer Eigenschaftendatei können Sie so etwas haben

my.list.of.strings = d, e, f

Verma
quelle
2

Achten Sie auf Leerzeichen in den Werten. Ich könnte mich irren, aber ich denke, Leerzeichen in der durch Kommas getrennten Liste werden nicht mit @Value und Spel abgeschnitten. Die Liste

foobar=a, b, c

würde als Liste von Zeichenfolgen eingelesen werden

"a", " b", " c"

In den meisten Fällen würden Sie wahrscheinlich die Räume nicht wollen!

Der Ausdruck

@Value("#{'${foobar}'.trim().replaceAll(\"\\s*(?=,)|(?<=,)\\s*\", \"\").split(',')}")
private List<String> foobarList;

würde Ihnen eine Liste von Zeichenfolgen geben:

"a", "b", "c".

Der reguläre Ausdruck entfernt alle Leerzeichen kurz vor und kurz nach einem Komma. Leerzeichen innerhalb der Werte werden nicht entfernt. So

foobar = AA, B B, CCC

sollte zu Werten führen

"AA", "B B", "CCC".
DAMungra
quelle
Die split () -Methode verwendet intern Regex als Trennzeichen, sodass Ihr Beispiel vereinfacht werden kann: <br/>@Value("#{'${foobar}'.trim().split( *, *)}")
Karlik_B
2

Ich denke, dies ist einfacher, um das Array zu greifen und Leerzeichen zu entfernen:

@Value("#{'${my.array}'.replace(' ', '').split(',')}")
private List<String> array;
Mike Samaras
quelle
2

In meinem Fall einer Liste von ganzen Zahlen funktioniert dies:

@Value("#{${my.list.of.integers}}")
private List<Integer> listOfIntegers;

Eigenschaftendatei:

my.list.of.integers={100,200,300,400,999}
Sergey Nemchinov
quelle
oder @Value ("# {$ {my.set.of.integers}}") private Set <Integer> setOfIntegers;
Alexey Simonov
1

Erwägen Sie die Verwendung der Commons-Konfiguration. Es hat eine integrierte Funktion, um einen Eintrag in der Eigenschaftendatei in Array / Liste zu unterteilen. Das Kämmen mit SpEL und @Value sollte das geben, was Sie wollen


Wie gewünscht, ist hier, was Sie brauchen (Ich habe den Code nicht wirklich ausprobiert, habe möglicherweise Tippfehler, bitte nehmen Sie Kontakt mit mir auf):

In der Apache Commons-Konfiguration gibt es PropertiesConfiguration. Es unterstützt die Funktion zum Konvertieren von begrenzten Zeichenfolgen in Arrays / Listen.

Zum Beispiel, wenn Sie eine Eigenschaftendatei haben

#Foo.properties
foo=bar1, bar2, bar3

Mit dem folgenden Code:

PropertiesConfiguration config = new PropertiesConfiguration("Foo.properties");
String[] values = config.getStringArray("foo");

gibt Ihnen ein String-Array von ["bar1", "bar2", "bar3"]

Um dies mit Spring zu verwenden, haben Sie dies in Ihrem App-Kontext xml:

<bean id="fooConfig" class="org.apache.commons.configuration.PropertiesConfiguration">
    <constructor-arg type="java.lang.String" value="classpath:/Foo.properties"/>
</bean>

und haben dies in Ihrer Frühlingsbohne:

public class SomeBean {

    @Value("fooConfig.getStringArray('foo')")
    private String[] fooArray;
}

Ich glaube, das sollte funktionieren: P.

Adrian Shum
quelle
Könnten Sie genauer über die zu verwendende Methode und Klasse sein, und das tatsächliche Beispielcode-Sniplet wäre großartig.
JackDev
1

Mein bevorzugter Weg (insbesondere für Strings) ist der folgende:

admin.user={'Doe, John','Headroom, Max','Mouse, Micky'}

und verwenden

@Value("#{${admin.user}}")
private List<String> userList;

Auf diese Weise können Sie auch Kommas in Ihren Parameter aufnehmen. Es funktioniert auch für Sets.

Sampisa
quelle
0

Wenn Sie Platzhalter für Eigenschaften verwenden, wird das Beispiel ser1702544

@Value("#{myConfigProperties['myproperty'].trim().replaceAll(\"\\s*(?=,)|(?<=,)\\s*\", \"\").split(',')}") 

Mit Platzhalter xml:

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">   
    <property name="properties" ref="myConfigProperties" />
    <property name="placeholderPrefix"><value>$myConfigProperties{</value></property>
</bean>    

<bean id="myConfigProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
     <property name="locations">
         <list>
                <value>classpath:myprops.properties</value>
         </list>
     </property>
</bean> 
Möwe
quelle
0

Ich benutze Spring Boot 2.2.6

Meine Eigenschaftendatei:

usa.big.banks= JP Morgan, Wells Fargo, Citigroup, Morgan Stanley, Goldman Sachs

Mein Code:

@Value("${usa.big.banks}")
    private List<String> bigBanks;

@RequestMapping("/bigbanks")
    public String getBanks() {
        System.out.println("bigBanks = " + bigBanks);
        return bigBanks.toString();
    }

Es funktioniert gut

Ankit
quelle