Configuration Properties를 사용한 일반적인 맵 채우기
지도에 속성을 입력하는 일반적인 방법이 있는지 궁금하네요. 접두사만 알고 있으면 됩니다.
이런 종류의 물건들이 산더미처럼 있다고 가정하면
namespace.prop1=value1
namespace.prop2=value2
namespace.iDontKnowThisNameAtCompileTime=anothervalue
이 지역을 지도 안에 채우는 일반적인 방법을 알고 싶어요
@Component
@ConfigurationProperties("namespace")
public class MyGenericProps {
private Map<String, String> propmap = new HashMap<String, String>();
// setter and getter for propmap omitted
public Set<String> returnAllKeys() {
return propmap.keySet();
}
}
또는 환경 내의 모든 PropertySources에 대해 반복하지 않고 특정 접두사를 사용하여 모든 속성을 수집할 수 있는 다른 편리한 방법이 있습니까?
고마워 한스호어그
뿐만 아니라 스럽다면 이 할 수 .@ConfigurationProperties에 걸 다namespace 빈 .namespace:
@ConfigurationProperties("")
public class CustomProperties {
private final Map<String, String> namespace = new HashMap<>();
public Map<String, String> getNamespace() {
return namespace;
}
}
에서는 「」를 합니다.getNamespace맵에 속성을 추가할 수 있도록 맵을 가져옵니다.음음음:
namespace.a=alpha
namespace.b=bravo
namespace.c=charlie
namespace에는 map 음 、 3 개 、 3 개 개 개 : : entries entries entries map map map map map map map map mapmap
{a=alpha, b=bravo, c=charlie}
속성이 더 깊이 중첩된 경우, 예를 들어 다음과 같습니다.
namespace.foo.bar.a=alpha
namespace.foo.bar.b=bravo
namespace.foo.bar.c=charlie
★★★★★★★★★★★★★★★★★★★★★★★★.namespace.foo을 변경합니다.namespace ★★★★★★★★★★★★★★★★★」getNamespaceCustomProperties로로 합니다.bar ★★★★★★★★★★★★★★★★★」getBar각각 다음과 같다.
, 이 때 '적용하다'를 주의해 주세요.@EnableConfigurationProperties해, 「」의 하게 합니다.@ConfigurationProperties 이할 수 @Bean 방법 「」 「」 「」를 사용합니다」@Component'CHANGE: 'CHANGE: 'CHANGE: 'CHANGE: 'CHANGE:
@SpringBootApplication
@EnableConfigurationProperties(CustomProperties.class)
public class YourApplication {
// …
}
이와 더불어 간단한 키/값 속성이 여러 개 아닌 전체 개체가 있다는 것이 문제였습니다.
zuul:
routes:
query1:
path: /api/apps/test1/query/**
stripPrefix: false
url: "https://test.url.com/query1"
query2:
path: /api/apps/test2/query/**
stripPrefix: false
url: "https://test.url.com/query2"
index1:
path: /api/apps/*/index/**
stripPrefix: false
url: "https://test.url.com/index"
제이크의 조언에 따라 나는 Pojo와 함께 다음과 같은 지도를 사용하려고 했다.
@ConfigurationProperties("zuul")
public class RouteConfig {
private Map<String, Route> routes = new HashMap<>();
public Map<String, Route> getRoutes() {
return routes;
}
public static class Route {
private String path;
private boolean stripPrefix;
String url;
// [getters + setters]
}
}
마법처럼 잘 먹히네요, 감사합니다!
나는 왜 @Andy의 대답이 나에게 효과가 없는지 이해하려고 미칠 것 같았다.Map내가 롬복의 병을 가지고 있다는 걸 깨달았을 때)@Builder주석으로 인해 생성자가 비어 있지 않습니다. 는 이 대답을 @ConfigurationProperties을 하다Map값 유형에는 No-Arguments 컨스트럭터가 있어야 합니다.이는 Spring 문서에도 기재되어 있습니다.
이러한 배열은 기본 빈 생성자에 의존하며 일반적으로 getter와 setter는 필수입니다.
나는 이것이 다른 누군가의 시간을 절약해 주길 바란다.
는 스스로 글을 .MapFilter이 문제를 효율적으로 처리할 수 있습니다.기본적으로, 사용자는Map그런 다음 키의 접두사를 지정하여 필터링합니다.또, 이 컨스트럭터에서는,Properties편의상
이것은 단지 메인 맵을 필터링 할 뿐이라는 점에 주의해 주세요.필터링된 맵에 적용된 변경은 삭제 등을 포함하여 기본 맵에도 적용되지만 메인 맵에 대한 변경은 재구축이 발생할 때까지 필터링된 맵에 반영되지 않습니다.
또한 이미 필터링된 맵을 필터링하는 것도 매우 쉽고 효율적입니다.
public class MapFilter<T> implements Map<String, T> {
// The enclosed map -- could also be a MapFilter.
final private Map<String, T> map;
// Use a TreeMap for predictable iteration order.
// Store Map.Entry to reflect changes down into the underlying map.
// The Key is the shortened string. The entry.key is the full string.
final private Map<String, Map.Entry<String, T>> entries = new TreeMap<>();
// The prefix they are looking for in this map.
final private String prefix;
public MapFilter(Map<String, T> map, String prefix) {
// Store my backing map.
this.map = map;
// Record my prefix.
this.prefix = prefix;
// Build my entries.
rebuildEntries();
}
public MapFilter(Map<String, T> map) {
this(map, "");
}
private synchronized void rebuildEntries() {
// Start empty.
entries.clear();
// Build my entry set.
for (Map.Entry<String, T> e : map.entrySet()) {
String key = e.getKey();
// Retain each one that starts with the specified prefix.
if (key.startsWith(prefix)) {
// Key it on the remainder.
String k = key.substring(prefix.length());
// Entries k always contains the LAST occurrence if there are multiples.
entries.put(k, e);
}
}
}
@Override
public String toString() {
return "MapFilter (" + prefix + ") of " + map + " containing " + entrySet();
}
// Constructor from a properties file.
public MapFilter(Properties p, String prefix) {
// Properties extends HashTable<Object,Object> so it implements Map.
// I need Map<String,T> so I wrap it in a HashMap for simplicity.
// Java-8 breaks if we use diamond inference.
this(new HashMap<String, T>((Map) p), prefix);
}
// Helper to fast filter the map.
public MapFilter<T> filter(String prefix) {
// Wrap me in a new filter.
return new MapFilter<>(this, prefix);
}
// Count my entries.
@Override
public int size() {
return entries.size();
}
// Are we empty.
@Override
public boolean isEmpty() {
return entries.isEmpty();
}
// Is this key in me?
@Override
public boolean containsKey(Object key) {
return entries.containsKey(key);
}
// Is this value in me.
@Override
public boolean containsValue(Object value) {
// Walk the values.
for (Map.Entry<String, T> e : entries.values()) {
if (value.equals(e.getValue())) {
// Its there!
return true;
}
}
return false;
}
// Get the referenced value - if present.
@Override
public T get(Object key) {
return get(key, null);
}
// Get the referenced value - if present.
public T get(Object key, T dflt) {
Map.Entry<String, T> e = entries.get((String) key);
return e != null ? e.getValue() : dflt;
}
// Add to the underlying map.
@Override
public T put(String key, T value) {
T old = null;
// Do I have an entry for it already?
Map.Entry<String, T> entry = entries.get(key);
// Was it already there?
if (entry != null) {
// Yes. Just update it.
old = entry.setValue(value);
} else {
// Add it to the map.
map.put(prefix + key, value);
// Rebuild.
rebuildEntries();
}
return old;
}
// Get rid of that one.
@Override
public T remove(Object key) {
// Do I have an entry for it?
Map.Entry<String, T> entry = entries.get((String) key);
if (entry != null) {
entries.remove(key);
// Change the underlying map.
return map.remove(prefix + key);
}
return null;
}
// Add all of them.
@Override
public void putAll(Map<? extends String, ? extends T> m) {
for (Map.Entry<? extends String, ? extends T> e : m.entrySet()) {
put(e.getKey(), e.getValue());
}
}
// Clear everything out.
@Override
public void clear() {
// Just remove mine.
// This does not clear the underlying map - perhaps it should remove the filtered entries.
for (String key : entries.keySet()) {
map.remove(prefix + key);
}
entries.clear();
}
@Override
public Set<String> keySet() {
return entries.keySet();
}
@Override
public Collection<T> values() {
// Roll them all out into a new ArrayList.
List<T> values = new ArrayList<>();
for (Map.Entry<String, T> v : entries.values()) {
values.add(v.getValue());
}
return values;
}
@Override
public Set<Map.Entry<String, T>> entrySet() {
// Roll them all out into a new TreeSet.
Set<Map.Entry<String, T>> entrySet = new TreeSet<>();
for (Map.Entry<String, Map.Entry<String, T>> v : entries.entrySet()) {
entrySet.add(new Entry<>(v));
}
return entrySet;
}
/**
* An entry.
*
* @param <T>
*
* The type of the value.
*/
private static class Entry<T> implements Map.Entry<String, T>, Comparable<Entry<T>> {
// Note that entry in the entry is an entry in the underlying map.
private final Map.Entry<String, Map.Entry<String, T>> entry;
Entry(Map.Entry<String, Map.Entry<String, T>> entry) {
this.entry = entry;
}
@Override
public String getKey() {
return entry.getKey();
}
@Override
public T getValue() {
// Remember that the value is the entry in the underlying map.
return entry.getValue().getValue();
}
@Override
public T setValue(T newValue) {
// Remember that the value is the entry in the underlying map.
return entry.getValue().setValue(newValue);
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Entry)) {
return false;
}
Entry e = (Entry) o;
return getKey().equals(e.getKey()) && getValue().equals(e.getValue());
}
@Override
public int hashCode() {
return getKey().hashCode() ^ getValue().hashCode();
}
@Override
public String toString() {
return getKey() + "=" + getValue();
}
@Override
public int compareTo(Entry<T> o) {
return getKey().compareTo(o.getKey());
}
}
// Simple tests.
public static void main(String[] args) {
String[] samples = {
"Some.For.Me",
"Some.For.You",
"Some.More",
"Yet.More"};
Map map = new HashMap();
for (String s : samples) {
map.put(s, s);
}
Map all = new MapFilter(map);
Map some = new MapFilter(map, "Some.");
Map someFor = new MapFilter(some, "For.");
System.out.println("All: " + all);
System.out.println("Some: " + some);
System.out.println("Some.For: " + someFor);
}
}
제가 지나다니는 대부분의 장소들은 설명이 부족하거나 조금 구식이기 때문에, 제가 그렇게 하기 위해 취한 모든 단계들을 소개합니다.주의: 사용한Spring 부트버전은 2.4.0 입니다.
Add in pom.xml - spring-boot-configuration-processor
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>속성 파일을 만들고 그 안에 데이터를 설정합니다.shared-messages.properties 주의: "LIBRARY_10001"은 맵 키이고 "Unable to find the book"은 맵 값입니다.
shared-messages.messages.LIBRARY_10001=Unable to find the book shared-messages.messages.LIBRARY_10002=Book already exists속성 파일을 사용하는 속성 클래스를 만듭니다.
@ConfigurationProperties("shared-messages") @Getter public class LibraryProperties { private final Map<String, String> messages = new HashMap<>(); }애플리케이션 수준에서 속성 소스를 정의하고 구성 속성을 사용하도록 설정합니다.
@EnableConfigurationProperties(LibraryProperties.class) @PropertySource("shared-messages.properties") public class LibraryApplication { .... }서비스 레벨에서 "LibraryProperties" 클래스를 삽입하고 필요한 속성에 액세스합니다.
@Autowired private LibraryProperties libraryProperties; libraryProperties.getMessages().get("LIBRARY_10001")
완벽한 솔루션은 아닐 수도 있지만, 다른 조합을 시도했지만 나에게는 맞지 않았기 때문에 그 방법을 공유했습니다.
언급URL : https://stackoverflow.com/questions/31045955/using-configurationproperties-to-fill-map-in-generic-way
'programing' 카테고리의 다른 글
| react 라우터 v^4.0.0 Uncaughed TypeError: 정의되지 않은 속성 '위치'를 읽을 수 없습니다. (0) | 2023.03.05 |
|---|---|
| componentDidCatch와 동등한 리액트 훅? (0) | 2023.03.05 |
| PyMongo 3이 Server Selection을 제공하는 이유TimeoutError? (0) | 2023.03.05 |
| Ajax의 유형과 메서드 간 차이는 무엇입니까? (0) | 2023.03.05 |
| componentDidMount가 콜백을 참조하기 전에 호출되었습니다. (0) | 2023.03.05 |