# extensions-message-source-spring-boot-starter **Repository Path**: liuyangbox/extensions-message-source-spring-boot-starter ## Basic Information - **Project Name**: extensions-message-source-spring-boot-starter - **Description**: 对Spring MessageSource的再扩展,支持从数据库加载messages映射关系,也可扩展自定义的方式 - **Primary Language**: Java - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2020-09-21 - **Last Updated**: 2022-11-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # extensions-message-source-spring-boot-starter > 扩展国际化消息配置 [TOC] ## 1介绍 对Spring MessageSource的再扩展,比如数据库加载messages映射关系,也可扩展自定义的方式。 可达到的目的 ### 1.1国际化消息落地 可以将消息统一放置到数据库中管理,或集中管理,不用在一定放到项目`resource/messages`下 ### 1.2扩展国际化消息 项目中可以只放默认的`messages.properties`,国际化的消息文件可通过扩展模式加载 > 例如`messages.properties`默认中文,其他语言类型的放到数据中,随时增加语言类型与调整消息内容 ### 1.3定义国际化消息的优先级 可通过此组件,实现优先使用项目`resource/messages`还是优先从`扩展解析提供者`中获取 > 比如先读取项目本地的国际化文件,不存在则从数据库中读取,也可反之 ## 2start ### 2.1引入`extensions-message-source-spring-boot-starter` ```xml com.zhituanbox extensions-message-source-spring-boot-starter {extensions.message.source.version} ``` ### 2.2配置 可在`application`文件中配置,配置前缀为`spring.messages.extensions` ```properties # 是否开启该扩展,默认为true spring.messages.extensions.enable=true # 扩展模式,默认extensions_then_default spring.messages.extensions.mode=extensions_then_default ``` #### 2.2.1mode ```java /** * 优先扩展然后默认 */ EXTENSIONS_THEN_DEFAULT /** * 优先默认然后扩展 */ DEFAULT_THEN_EXTENSIONS /** * 只使用扩展 */ ONLY_EXTENSIONS /** * 只使用默认 */ ONLY_DEFAULT ``` > 原有的`spring.messages`配置依旧可用 ### 2.3提供解析 实现接口`com.zhituanbox.extensions.core.ExtensionsMessageSourceResolveCodeProvider` ```java @FunctionalInterface public interface ExtensionsMessageSourceResolveCodeProvider { /** * 解析code * @param code code * @param locale 地区 * @return 返回编码对应消息 */ Optional resolveCode(@NotBlank String code, @Nullable Locale locale); } ``` #### 2.3.1解析策略 多个`ExtensionsMessageSourceResolveCodeProvider`按照spring的order排序进行排序 ```java ObjectProvider> extensionsMessageProviders List messageProviders = extensionsMessageProviders.getIfAvailable(); ``` 解析成功后则停止继续解析 > 具体源码在`com.zhituanbox.extensions.core.ExtensionsMessageSource#resolveCode` ### 2.4扩展`Validator`支持`ExtensionsMessageSource` 原有的`Validator`不支持message为MessageSource中的消息,只支持本地目录下`ValidationMessages.properties`文件 > 默认开启 ## 3Demo ### 3.1引入`extensions-message-source-spring-boot-starter` ### 3.2配置`application.properties` ```yaml server.port=9003 # 开启debug日志,方便查看 logging.level.com.zhituanbox.extensions: debug # 是否开启该扩展,默认为true spring.messages.extensions.enable=true # 扩展模式,默认extensions_then_default spring.messages.extensions.mode=extensions_then_default ``` ### 3.3启动类增加测试`controller` ```java @Validated @SpringBootApplication @RestController public class DemoOneApplication { public static void main(String[] args) { SpringApplication.run(DemoOneApplication.class, args); } @Lazy @Autowired private MessageSource messageSource; @GetMapping("message") public String getMessage(@NotBlank(message = "{demo.zhituanbox.test}") @RequestParam(value = "code",required = false) String code) { return messageSource.getMessage(code, new Object[0], Locale.ENGLISH); } } ``` ### 3.4创建`ExtensionsMessageSourceResolveCodeProvider` bean ```java @Component public class RandomExtensionsMessageProvider implements ExtensionsMessageSourceResolveCodeProvider { private final Logger log = LoggerFactory.getLogger(RandomExtensionsMessageProvider.class); @Override public Optional resolveCode(@NotBlank String code, Locale locale) { boolean b = new Random().nextBoolean(); if (b) { log.info("使用扩展消息"); return Optional.of("扩展" + Optional.ofNullable(locale).map(Locale::toString).orElse("") + "消息"); } return Optional.empty(); } } ``` > 此处随机解析code ### 3.5创建messages文件 在目录`resources`创建文件`messages.properties`、`messages_en.properties` **messages.properties** ```properties demo.zhituanbox.test=文件中文消息 ``` **messages_en.properties** ```properties demo.zhituanbox.test=file english message ``` ### 3.6启动项目 日志如下 ```verilog . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.3.3.RELEASE) 2020-09-22 18:58:48.222 INFO 13928 --- [ main] com.zy.demo.one.DemoOneApplication : Starting DemoOneApplication on PC-HAND-196 with PID 13928 (D:\code\idea-projects\demo\demo-one\target\classes started by hand-196 in D:\code\idea-projects\demo) 2020-09-22 18:58:48.231 INFO 13928 --- [ main] com.zy.demo.one.DemoOneApplication : No active profile set, falling back to default profiles: default 2020-09-22 18:58:49.712 INFO 13928 --- [ main] ExtensionsMessageSourceAutoConfiguration : ExtensionsMessageSource loading 2020-09-22 18:58:49.765 INFO 13928 --- [ main] ExtensionsMessageSourceAutoConfiguration : MessageSource load mode is DEFAULT_THEN_EXTENSIONS(优先默认然后扩展) 2020-09-22 18:58:50.205 INFO 13928 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 9003 (http) 2020-09-22 18:58:50.221 INFO 13928 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2020-09-22 18:58:50.221 INFO 13928 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.37] 2020-09-22 18:58:50.438 INFO 13928 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2020-09-22 18:58:50.439 INFO 13928 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2078 ms 2020-09-22 18:58:50.573 INFO 13928 --- [ main] z.e.ExtensionsValidatorAutoConfiguration : Validator mode is DEFAULT_THEN_EXTENSIONS(优先默认然后扩展) 2020-09-22 18:58:50.778 INFO 13928 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2020-09-22 18:58:51.271 INFO 13928 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 9003 (http) with context path '' 2020-09-22 18:58:51.289 INFO 13928 --- [ main] com.zy.demo.one.DemoOneApplication : Started DemoOneApplication in 4.367 seconds (JVM running for 10.097) ``` ### 3.7测试 **访问接口`localhost:9003/message?code=demo.zhituanbox.test`** #### 3.7.1读取的message_en.properties 返回 ``` file english message ``` 日志 ```verilog 2020-09-22 19:52:26.025 DEBUG 29848 --- [nio-9003-exec-2] c.z.e.core.ExtensionsMessageSource : ExtensionsMessageSourceResolveCodeProvider: find impl [RandomExtensionsMessageProvider] 2020-09-22 19:52:26.025 DEBUG 29848 --- [nio-9003-exec-2] c.z.e.core.ExtensionsMessageSource : RandomExtensionsMessageProvider.resolveCode(demo.zhituanbox.test,en) result is empty ``` #### 3.7.2读取的`RandomExtensionsMessageProvider` 返回 ``` 扩展en消息 ``` 日志 ```verilog ExtensionsMessageSourceResolveCodeProvider: find impl [RandomExtensionsMessageProvider] 2020-09-22 19:57:20.137 INFO 29848 --- [nio-9003-exec-7] c.z.d.o.RandomExtensionsMessageProvider : 使用扩展消息 2020-09-22 19:57:20.138 DEBUG 29848 --- [nio-9003-exec-7] c.z.e.core.ExtensionsMessageSource : RandomExtensionsMessageProvider.resolveCode(demo.zhituanbox.test,en) result is [扩展en消息] ``` **访问接口`localhost:9003/message`** #### 3.7.3读取的message.properties 日志 ```verilog ExtensionsMessageSourceResolveCodeProvider: find impl [RandomExtensionsMessageProvider] 2020-09-22 20:00:55.977 DEBUG 29848 --- [nio-9003-exec-4] c.z.e.core.ExtensionsMessageSource : RandomExtensionsMessageProvider.resolveCode(demo.zhituanbox.test,zh_CN) result is empty 2020-09-22 20:00:55.980 ERROR 29848 --- [nio-9003-exec-4] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is javax.validation.ConstraintViolationException: getMessage.code: 文件中文消息] with root cause javax.validation.ConstraintViolationException: getMessage.code: 文件中文消息 at org.springframework.validation.beanvalidation.MethodValidationInterceptor.invoke(MethodValidationInterceptor.java:116) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.8.RELEASE.jar:5.2.8.RELEASE] ``` > 因为`@NotBlank(message = "{demo.zhituanbox.test}")`中使用的默认时区 #### 3.7.4读取的`RandomExtensionsMessageProvider` 日志 ```verilog 使用扩展消息 2020-09-22 20:00:14.815 DEBUG 29848 --- [io-9003-exec-10] c.z.e.core.ExtensionsMessageSource : RandomExtensionsMessageProvider.resolveCode(demo.zhituanbox.test,zh_CN) result is [扩展zh_CN消息] 2020-09-22 20:00:14.836 ERROR 29848 --- [io-9003-exec-10] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is javax.validation.ConstraintViolationException: getMessage.code: 扩展zh_CN消息] with root cause javax.validation.ConstraintViolationException: getMessage.code: 扩展zh_CN消息 at org.springframework.validation.beanvalidation.MethodValidationInterceptor.invoke(MethodValidationInterceptor.java:116) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.8.RELEASE.jar:5.2.8.RELEASE] ```