[英]How to fill HashMap from java property file with Spring @Value
是否可以使用 Spring @Value,从属性文件到 map 值到 HashMap。
目前我有这样的东西,映射一个值不是问题。 但我需要在 HashMap 到期时使用 map 自定义值。 这样的事情可能吗?
@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>();
属性文件:'my_service.properties'
service.cache=true
service.expiration.name1=100
service.expiration.name2=20
是否可以像这样设置 map 键:值集
名称 1 = 100
名称 2 = 20
您可以使用类似于 SPEL json 的语法在属性文件中编写简单的映射或列表映射。
simple.map={'KEY1': 'value1', 'KEY2': 'value3', 'KEY3': 'value5'}
map.of.list={\
'KEY1': {'value1','value2'}, \
'KEY2': {'value3','value4'}, \
'KEY3': {'value5'} \
}
我使用\\
作为多行属性来增强可读性
然后,在 Java 中,您可以像这样使用@Value
自动访问和解析它。
@Value("#{${simple.map}}")
Map<String, String> simpleMap;
@Value("#{${map.of.list}}")
Map<String, List<String>> mapOfList;
这里使用${simple.map}
, @Value
从属性文件中获取以下字符串:
"{'KEY1': 'value1', 'KEY2': 'value3', 'KEY3': 'value5'}"
然后,它被评估为好像它是内联的
@Value("#{{'KEY1': 'value1', 'KEY2': 'value3', 'KEY3': 'value5'}}")
是否可以使用 Spring @Value 将值从属性文件映射到 HashMap?
是的。 在代码和Spel 的帮助下。
首先,考虑这个单例 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);
}
}
注意: PropertySplitter
类使用来自 Guava 的Splitter
实用程序。 有关更多详细信息,请参阅其文档。
然后,在你的一些豆子中:
@Component
public class MyBean {
@Value("#{PropertySplitter.map('${service.expiration}')}")
Map<String, String> propertyAsMap;
}
最后,属性:
service.expiration = name1:100,name2:20
这并不完全是您所问的,因为这个PropertySplitter
使用一个转换为Map
单个属性,但我认为您可以切换到这种指定属性的方式,或者修改PropertySplitter
代码,使其与更多层次结构相匹配你想要的方式。
从 Spring 4.1.x(虽然我不记得具体版本),你可以做类似的事情
@Value("#{${your.properties.key.name}}")
private Map<String, String> myMap;
您的属性文件中的 your.properties.key.name 应该类似于
your.properties.key.name={\
name1 : 100, \
name2 : 200 \
}
只要确保您应该创建 PropertySourcesPlaceholderConfigurer bean 以使其在您的应用程序中工作,如果您正在编写任何单元测试代码来测试您的代码,否则属性值的 ${...} 占位符将无法按预期工作,并且你会看到一些奇怪的 SpringEL 错误。
我能想到的最快的基于 Spring Boot的解决方案如下。 在我的特定示例中,我将数据从一个系统迁移到另一个系统。 这就是为什么我需要一个名为priority的字段的映射。
首先,我创建了这样的属性文件(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
并将其放在类路径上。
假设您想在 spring 管理的 bean/组件中使用映射,请使用以下注释对您的类进行注释:
@Component
@PropertySource("classpath:/priority-migration.properties")
您在地图中真正想要的当然只是以 my.prefix 为前缀的键/值对,即这部分:
{
0:0
10:1
15:2
20:2
}
要实现这一点,您需要使用
@ConfigurationProperties("my.prefix")
并为优先级中缀创建一个吸气剂。 后者在我的情况下被证明是强制性的(尽管Sring Doc说拥有一个属性优先级并用可变值初始化它就足够了)
private final Map<Integer, Integer> priorityMap = new HashMap<>();
public Map<Integer, Integer> getPriority() {
return priorityMap;
}
到底
它看起来像这样:
@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
}
}
我根据上一篇文章提出了一个解决方案。
在 Spring 配置中注册属性文件:
<util:properties id="myProp" location="classpath:my.properties"/>
我创建组件:
@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;
}
}
当我想将所有以特定值开头的属性映射到 HashMap 时,使用 @Value 注释:
@Service
public class MyServiceImpl implements MyService {
@Value("#{PropertyMapper.startWith('myProp', 'service.expiration.', true)}")
private HashMap<String, Object> portalExpirations;
使用@Value从application.yml属性中提取Map 的解决方案编码为多行
应用程序.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
这里,我们的地图属性“my-map-property-name”的值以JSON格式存储在一个字符串中,我们在行尾使用\\ 实现了多行
我的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...
} }
}
更多解释
\\在 yaml 中用于将字符串分成多行
\\"是 yaml 字符串中 "(quote) 的转义字符
yaml 中的{key:value} JSON 将被 @Value 转换为 Map
#{ }是SpEL 表达式,可以在@Value 中使用,转换json int Map 或Array / list 参考
在 Spring Boot 项目中测试
使用与 Yaml 名称相同的变量名称
例如:
private final HashMap<String, String> expiration
代替
private final HashMap<String, String> expirations
或者属性文件中类似的东西
org.code=0009,0008,0010
org.code.0009.channel=30,40
org.code.0008.channel=30,40
org.code.0010.channel=30,40
在 Java 中,读取 org.code 然后遍历每个 org.code 并构建 org.code..channel 并将其放入 map....
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.