12. SpringBoot国际化

1)、编写国际化配置文件;

2)、使用ResourceBundleMessageSource管理国际化资源文件

3)、在页面使用fmt:message取出国际化内容  


步骤
1)、编写国际化配置文件,抽取页面需要显示的国际化消息

 

 

 

国际化文件是peroperties文件  

 

 

 自动识别国际化视图

 

 通过国际化视图创建国际化配置文件

 

 

 同时对比编辑多个配置文件

 

 

 

 

 配置国际化文件路径:

spring.messages.basename=static.i18n.login

 

 

 

 

@Configuration
@ConditionalOnMissingBean(
    value = {MessageSource.class},
    search = SearchStrategy.CURRENT
)
@AutoConfigureOrder(-2147483648)
@Conditional({MessageSourceAutoConfiguration.ResourceBundleCondition.class})
@EnableConfigurationProperties
public class MessageSourceAutoConfiguration {
    private static final Resource[] NO_RESOURCES = new Resource[0];

    public MessageSourceAutoConfiguration() {
    }

    @Bean
    @ConfigurationProperties(
        prefix = "spring.messages"
    )
    public MessageSourceProperties messageSourceProperties() {
        return new MessageSourceProperties();
    }

    @Bean
    public MessageSource messageSource(MessageSourceProperties properties) {
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
        if (StringUtils.hasText(properties.getBasename())) {
       //设置国际化文件的基础名称(去掉语言_国家代{zh_CN})的):即默认是message.properties,上图中我们起的名称是login.properties messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(properties.getBasename()))); }
if (properties.getEncoding() != null) { messageSource.setDefaultEncoding(properties.getEncoding().name()); } messageSource.setFallbackToSystemLocale(properties.isFallbackToSystemLocale()); Duration cacheDuration = properties.getCacheDuration(); if (cacheDuration != null) { messageSource.setCacheMillis(cacheDuration.toMillis()); } messageSource.setAlwaysUseMessageFormat(properties.isAlwaysUseMessageFormat()); messageSource.setUseCodeAsDefaultMessage(properties.isUseCodeAsDefaultMessage()); return messageSource; } protected static class ResourceBundleCondition extends SpringBootCondition { private static ConcurrentReferenceHashMap<String, ConditionOutcome> cache = new ConcurrentReferenceHashMap(); protected ResourceBundleCondition() { } public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
       //自定义的话就用此属性:spring.messages.basename来指定,默认叫message.propertie
       //我们上图的需要指定为:spring.messages.basename=login String basename
= context.getEnvironment().getProperty("spring.messages.basename", "messages"); ConditionOutcome outcome = (ConditionOutcome)cache.get(basename); if (outcome == null) { outcome = this.getMatchOutcomeForBasename(context, basename); cache.put(basename, outcome); } return outcome; } private ConditionOutcome getMatchOutcomeForBasename(ConditionContext context, String basename) { Builder message = ConditionMessage.forCondition("ResourceBundle", new Object[0]); String[] var4 = StringUtils.commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(basename)); int var5 = var4.length; for(int var6 = 0; var6 < var5; ++var6) { String name = var4[var6]; Resource[] var8 = this.getResources(context.getClassLoader(), name);//类路径 int var9 = var8.length; for(int var10 = 0; var10 < var9; ++var10) { Resource resource = var8[var10]; if (resource.exists()) { return ConditionOutcome.match(message.found("bundle").items(new Object[]{resource})); } } } return ConditionOutcome.noMatch(message.didNotFind("bundle with basename " + basename).atAll()); } private Resource[] getResources(ClassLoader classLoader, String name) { String target = name.replace('.', '/'); try {
          //类路径下的 message.properties 和 messages_zh_CN.properties 或 自己指定的xxxx.properties 、xxxx.preperties
return (new PathMatchingResourcePatternResolver(classLoader)).getResources("classpath*:" + target + ".properties"); } catch (Exception var5) { return MessageSourceAutoConfiguration.NO_RESOURCES; } } } }

 

 

 

