Comment remplir HashMap à partir du fichier de propriétés java avec Spring @Value

est-il possible d'utiliser la valeur Spring@, pour mapper les valeurs du fichier de propriétés vers le HashMap.

actuellement j'ai quelque chose comme ça, et mapper une valeur n'est pas un problème. Mais j'ai besoin de cartographier les valeurs personnalisées dans les expirations HashMap. Est quelque chose comme cela possible?

@Service
@PropertySource(value = "classpath:my_service.properties")
public class SomeServiceImpl implements SomeService {


    @Value("#{conf['service.cache']}")
    private final boolean useCache = false;

    @Value("#{conf['service.expiration.[<custom name>]']}")
    private final HashMap<String, String> expirations = new HashMap<String, String>();

fichier de propriétés: 'my_service.propriétés'

service.cache=true
service.expiration.name1=100
service.expiration.name2=20

est-il possible de map comme cette clé:valeur définie

  • nom1 = 100

  • nom2 = 20

22
demandé sur d-sauer 2015-02-06 18:45:54

5 réponses

est-il possible d'utiliser la valeur Spring@, pour mapper les valeurs du fichier de propriétés vers le HashMap?

Oui, il est. Avec un peu d'aide de code et Spel.

tout D'abord, considérez ce haricot à ressort (vous devriez le scanner):

@Component("PropertySplitter")
public class PropertySplitter {

    /**
     * Example: one.example.property = KEY1:VALUE1,KEY2:VALUE2
     */
    public Map<String, String> map(String property) {
        return this.map(property, ",");
    }

    /**
     * Example: one.example.property = KEY1:VALUE1.1,VALUE1.2;KEY2:VALUE2.1,VALUE2.2
     */
    public Map<String, List<String>> mapOfList(String property) {
        Map<String, String> map = this.map(property, ";");

        Map<String, List<String>> mapOfList = new HashMap<>();
        for (Entry<String, String> entry : map.entrySet()) {
            mapOfList.put(entry.getKey(), this.list(entry.getValue()));
        }

        return mapOfList;
    }

    /**
     * Example: one.example.property = VALUE1,VALUE2,VALUE3,VALUE4
     */
    public List<String> list(String property) {
        return this.list(property, ",");
    }

    /**
     * Example: one.example.property = VALUE1.1,VALUE1.2;VALUE2.1,VALUE2.2
     */
    public List<List<String>> groupedList(String property) {
        List<String> unGroupedList = this.list(property, ";");

        List<List<String>> groupedList = new ArrayList<>();
        for (String group : unGroupedList) {
            groupedList.add(this.list(group));
        }

        return groupedList;

    }

    private List<String> list(String property, String splitter) {
        return Splitter.on(splitter).omitEmptyStrings().trimResults().splitToList(property);
    }

    private Map<String, String> map(String property, String splitter) {
        return Splitter.on(splitter).omitEmptyStrings().trimResults().withKeyValueSeparator(":").split(property);
    }

}

Remarque:PropertySplitter class Splitter utilitaire à partir de la goyave. Veuillez vous référer à sa documentation pour plus de détails.

puis, dans un haricot de la vôtre:

@Component
public class MyBean {

    @Value("#{PropertySplitter.map('${service.expiration}')}")
    Map<String, String> propertyAsMap;

}

Et enfin, la propriété:

service.expiration = name1:100,name2:20

Ce n'est pas exactement ce que vous avez demandé, parce que ce PropertySplitter fonctionne avec une seule propriété qui est transformée dans un Map, mais je pense que vous pouvez soit passer à cette façon de spécifier les propriétés, soit modifier le PropertySplitter code de sorte qu'il corresponde à la façon plus hiérarchique que vous désirez.

18
répondu Federico Peralta Schaffner 2015-02-06 17:07:41

je fais une solution inspirée du post précédent.

Enregistrer le fichier de propriétés dans la configuration du ressort:

<util:properties id="myProp" location="classpath:my.properties"/>

Et j'ai créer un composant:

@Component("PropertyMapper")
public class PropertyMapper {

    @Autowired
    ApplicationContext applicationContext;

    public HashMap<String, Object> startWith(String qualifier, String startWith) {
        return startWith(qualifier, startWith, false);
    }

