java 国际化 配置文件_spring国际化properties文件配置在数据库中

1.spring为java项目提供国际化支持

message_zh_CN.properties(中文简体)

message_en_US.properties(美国英文)

等等中配置key=value

key可以是错误提示信息,页面显示信息等等。

使用配置的配置

@Autowired

private MessageSource messageSource;

messageSource.getMessage(key,null,"default value",Locale.getDefault()); //如果没有配置,会返回默认值

messageSource.getMessage(key,null,Locale.getDefault()); //如果没有配置会抛出异常

String getMessage(String code, Object[] args, String defaultMessage, Locale locale);

String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException;

2.上述使用缺点

上述国际化使用适合做小型的web项目,配置key不多,或者项目的使用国家或地区很少。

如果配置项非常多的话,那么properties文件将会非常大,而且配置项非常多。如果支持全世界所有国家和地区时,那么就要有许多个properties文件,能够使用,但相对比较麻烦。

针对上述缺点,能否将上述的配置key及value写入数据中了?

3.具体解决方案

在数据库中定义表,表中基础字段国家或地区代表符号,如zh_CN(简体中文),en_US(美国英语)等,key及value,然后再增加一个basename,这个字段是参考spring源码做的,下面详细讲解。

创建sql

CREATE TABLE t_messages (

`basename` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,

`locale_lang` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,

`k` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,

`v` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL

) ;

basename基础文件目录

locale_lan国家或地区代表符号

k key值

v value值

a方案

对待该表就想对待普通的业务表,针对该表建立MessageMapper文件,创建针对该表的增删改查方法,在service层控制事务管理及缓存等等,当任何一个controller需要国际化返回结果的时候,就可以通过调MessageService方法来得到对应的value.

此处mapper里面的方法仅仅是举例,详细的可根据项目需求自己修改

@Mapper

public interface MessageMapper {

String columnList = " basename,locale_lan,k,v ";

@Insert("insert into t_message(" +columnList+") values(#{basename},#{locale_lan},#{k},#{v})")

boolean insertMessage(Message message);

@Select("select " + columnList + "from t_message where basename = #{basename} and locale_lan = #{language}")

AddressEntity getMessage(String basename,String language);

}

b方案

a方案是一种实现方法,但是spring既然已经实现properties文件的具体用法,对spring进行二次开发,开发适合自己项目的业务,岂不是更好吗?

spring 实现国际化源码简单分析

MessageSource接口

public interface MessageSource {

String getMessage(String code, Object[] args, String defaultMessage, Locale locale);

String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException;

String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;

}

HierarchicalMessageSource接口

其继承了MessageSource接口,增加了父MessageSource的设置方法

public interface HierarchicalMessageSource extends MessageSource {

void setParentMessageSource(MessageSource parent);

MessageSource getParentMessageSource();

}

DelegatingMessageSource类

该类主要是委派父MessageSource处理getMessage();

public class DelegatingMessageSource extends MessageSourceSupport implements HierarchicalMessageSource;

@Override

public String getMessage(String code, Object[] args, String defaultMessage, Locale locale) {

if (this.parentMessageSource != null) {

return **this.parentMessageSource.getMessage(code, args, defaultMessage, locale);**

}

else {

**return renderDefaultMessage(defaultMessage, args, locale);**

}

}

@Override

public String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException {

if (this.parentMessageSource != null) {

**return this.parentMessageSource.getMessage(code, args, locale);**

}

else {

throw new NoSuchMessageException(code, locale);

}

}

@Override

public String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException {

if (this.parentMessageSource != null) {

**return this.parentMessageSource.getMessage(resolvable, locale);**

}

else {

if (resolvable.getDefaultMessage() != null) {

**return renderDefaultMessage(resolvable.getDefaultMessage(), resolvable.getArguments(), locale);**

}

String[] codes = resolvable.getCodes();

String code = (codes != null && codes.length > 0 ? codes[0] : null);

throw new NoSuchMessageException(code, locale);

}

}

MessageSourceSupport 该类为获取字符串后的格式化处理的类

private final Map> messageFormatsPerMessage = new HashMap();

格式化存储的结构类型,大Map的key为basename,嵌套的Map,key为Locale,value为MessageFormat,不同地区可以设置不同的格式化样式

核心方法:return messageFormat.format(this.resolveArguments(code, locale));

this.resolveArguments(code, locale)方法获取对应的value

AbstractMessageSource为MessageSource接口的核心实现类

核心方法的实现方法都是final的,不允许重写

public final String getMessage(String code, Object[] args, String defaultMessage, Locale locale) ;

public final String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException;

AbstractResourceBasedMessageSource继承了AbstractMessageSource类

AbstractResourceBasedMessageSource的实现类有

1.ResourceBundleMessageSource

2.ReloadableResourceBundleMessageSource

3.ReloadableResourceBundleMessageSource

关注的主要是ResourceBundleMessageSource类

当调用ResourceBundleMessageSource 对象的getMessage()方法时候

