복붙노트

[SPRING] 스프링 @Value를 사용하여 자바 속성 파일에서 HashMap을 채우는 법

SPRING

스프링 @Value를 사용하여 자바 속성 파일에서 HashMap을 채우는 법

Spring @Value를 사용하여 속성 파일에서 HashMap으로 값을 매핑 할 수 있습니까?

현재 나는 이와 같은 것을 가지고 있으며, 하나의 값을 매핑하는 것은 문제가되지 않습니다. 하지만 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>();

속성 파일 : 'my_service.properties'

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

이 키처럼 맵핑 할 수 있습니까?

해결법

  1. ==============================

    1.예, 그렇습니다. 코드와 Spel의 도움으로

    예, 그렇습니다. 코드와 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 코드를 수정하여보다 계층적인 네가 원하는대로.

  2. ==============================

    2.나는 이전 게시물에서 영감을 얻은 하나의 솔루션을 만듭니다.

    나는 이전 게시물에서 영감을 얻은 하나의 솔루션을 만듭니다.

    스프링 설정에 등록 정보 파일 등록 :

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

    그리고 특정 값으로 시작하는 모든 속성을 @Value 주석과 함께 HashMap에 매핑하고자 할 때 :

    @Service
    public class MyServiceImpl implements MyService {
    
        @Value("#{PropertyMapper.startWith('myProp', 'service.expiration.', true)}")
        private HashMap<String, Object> portalExpirations;
    
  3. ==============================

    3.제가 생각할 수있는 가장 빠른 스프링 부트 기반 솔루션은 다음과 같습니다. 필자의 특별한 예에서는 한 시스템에서 다른 시스템으로 데이터를 마이그레이션하고 있습니다. 그래서 우선 순위라는 필드에 대한 매핑이 필요합니다.

    제가 생각할 수있는 가장 빠른 스프링 부트 기반 솔루션은 다음과 같습니다. 필자의 특별한 예에서는 한 시스템에서 다른 시스템으로 데이터를 마이그레이션하고 있습니다. 그래서 우선 순위라는 필드에 대한 매핑이 필요합니다.

    먼저 다음과 같이 속성 파일 (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
    

    classpath에 놓으십시오.

    스프링 관리 빈 / 컴포넌트에서 맵을 사용한다고 가정하면 다음과 같이 클래스에 주석을 추가하십시오.

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

    지도에서 실제로 원하는 것은 my.prefix라는 접두어가 붙은 키 / 값 쌍인 것입니다. 즉,이 부분은 다음과 같습니다.

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

    이를 달성하려면 구성 요소에 주석을 달아야합니다.

    @ConfigurationProperties("my.prefix")
    

    우선 순위 중위에 대한 getter를 생성합니다. 후자는 필자의 경우에 필수적인 것으로 판명되었다. (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. ==============================

    4.Spring 4.1.x (특정 버전을 기억하지 못함)에서 다음과 같이 할 수 있습니다.

    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 빈을 만들어야하고 코드를 테스트 할 단위 테스트 코드를 작성하는 경우에는 $ {...} 속성 값의 자리 표시자가 예상대로 작동하지 않으며 이상한 SpringEL 오류가 나타날 것입니다.

  5. ==============================

    5.SPEL json과 같은 구문을 사용하여 속성 파일에 간단한지도 또는 목록의지도를 작성할 수 있습니다.

    SPEL json과 같은 구문을 사용하여 속성 파일에 간단한지도 또는 목록의지도를 작성할 수 있습니다.

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

    가독성을 높이기 위해 \를 multiline 속성으로 사용했습니다.

    그런 다음 자바에서는 @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'}}")
    

    공식 문서에서 더 많은 것을 배울 수 있습니다.

  6. from https://stackoverflow.com/questions/28369458/how-to-fill-hashmap-from-java-property-file-with-spring-value by cc-by-sa and MIT license