diff --git a/spring-boot/002-properties-bind/src/main/java/com/git/hui/boot/bind/config/BindConfig.java b/spring-boot/002-properties-bind/src/main/java/com/git/hui/boot/bind/config/BindConfig.java index f8b90b53..c1be3cd2 100644 --- a/spring-boot/002-properties-bind/src/main/java/com/git/hui/boot/bind/config/BindConfig.java +++ b/spring-boot/002-properties-bind/src/main/java/com/git/hui/boot/bind/config/BindConfig.java @@ -1,9 +1,12 @@ package com.git.hui.boot.bind.config; import lombok.Data; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.core.env.Environment; import org.springframework.validation.annotation.Validated; +import javax.annotation.PostConstruct; import javax.validation.constraints.Max; import javax.validation.constraints.Min; import java.util.List; @@ -31,4 +34,17 @@ public class BindConfig { private Pwd mainPwd; private Jwt jwt; + + /** + * fixme 对于列表这种嵌套的方式,生成的 spring-configuration-metadata.json 无法友好的支持它; 即IDEA中,在yml文件中,配置对应的属性时,无法直接定位到 Jwt#token + */ + private List tokens; + + @Autowired + private Environment environment; + + @PostConstruct + public void init() { + System.out.println(tokens); + } } diff --git a/spring-boot/002-properties-bind/src/main/resources/application-bind.yml b/spring-boot/002-properties-bind/src/main/resources/application-bind.yml index d8574041..d0eb955b 100644 --- a/spring-boot/002-properties-bind/src/main/resources/application-bind.yml +++ b/spring-boot/002-properties-bind/src/main/resources/application-bind.yml @@ -17,4 +17,9 @@ hhui: user: 一灰灰blog pwd: yihuihui code: 9 - Jwt: '{"token": "11111111123", "timestamp": 1610880489123}' \ No newline at end of file + Jwt: '{"token": "11111111123", "timestamp": 1610880489123}' + tokens: + - token: 123 + timestamp: 1111111 + - token: abc + timestamp: 2222222 \ No newline at end of file diff --git a/spring-boot/002-properties-bind/src/main/resources/application.yml b/spring-boot/002-properties-bind/src/main/resources/application.yml index a56964cb..bf8241d8 100644 --- a/spring-boot/002-properties-bind/src/main/resources/application.yml +++ b/spring-boot/002-properties-bind/src/main/resources/application.yml @@ -2,3 +2,12 @@ spring: profiles: active: bind + +val: + inj: + - a: 1 + b: 2 + c: 3 + - z: 10 + zz: 11 + zzz: 12 \ No newline at end of file diff --git a/spring-boot/002-properties-value/.gitignore b/spring-boot/002-properties-value/.gitignore new file mode 100644 index 00000000..e168aa9f --- /dev/null +++ b/spring-boot/002-properties-value/.gitignore @@ -0,0 +1,4 @@ +.* +target/* +*.iml +!.gitignore diff --git a/spring-boot/002-properties-value/pom.xml b/spring-boot/002-properties-value/pom.xml new file mode 100644 index 00000000..5f4a3671 --- /dev/null +++ b/spring-boot/002-properties-value/pom.xml @@ -0,0 +1,15 @@ + + + + spring-boot + com.git.hui.boot + 0.0.1-SNAPSHOT + + 4.0.0 + + 002-properties-value + + + \ No newline at end of file diff --git a/spring-boot/002-properties-value/src/main/java/com/git/hui/boot/properties/value/Application.java b/spring-boot/002-properties-value/src/main/java/com/git/hui/boot/properties/value/Application.java new file mode 100644 index 00000000..bc173ab8 --- /dev/null +++ b/spring-boot/002-properties-value/src/main/java/com/git/hui/boot/properties/value/Application.java @@ -0,0 +1,17 @@ +package com.git.hui.boot.properties.value; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * @author yihui + * @date 2021/6/2 + */ +@SpringBootApplication +public class Application { + + + public static void main(String[] args) { + SpringApplication.run(Application.class); + } +} diff --git a/spring-boot/002-properties-value/src/main/java/com/git/hui/boot/properties/value/AutoConfiguration.java b/spring-boot/002-properties-value/src/main/java/com/git/hui/boot/properties/value/AutoConfiguration.java new file mode 100644 index 00000000..6767674a --- /dev/null +++ b/spring-boot/002-properties-value/src/main/java/com/git/hui/boot/properties/value/AutoConfiguration.java @@ -0,0 +1,52 @@ +package com.git.hui.boot.properties.value; + +import com.git.hui.boot.properties.value.model.Jwt; +import com.git.hui.boot.properties.value.parse.JwtConverter; +import com.git.hui.boot.properties.value.parse.JwtEditor; +import com.git.hui.boot.properties.value.parse.JwtFormatter; +import org.springframework.beans.factory.config.CustomEditorConfigurer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.support.ConversionServiceFactoryBean; +import org.springframework.format.support.FormattingConversionServiceFactoryBean; + +import java.util.Collections; + +/** + * @author yihui + * @date 2021/6/2 + */ +@Configuration +public class AutoConfiguration { + /** + * 注册自定义的 propertyEditor + * + * @return + */ +// @Bean + public CustomEditorConfigurer editorConfigurer() { + CustomEditorConfigurer editorConfigurer = new CustomEditorConfigurer(); + editorConfigurer.setCustomEditors(Collections.singletonMap(Jwt.class, JwtEditor.class)); + return editorConfigurer; + } + + /** + * 注册自定义的converter + * + * @return + */ + @Bean("conversionService") + public ConversionServiceFactoryBean conversionService() { + ConversionServiceFactoryBean factoryBean = new ConversionServiceFactoryBean(); + factoryBean.setConverters(Collections.singleton(new JwtConverter())); + return factoryBean; + } + +// @Bean("conversionService") + public FormattingConversionServiceFactoryBean conversionService2() { + FormattingConversionServiceFactoryBean factoryBean = new FormattingConversionServiceFactoryBean(); + factoryBean.setConverters(Collections.singleton(new JwtConverter())); + factoryBean.setFormatters(Collections.singleton(new JwtFormatter())); + return factoryBean; + } +} diff --git a/spring-boot/002-properties-value/src/main/java/com/git/hui/boot/properties/value/config/ConfigProperties.java b/spring-boot/002-properties-value/src/main/java/com/git/hui/boot/properties/value/config/ConfigProperties.java new file mode 100644 index 00000000..70f2f2fd --- /dev/null +++ b/spring-boot/002-properties-value/src/main/java/com/git/hui/boot/properties/value/config/ConfigProperties.java @@ -0,0 +1,58 @@ +package com.git.hui.boot.properties.value.config; + +import com.git.hui.boot.properties.value.model.Jwt; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.util.Arrays; +import java.util.List; + +/** + * @author yihui + * @date 2021/6/2 + */ +@Component +public class ConfigProperties { + + @Value("${auth.jwt.token}") + private String token; + + @Value("${auth.jwt.expire}") + private Long expire; + + /** + * 不存在,使用默认值 + */ + @Value("${auth.jwt.no:default_no:111}") + private String no; + + /** + * 英文逗号分隔,转列表 + */ + @Value("${auth.jwt.whiteList}") + private List whiteList; + + /** + * yml数组,无法转换过来,只能根据 "auth.jwt.blackList[0]", "auth.jwt.blackList[1]" 来取对应的值 + */ + @Value("${auth.jwt.blackList:10,11,12}") + private String[] blackList; + + /** + * 借助 PropertyEditor 来实现字符串转对象 + */ + @Value("${auth.jwt.tt}") + private Jwt tt; + + @Autowired + private Environment environment; + + @PostConstruct + public void init() { + System.out.println("token: " + token + "\nexpire:" + expire + "\nno:" + no + "\nwhiteList:" + whiteList + + "\nblackList:" + Arrays.asList(blackList) + "\ntt:" + tt); + } +} diff --git a/spring-boot/002-properties-value/src/main/java/com/git/hui/boot/properties/value/config/MyPropertySourcesPlaceHolderConfigure.java b/spring-boot/002-properties-value/src/main/java/com/git/hui/boot/properties/value/config/MyPropertySourcesPlaceHolderConfigure.java new file mode 100644 index 00000000..07ec56aa --- /dev/null +++ b/spring-boot/002-properties-value/src/main/java/com/git/hui/boot/properties/value/config/MyPropertySourcesPlaceHolderConfigure.java @@ -0,0 +1,80 @@ +package com.git.hui.boot.properties.value.config; + +import lombok.SneakyThrows; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.context.annotation.Primary; +import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; +import org.springframework.core.env.ConfigurablePropertyResolver; +import org.springframework.core.env.Environment; +import org.springframework.core.env.MutablePropertySources; +import org.springframework.core.env.PropertySource; +import org.springframework.lang.Nullable; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Field; + +/** + * @author yihui + * @date 2021/6/2 + */ +@Primary +@Component +public class MyPropertySourcesPlaceHolderConfigure extends PropertySourcesPlaceholderConfigurer { + @Autowired + protected Environment environment; + + /** + * {@code PropertySources} from the given {@link Environment} + * will be searched when replacing ${...} placeholders. + * + * @see #setPropertySources + * @see #postProcessBeanFactory + */ + @Override + public void setEnvironment(Environment environment) { + super.setEnvironment(environment); + this.environment = environment; + } + + @SneakyThrows + @Override + protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, ConfigurablePropertyResolver propertyResolver) throws BeansException { + Field field = propertyResolver.getClass().getDeclaredField("propertySources"); + boolean access = field.isAccessible(); + field.setAccessible(true); + MutablePropertySources propertySource = (MutablePropertySources) field.get(propertyResolver); + field.setAccessible(access); + PropertySource source = new PropertySource(ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME, this.environment) { + @Override + @Nullable + public String getProperty(String key) { + // 对数组进行兼容 + String ans = this.source.getProperty(key); + if (ans != null) { + return ans; + } + + StringBuilder builder = new StringBuilder(); + String prefix = key.contains(":") ? key.substring(key.indexOf(":")) : key; + int i = 0; + while (true) { + String subKey = prefix + "[" + i + "]"; + ans = this.source.getProperty(subKey); + if (ans == null) { + return i == 0 ? null : builder.toString(); + } + + if (i > 0) { + builder.append(","); + } + builder.append(ans); + ++i; + } + } + }; + propertySource.addLast(source); + super.processProperties(beanFactoryToProcess, propertyResolver); + } +} diff --git a/spring-boot/002-properties-value/src/main/java/com/git/hui/boot/properties/value/model/Jwt.java b/spring-boot/002-properties-value/src/main/java/com/git/hui/boot/properties/value/model/Jwt.java new file mode 100644 index 00000000..34a8020f --- /dev/null +++ b/spring-boot/002-properties-value/src/main/java/com/git/hui/boot/properties/value/model/Jwt.java @@ -0,0 +1,35 @@ +package com.git.hui.boot.properties.value.model; + +import lombok.Data; +import org.springframework.util.StringUtils; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author yihui + * @date 2021/6/2 + */ +@Data +public class Jwt { + private String source; + private String token; + private Long expire; + + public static Jwt parse(String text, String source) { + String[] kvs = StringUtils.split(text, ";"); + Map map = new HashMap<>(8); + for (String kv : kvs) { + String[] items = StringUtils.split(kv, ":"); + if (items.length != 2) { + continue; + } + map.put(items[0].trim().toLowerCase(), items[1].trim()); + } + Jwt jwt = new Jwt(); + jwt.setSource(source); + jwt.setToken(map.get("token")); + jwt.setExpire(Long.valueOf(map.getOrDefault("expire", "0"))); + return jwt; + } +} diff --git a/spring-boot/002-properties-value/src/main/java/com/git/hui/boot/properties/value/parse/JwtConverter.java b/spring-boot/002-properties-value/src/main/java/com/git/hui/boot/properties/value/parse/JwtConverter.java new file mode 100644 index 00000000..b9e70342 --- /dev/null +++ b/spring-boot/002-properties-value/src/main/java/com/git/hui/boot/properties/value/parse/JwtConverter.java @@ -0,0 +1,17 @@ +package com.git.hui.boot.properties.value.parse; + +import com.git.hui.boot.properties.value.model.Jwt; +import org.springframework.core.convert.converter.Converter; + +/** + * convert 优先级大于 propertyEditor + * + * @author yihui + * @date 2021/6/2 + */ +public class JwtConverter implements Converter { + @Override + public Jwt convert(String s) { + return Jwt.parse(s, "JwtConverter"); + } +} diff --git a/spring-boot/002-properties-value/src/main/java/com/git/hui/boot/properties/value/parse/JwtEditor.java b/spring-boot/002-properties-value/src/main/java/com/git/hui/boot/properties/value/parse/JwtEditor.java new file mode 100644 index 00000000..6bfd5afd --- /dev/null +++ b/spring-boot/002-properties-value/src/main/java/com/git/hui/boot/properties/value/parse/JwtEditor.java @@ -0,0 +1,18 @@ +package com.git.hui.boot.properties.value.parse; + +import com.git.hui.boot.properties.value.model.Jwt; + +import java.beans.PropertyEditorSupport; + +/** + * 当Editor 与 PODO 放在同一个包路径下时,不需要主动注册,就会被Spring识别到 + * + * @author yihui + * @date 2021/6/2 + */ +public class JwtEditor extends PropertyEditorSupport { + @Override + public void setAsText(String text) throws IllegalArgumentException { + setValue(Jwt.parse(text, "JwtEditor")); + } +} diff --git a/spring-boot/002-properties-value/src/main/java/com/git/hui/boot/properties/value/parse/JwtFormatter.java b/spring-boot/002-properties-value/src/main/java/com/git/hui/boot/properties/value/parse/JwtFormatter.java new file mode 100644 index 00000000..4deef588 --- /dev/null +++ b/spring-boot/002-properties-value/src/main/java/com/git/hui/boot/properties/value/parse/JwtFormatter.java @@ -0,0 +1,24 @@ +package com.git.hui.boot.properties.value.parse; + +import com.alibaba.fastjson.JSONObject; +import com.git.hui.boot.properties.value.model.Jwt; +import org.springframework.format.Formatter; + +import java.text.ParseException; +import java.util.Locale; + +/** + * @author yihui + * @date 2021/6/2 + */ +public class JwtFormatter implements Formatter { + @Override + public Jwt parse(String text, Locale locale) throws ParseException { + return Jwt.parse(text, "JwtFormatter"); + } + + @Override + public String print(Jwt object, Locale locale) { + return JSONObject.toJSONString(object); + } +} diff --git a/spring-boot/002-properties-value/src/main/resources/application.yml b/spring-boot/002-properties-value/src/main/resources/application.yml new file mode 100644 index 00000000..f5eb2265 --- /dev/null +++ b/spring-boot/002-properties-value/src/main/resources/application.yml @@ -0,0 +1,10 @@ +auth: + jwt: + token: TOKEN.123 + expire: 1622616886456 + whiteList: 4,5,6 + blackList: + - 100 + - 200 + - 300 + tt: token:tt_token; expire:1622616888888 \ No newline at end of file diff --git a/spring-boot/pom.xml b/spring-boot/pom.xml index e809624f..91adb9c7 100644 --- a/spring-boot/pom.xml +++ b/spring-boot/pom.xml @@ -108,6 +108,7 @@ 411-zookeeper-distributelock 420-prometheus-basic 150-i18n + 002-properties-value