其会调用其的protected ResourceBundle doGetBundle(String basename, Locale locale) throws MissingResourceException {

return ResourceBundle.getBundle(basename, locale, this.getBundleClassLoader(), new ResourceBundleMessageSource.MessageSourceControl());

}方法,所以重写该方法可以实现自我配置的类。

b方案具体实现,具体的查库方法没有贴出来

public class DatabaseAndResourceBundleMessageSource

extends ResourceBundleMessageSource {

private static final Logger log = LoggerFactory.getLogger(DatabaseAndResourceBundleMessageSource2.class);

@Autowired

DataSource dataSource;

@Autowired

MessageDBHandler databaseMessageHandler;

@Override

protected ResourceBundle doGetBundle(String basename, Locale locale) throws MissingResourceException {

try {

ResourceBundle delegate = super.doGetBundle(basename, locale);//父类MessageSource实现

return new ResourceBundle() {

@Override

protected Object handleGetObject(String key) {

return Optional.ofNullable(databaseMessageHandler.loadMessageFromDb(basename, locale.getLanguage(), key)).orElseGet(() -> delegate.getObject(key)); //依据key获取value

}

@Override

public Enumeration getKeys() {

log.info("getKeys");

Set l = databaseMessageHandler.loadKeysFromDb(basename, locale.getLanguage());

l.addAll(delegate.keySet());

return Collections.enumeration(l);

}

};

} catch (MissingResourceException e) {

return new ResourceBundle() {

@Override

protected Object handleGetObject(String key) {

return databaseMessageHandler.loadMessageFromDb(basename, locale.getLanguage(), key);

}

@Override

public Enumeration getKeys() {

return Collections.enumeration(databaseMessageHandler.loadKeysFromDb(basename, locale.getLanguage())); //获取同一basename和language下的所有keys

}

};

}

}

}

@Configuration

public class MessageConfig {

@Value("message.basename:app/notice,app/mail")

private String[] baseNames;

private Logger logger = LoggerFactory.getLogger(this.getClass());

@Bean("messageSource")

public MessageSource myMessageSource(){

ResourceBundleMessageSource messageSource = new DatabaseAndResourceBundleMessageSource();

messageSource.setBasenames(baseNames);

return messageSource;

}

}

上述描述了一大堆,不好理解,下面的方便理解

spring解析properties文件使用的是Map>数据结构,ResourceBundle类中有Set set = new HashSet<>();

这个set就是封装properties中对应的key-value,在ResourceBundleMessageSource对象中doGetBundle()方法中就是获取ResourceBundle对象的,所以重写doGetBundle()方法,就可以将数据库中的key-value加入到已经存在的key-value中了。如果仅仅以语言进行区别,可以使用Locale.getDefault().getLanguage()即可,如果想以国家和地区来区分就可以使用Locale.getDefault().toString(),两者是有区别的。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【2021年,将Spring全家桶的课程进行Review,确保不再有课程的顺序错乱,从而导致学员看不懂。进入2022年,将Spring的课程进行整理,整理为案例精讲的系列课程,并开始加入高阶Spring Security等内容,一步步手把手教你从零开始学会应用Spring,课件将逐步进行上传,敬请期待!】 本课程是Spring全家桶系列课程的第三部分Spring Boot,Spring案例精讲课程以真实场景、项目实战为导向,循序渐进,深入浅出的讲解Java网络编程,助力您在技术工作更进一步。 本课程聚焦Spring Boot核心知识点:整合Web(如:JSP、Thymeleaf、freemarker等的整合)的开发、全局异常处理、配置文件配置访问、多环境的配置文件设置、日志Logback及slf4j的使用、国际化设置及使用, 并在最后以一个贯穿前后台的Spring Boot整合Mybatis的案例为终奖,使大家快速掌握Spring的核心知识,快速上手,为面试、工作都做好充足的准备。 由于本课程聚焦于案例,即直接上手操作,对于Spring的原理等不会做过多介绍,希望了解原理等内容的需要通过其他视频或者书籍去了解,建议按照该案例课程一步步做下来,之后再去进一步回顾原理,这样能够促进大家对原理有更好的理解。 【通过Spring全家桶,我们保证你能收获到以下几点】 1、掌握Spring全家桶主要部分的开发、实现2、可以使用Spring MVC、Spring Boot、Spring Cloud及Spring Data进行大部分的Spring开发3、初步了解使用微服务、了解使用Spring进行微服务的设计实现4、奠定扎实的Spring技术,具备了一定的独立开发的能力  【实力讲师】 毕业于清华大学软件学院软件工程专业,曾在Accenture、IBM等知名外企任管理及架构职位,近15年的JavaEE经验,近8年的Spring经验,一直致力于架构、设计、开发及管理工作,在电商、零售、制造业等有丰富的项目实施经验  【本课程适用人群】如果你是一定不要错过!  适合于有JavaEE基础的,如:JSP、JSTL、Java基础等的学习者没有基础的学习者跟着课程可以学习,但是需要补充相关基础知识后,才能很好的参与到相关的工作。 【Spring全家桶课程共包含如下几门】 

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值