public class MessageSourceProperties {
    private String basename = "messages";//我们的配置文件可以直接放在类路径下,默认名称叫message.properties
    private Charset encoding;
    @DurationUnit(ChronoUnit.SECONDS)
    private Duration cacheDuration;
    private boolean fallbackToSystemLocale;
    private boolean alwaysUseMessageFormat;
    private boolean useCodeAsDefaultMessage;

    public MessageSourceProperties() {
        this.encoding = StandardCharsets.UTF_8;
        this.fallbackToSystemLocale = true;
        this.alwaysUseMessageFormat = false;
        this.useCodeAsDefaultMessage = false;
    }

    public String getBasename() {
        return this.basename;
    }

    public void setBasename(String basename) {
        this.basename = basename;
    }
......
}

 

 

 

 

 

 <!-- 中英文切换链接 -->

<a class="btn btn-sm" th:href="@{/index.html(l='zh_CN'}">中文</a>
<a class="btn btn-sm" th:href="@{/index.html(l='en_US')}">English</a>

 

 

 

 是根据浏览器的默认语言识别的

 

 

 

 不过取出来的中文有乱码

 

 

 IDEA中将UTF-8自动组转为ASSIC码

  

 

 

 File   ——》 settings 里的设置只是针对当前项目的设置,要想设置全局的

 

 

 

 

 Settins  ——》Other Settings ——》Default Settings  设置全局的默认设置

 

然后重新编辑有乱码的properties文件

 根据浏览器的默认语言设置自动区分国际化字段的显示

 

 

 默认请求头里会有语言的信息

 

 

 

 切换默认的语言,请求头中排在第一位的也就变了

 

 

 

实现原理:

国际化Locale(区域信息对象);LocaleResolver(获取区域信息对象)

public class WebMvcAutoConfiguration {
    public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ResourceLoaderAware {


        @Bean
        @ConditionalOnMissingBean  //当项目中没有区域解析器的时候,才执行这个SprigBoot默认的配置,所以可以自定义
        @ConditionalOnProperty(
                prefix = "spring.mvc",
                name = {"locale"}
        )
        //
        public LocaleResolver localeResolver() {


            //默认从配置文件中获取
            if (this.mvcProperties.getLocaleResolver() == org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties.LocaleResolver.FIXED) {
                return new FixedLocaleResolver(this.mvcProperties.getLocale());
            } else {//如果配置文件中没有,则从HttpRequest的header中获取
                AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
                localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
                return localeResolver;
            }
        }

    }



    public class AcceptHeaderLocaleResolver implements LocaleResolver {

        public Locale resolveLocale(HttpServletRequest request) {
            Locale defaultLocale = this.getDefaultLocale();
            if (defaultLocale != null && request.getHeader("Accept-Language") == null) {
                return defaultLocale;
            } else {
                Locale requestLocale = request.getLocale();
                List<Locale> supportedLocales = this.getSupportedLocales();
                if (!supportedLocales.isEmpty() && !supportedLocales.contains(requestLocale)) {
                    Locale supportedLocale = this.findSupportedLocale(request, supportedLocales);
                    if (supportedLocale != null) {
                        return supportedLocale;
                    } else {//如果默认的区域解析器为空,则从requset请求头中获取
                        return defaultLocale != null ? defaultLocale : requestLocale;
                    }
                } else {
                    return requestLocale;
                }
            }
        }

    }

 

自定义区域解析器,点击链接切换国际化

public class MyLocaleResolver implements LocaleResolver {
    @Override
    public Locale resolveLocale(HttpServletRequest request) {
        String l = request.getParameter("l");
        Locale locale = Locale.getDefault();         
        if (!StringUtils.isEmpty(l)) {             
            String[] split = l.split("_");             
            locale = new Locale(split[0], split[1]);        
        }        
        return locale;
    }

    @Override
    public void setLocale(HttpServletRequest httpServletRequest, @Nullable HttpServletResponse httpServletResponse, @Nullable Locale locale) {

    }
}

 

//将自定义的区域解析器加入到容器中来
@Bean     
public LocaleResolver localeResolver(){         
    return new MyLocaleResolver();     
} 

 

posted @ 2018-11-19 10:33  超轶绝尘  阅读(2267)  评论(0编辑  收藏  举报