如何使用 Spring @Value 从 java 属性文件填充 HashMap
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28369458/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to fill HashMap from java property file with Spring @Value
提问by d-sauer
Is it possible to use Spring @Value, to map values from properties file to the HashMap.
是否可以使用 Spring @Value 将值从属性文件映射到 HashMap。
Currently I have something like this, and mapping one value is not a problem. But I need to map custom values in HashMap expirations. Is something like this possible?
目前我有这样的东西,映射一个值不是问题。但我需要在 HashMap 到期时映射自定义值。这样的事情可能吗?
@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>();
Property file: 'my_service.properties'
属性文件:'my_service.properties'
service.cache=true
service.expiration.name1=100
service.expiration.name2=20
Is it posible to map like this key:value set
是否可以像这样映射键:值集
name1 = 100
name2 = 20
名称 1 = 100
名称 2 = 20
采纳答案by d-sauer
I make one solution inspired by the previous post.
我根据上一篇文章提出了一个解决方案。
Register property file in the Spring configuration:
在 Spring 配置中注册属性文件:
<util:properties id="myProp" location="classpath:my.properties"/>
And I create component:
我创建组件:
@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;
}
}
And when I want to map all properties that begin with specifix value to HashMap, with @Value annotation:
当我想将所有以特定值开头的属性映射到 HashMap 时,使用 @Value 注释:
@Service
public class MyServiceImpl implements MyService {
@Value("#{PropertyMapper.startWith('myProp', 'service.expiration.', true)}")
private HashMap<String, Object> portalExpirations;
回答by Federico Peralta Schaffner
Is it possible to use Spring @Value, to map values from properties file to the HashMap?
是否可以使用 Spring @Value 将值从属性文件映射到 HashMap?
Yes, it is. With a little help of code and Spel.
是的。在代码和Spel 的帮助下。
Firstly, consider this singleton Spring-bean (you should scan it):
首先,考虑这个单例 Spring-bean(你应该扫描它):
@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);
}
}
Note:PropertySplitter
class uses Splitter
utility from Guava. Please refer to its documentationfor further details.
注意:PropertySplitter
类使用Splitter
来自番石榴的实用程序。有关更多详细信息,请参阅其文档。
Then, in some bean of yours:
然后,在你的一些豆子中:
@Component
public class MyBean {
@Value("#{PropertySplitter.map('${service.expiration}')}")
Map<String, String> propertyAsMap;
}
And finally, the property:
最后,属性:
service.expiration = name1:100,name2:20
It's not exactly what you've asked, because this PropertySplitter
works with one single property that is transformedinto a Map
, but I think you could either switch to this way of specifying properties, or modify the PropertySplitter
code so that it matches the more hierarchical way you desire.
这不完全是您所要求的,因为这PropertySplitter
适用于转换为 a 的单个属性Map
,但我认为您可以切换到这种指定属性的方式,或者修改PropertySplitter
代码以使其与您希望的更分层的方式相匹配.
回答by Viktor Stoitschev
The quickest Spring Bootbased solution I can think of follows. In my particular example I am migrating data from one system to another. That is why I need a mapping for a field called priority.
我能想到的最快的基于Spring Boot的解决方案如下。在我的特定示例中,我将数据从一个系统迁移到另一个系统。这就是为什么我需要一个名为priority的字段的映射。
First I've created the properties file (priority-migration.properties) like such:
首先,我创建了这样的属性文件(priority-migration.properties):
my.prefix.priority.0:0
my.prefix.priority.10:1
my.prefix.priority.15:2
my.prefix.priority.20:2
another.prefix.foo:bar
and put it on the classpath.
并将其放在类路径上。
Assuming you want to use the map in a spring managed bean/component, annotate your class with:
假设您想在 spring 管理的 bean/组件中使用映射,请使用以下注释对您的类进行注释:
@Component
@PropertySource("classpath:/priority-migration.properties")
What you actually want in your map is of course only the key/value pairs which are prefixed with my.prefix, i.e. this part:
您在地图中真正想要的当然只是以 my.prefix 为前缀的键/值对,即这部分:
{
0:0
10:1
15:2
20:2
}
To achieve that you need to annotate your component with
要实现这一点,您需要使用
@ConfigurationProperties("my.prefix")
and create a getter for the priorityinfix. The latter proved to be mandatory in my case (although the Sring Docsays it is enough to have a property priorityand initialize it with a mutable value)
并为优先级中缀创建一个吸气剂。后者在我的情况下被证明是强制性的(尽管Sring Doc说拥有一个属性优先级并用可变值初始化它就足够了)
private final Map<Integer, Integer> priorityMap = new HashMap<>();
public Map<Integer, Integer> getPriority() {
return priorityMap;
}
In the End
到底
It looks something like this:
它看起来像这样:
@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
}
}
回答by wonhee
From Spring 4.1.x ( I can't remember specific version though ), you can do something like
从 Spring 4.1.x(虽然我不记得具体版本),你可以做类似的事情
@Value("#{${your.properties.key.name}}")
private Map<String, String> myMap;
where your.properties.key.name in your properties file should be something like
您的属性文件中的 your.properties.key.name 应该类似于
your.properties.key.name={\
name1 : 100, \
name2 : 200 \
}
Just make sure that you should create PropertySourcesPlaceholderConfigurer bean to make it work both in your app and if you are writing any unit test code to test your code, otherwise ${...} placeholder for the property value won't work as expected and you'll see some weird SpringEL errors.
只要确保您应该创建 PropertySourcesPlaceholderConfigurer bean 以使其在您的应用程序中工作,如果您正在编写任何单元测试代码来测试您的代码,否则属性值的 ${...} 占位符将无法按预期工作,并且你会看到一些奇怪的 SpringEL 错误。
回答by Marc Bouvier
You can use the SPEL json-like syntax to write a simple map or a map of list in property file.
您可以使用类似于 SPEL json 的语法在属性文件中编写简单的映射或列表映射。
simple.map={'KEY1': 'value1', 'KEY2': 'value3', 'KEY3': 'value5'}
map.of.list={\
'KEY1': {'value1','value2'}, \
'KEY2': {'value3','value4'}, \
'KEY3': {'value5'} \
}
I used \
for multiline property to enhance readability
我用于\
多行属性以增强可读性
Then, in Java, you can access and parse it automatically with @Value
like this.
然后,在 Java 中,您可以@Value
像这样自动访问和解析它。
@Value("#{${simple.map}}")
Map<String, String> simpleMap;
@Value("#{${map.of.list}}")
Map<String, List<String>> mapOfList;
Here with ${simple.map}
, @Value
gets the following String from the property file:
在这里${simple.map}
,@Value
从属性文件中获取以下字符串:
"{'KEY1': 'value1', 'KEY2': 'value3', 'KEY3': 'value5'}"
Then, it is evaluated as if it was inlined
然后,它被评估为好像它是内联的
@Value("#{{'KEY1': 'value1', 'KEY2': 'value3', 'KEY3': 'value5'}}")
You can learn more in the official documentation
回答by Milan
Solution for pulling Mapusing @Valuefrom application.ymlproperty coded as multiline
使用@Value从 application.yml属性中提取Map 的解决方案编码为多行
application.yml
应用程序.yml
other-prop: just for demo
my-map-property-name: "{\
key1: \"ANY String Value here\", \
key2: \"any number of items\" , \
key3: \"Note the Last item does not have comma\" \
}"
other-prop2: just for demo 2
Here the value for our map property "my-map-property-name" is stored in JSONformat inside a stringand we have achived multiline using \at end of line
在这里,我们的地图属性“my-map-property-name”的值以JSON格式存储在一个字符串中,我们在行尾使用\ 实现了多行
myJavaClass.java
我的JavaClass.java
import org.springframework.beans.factory.annotation.Value;
public class myJavaClass {
@Value("#{${my-map-property-name}}")
private Map<String,String> myMap;
public void someRandomMethod (){
if(myMap.containsKey("key1")) {
//todo...
} }
}
More explanation
更多解释
\in yaml it is Used to break string into multiline
\"is escape charater for "(quote) in yaml string
{key:value}JSON in yaml which will be converted to Map by @Value
#{ }it is SpEL expresion and can be used in @Value to convert json int Map or Array / list Reference
\在 yaml 中用于将字符串分成多行
\"是 yaml 字符串中 "(quote) 的转义字符
yaml 中的{key:value}JSON 将被 @Value 转换为 Map
#{ }是SpEL 表达式,可以在@Value 中使用,转换json int Map 或Array / list参考
Tested in a spring boot project
在 Spring Boot 项目中测试