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
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.
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;
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
}
}
À 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.
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