Как заполнить HashMap из файла свойств java с помощью Spring @Value
можно ли использовать Spring @Value, чтобы отобразить значения из файла свойств в HashMap.
в настоящее время у меня есть что-то вроде этого, и сопоставление одно значение-это не проблема. Но мне нужно сопоставить пользовательские значения в HashMap expirations. Возможно ли что-то подобное?
@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.свойства'
service.cache=true
service.expiration.name1=100
service.expiration.name2=20
возможно ли сопоставить такой ключ: value set
имя1 = 100
name2 = 20
5 ответов
можно ли использовать 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
класс использует Splitter
утилита от Guava. Пожалуйста, обратитесь к документация для получения дополнительной информации.
потом, в некоторых твой боб:
@Component
public class MyBean {
@Value("#{PropertySplitter.map('${service.expiration}')}")
Map<String, String> propertyAsMap;
}
и, наконец, собственность:
service.expiration = name1:100,name2:20
это не совсем то, что вы спросили, потому что это PropertySplitter
работает с одним единственным свойством, является преобразовано на Map
, но я думаю, вы можете переключиться на этот способ указания свойств или изменить PropertySplitter
код, чтобы он соответствовал более иерархическому способу, который вы хотите.
Я делаю одно решение, вдохновленное предыдущим сообщением.
зарегистрировать файл свойств в конфигурации 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;
}
}
и когда я хочу сопоставить все свойства, начинающиеся со значения specifix, с HashMap, с аннотацией @Value:
@Service
public class MyServiceImpl implements MyService {
@Value("#{PropertyMapper.startWith('myProp', 'service.expiration.', true)}")
private HashMap<String, Object> portalExpirations;
быстрый весны Boot решение я могу думать о следующем. В моем конкретном примере я переношу данные из одной системы в другую. Вот почему мне нужно сопоставление для поля приоритет.
сначала я создал файл свойств (приоритет-миграция.свойства) вроде таких:
my.prefix.priority.0:0
my.prefix.priority.10:1
my.prefix.priority.15:2
my.prefix.priority.20:2
another.prefix.foo:bar
и положить его в classpath.
предполагая, что вы хотите использовать карту в spring managed bean / component, аннотируйте свой класс с:
@Component
@PropertySource("classpath:/priority-migration.properties")
то, что вы действительно хотите на своей карте, - это, конечно, только пары ключ/значение, которые имеют префикс my.приставка, т. е. эта часть:
{
0:0
10:1
15:2
20:2
}
для этого вам нужно аннотировать свой компонент с помощью
@ConfigurationProperties("my.prefix")
и создать геттер для приоритет infix. Последнее оказалось обязательным в моем случае (хотя 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
}
}
С Весны 4.1.х ( я не помню конкретную версию ), вы можете сделать что-то вроде
@Value("#{${your.properties.key.name}}")
private Map<String, String> myMap;
где ваш.свойства.ключ.имя в вашем файле свойств должно быть что-то вроде
your.properties.key.name={\
name1 : 100, \
name2 : 200 \
}
просто убедитесь, что вы должны создать компонент PropertySourcesPlaceholderConfigurer, чтобы он работал как в вашем приложении, так и при написании кода модульного теста для тестирования кода, иначе ${...} заполнитель для значения свойства не будет работать должным образом, и вы увидите некоторые странные ошибки SpringEL.
вы можете использовать синтаксис 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'}}")
вы можете узнать больше в официальная документация