    public HashMap<String, Object> startWith(String qualifier, String startWith, boolean removeStartWith) {
        HashMap<String, Object> result = new HashMap<String, Object>();

        Object obj = applicationContext.getBean(qualifier);
        if (obj instanceof Properties) {
            Properties mobileProperties = (Properties)obj;

            if (mobileProperties != null) {
                for (Entry<Object, Object> e : mobileProperties.entrySet()) {
                    Object oKey = e.getKey();
                    if (oKey instanceof String) {
                        String key = (String)oKey;
                        if (((String) oKey).startsWith(startWith)) {
                            if (removeStartWith) 
                                key = key.substring(startWith.length());
                            result.put(key, e.getValue());
                        }
                    }
                }
            }
        }

        return result;
    }
}

Et quand je veux la carte toutes les propriétés qui commencent avec specifix de la valeur à table de hachage, avec @Valeur de l'annotation:

@Service
public class MyServiceImpl implements MyService {

    @Value("#{PropertyMapper.startWith('myProp', 'service.expiration.', true)}")
    private HashMap<String, Object> portalExpirations;
15
répondu d-sauer 2015-02-09 15:47:19

le moyen Le plus rapide de Printemps Boot solution basée je peux penser à la suite. Dans mon exemple particulier, je suis en train de migrer des données d'un système à un autre. C'est pourquoi j'ai besoin d'une cartographie d'un champ appelé prioritaire.

J'ai d'abord créé le fichier de propriétés (priority-migration.les propriétés) comme tel:

my.prefix.priority.0:0
my.prefix.priority.10:1
my.prefix.priority.15:2
my.prefix.priority.20:2
another.prefix.foo:bar

et le mettre sur le chemin de la classe.

en supposant que vous voulez utiliser la carte dans une fève/composante gérée au printemps, annoter votre classe:

@Component
@PropertySource("classpath:/priority-migration.properties")

ce que vous voulez réellement dans votre carte est bien sûr seulement les paires clé/valeur qui sont préfixées avec my.préfixe, c'est à dire cette partie:

{
    0:0
    10:1
    15:2
    20:2
}

pour ce faire, vous devez annoter votre composant avec

@ConfigurationProperties("my.prefix")

et créer un getter pour l' prioritaire infix. Ce dernier point s'est avéré obligatoire dans mon cas (bien que le Sring Doc dit il suffit d'avoir une propriété prioritaire et l'initialiser avec une valeur mutable)

private final Map<Integer, Integer> priorityMap = new HashMap<>();

public Map<Integer, Integer> getPriority() {
    return priorityMap;
}

À la Fin

Il ressemble à quelque chose comme ceci:

@Component
@ConfigurationProperties("my.prefix")
@PropertySource("classpath:/priority-migration.properties")
class PriorityProcessor {

    private final Map<Integer, Integer> priorityMap = new HashMap<>();

    public Map<Integer, Integer> getPriority() {
        return priorityMap;
    }

    public void process() {

        Integer myPriority = priorityMap.get(10)
        // use it here
    }
}
6
répondu Viktor Stoitschev 2017-11-18 18:41:34

À Partir Du Printemps 4.1.x ( je ne me souviens pas de version spécifique ), vous pouvez faire quelque chose comme

@Value("#{${your.properties.key.name}}")
private Map<String, String> myMap;

Où est votre.propriétés.la clé.nom dans votre fichier de propriétés devrait être quelque chose comme

your.properties.key.name={\
    name1 : 100, \
    name2 : 200 \
}

assurez-vous juste que vous devez créer PropertySourcesPlaceholderConfigurer bean pour le faire fonctionner à la fois dans votre application et si vous écrivez un code de test d'unité pour tester votre code, sinon ${...} pour la valeur de la propriété ne fonctionne pas comme prévu et vous verrez des erreurs de ressorts bizarres.

3
répondu wonhee 2018-06-22 00:30:18

vous pouvez utiliser la syntaxe SPEL json-like pour écrire une carte simple ou une carte de liste dans le fichier de propriétés.

simple.map={'KEY1': 'value1', 'KEY2': 'value3', 'KEY3': 'value5'}

map.of.list={\
  'KEY1': {'value1','value2'}, \
  'KEY2': {'value3','value4'}, \
  'KEY3': {'value5'} \
 }

j'ai utilisé \ pour la propriété multiligne pour améliorer la lisibilité

Puis, en Java, vous pouvez accéder et d'analyser automatiquement avec @Value comme ceci.

@Value("#{${simple.map}}")
Map<String, String> simpleMap;

@Value("#{${map.of.list}}")
Map<String, List<String>> mapOfList;

Ici ${simple.map},@Value obtient la chaîne suivante du fichier de propriétés:

"{'KEY1': 'value1', 'KEY2': 'value3', 'KEY3': 'value5'}"

Ensuite, il est évalué comme si c'était inline

@Value("#{{'KEY1': 'value1', 'KEY2': 'value3', 'KEY3': 'value5'}}")

vous pouvez en savoir plus en la documentation officielle

0
répondu Marc Bouvier 2018-09-21 08:34:09