Spring MVC中使用MessageSource默认是写在properties文件当中,以支持国际化。

但很多时候我们需要把数据写到数据库当中,而不是在properties文件当中,以方便日常维护。

1、先看Spring配置

  1. <!-- 默认的注解映射的支持 -->
  2. <mvc:annotation-driven validator="validator" conversion-service="conversionService" />
  3.  
  4. <!-- 资源文件 -->
  5. <bean id="propertiesMessageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
  6. <property name="basenames">
  7. <list>
  8. <value>resource</value>
  9. <value>validation</value>
  10. </list>
  11. </property>
  12. </bean>
  13. <bean id="databaseMessageSource" class="com.obs2.util.MessageResource">
  14. <property name="parentMessageSource" ref="propertiesMessageSource"/>
  15. </bean>
  16. <bean id="messageInterpolator" class="com.obs2.util.MessageResourceInterpolator">
  17. <property name="messageResource" ref="databaseMessageSource"/>
  18. </bean>
  19. <!-- 验证器 -->
  20. <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
  21. <property name="messageInterpolator" ref="messageInterpolator"/>
  22. </bean>

这里定义了一个propertiesMessageSource,一个databaseMessageSourcer,和一个messageInterpolator。

propertiesMessageSource用于读取properties文件

databaseMessageSourcer用于读取数据库的数据配置,其中,有一个属性设置它的父MessageSource为propertiesMessageSource。意思是如果数据库找不到对应的数据,到properties文件当中查找。

messageInterpolator是个拦截器。

2、数据库的POJO定义:

  1. package com.obs2.dao.impl.bean;
  2.  
  3. import java.io.Serializable;
  4.  
  5. import javax.persistence.Column;
  6. import javax.persistence.Entity;
  7. import javax.persistence.GeneratedValue;
  8. import javax.persistence.GenerationType;
  9. import javax.persistence.Id;
  10. import javax.persistence.Table;
  11.  
  12. @Entity
  13. @SuppressWarnings("serial")
  14. @Table(name="resource")
  15. public class Resource implements Serializable {
  16.  
  17. @Id
  18. @GeneratedValue(strategy=GenerationType.IDENTITY)
  19. @Column(name="resource_id")
  20. private long resourceId;
  21.  
  22. @Column(name="name", length=50, nullable=false)
  23. private String name;
  24.  
  25. @Column(name="text", length=1000, nullable=false)
  26. private String text;
  27.  
  28. @Column(name="language", length=5, nullable=false)
  29. private String language;
  30.  
  31. public long getResourceId() {
  32. return resourceId;
  33. }
  34. public void setResourceId(long resourceId) {
  35. this.resourceId = resourceId;
  36. }
  37. public String getName() {
  38. return name;
  39. }
  40. public void setName(String name) {
  41. this.name = name;
  42. }
  43. public String getText() {
  44. return text;
  45. }
  46. public void setText(String text) {
  47. this.text = text;
  48. }
  49. public String getLanguage() {
  50. return language;
  51. }
  52. public void setLanguage(String language) {
  53. this.language = language;
  54. }
  55.  
  56. }

定义了一张表[resource],字段有:[resource_id]、[name]、[text]、[language]

具体的DAO、Service操作方法这里忽略不写了。

3、读取数据库的MessageResource类

  1. package com.obs2.util;
  2.  
  3. import java.text.MessageFormat;
  4. import java.util.HashMap;
  5. import java.util.List;
  6. import java.util.Locale;
  7. import java.util.Map;
  8.  
  9. import javax.annotation.Resource;
  10.  
  11. import org.springframework.context.ResourceLoaderAware;
  12. import org.springframework.context.support.AbstractMessageSource;
  13. import org.springframework.core.io.DefaultResourceLoader;
  14. import org.springframework.core.io.ResourceLoader;
  15.  
  16. import com.obs2.service.ResourceService;
  17.  
  18. /**
  19. * 取得资源数据
  20. * @author Robin
  21. *
  22. */
  23. public class MessageResource extends AbstractMessageSource implements ResourceLoaderAware {
  24.  
  25. @SuppressWarnings("unused")
  26. private ResourceLoader resourceLoader;
  27.  
  28. @Resource
  29. private ResourceService resourceService;
  30.  
  31. /**
  32. * Map切分字符
  33. */
  34. protected final String MAP_SPLIT_CODE = "|";
  35.  
  36. protected final String DB_SPLIT_CODE = "_";
  37.  
  38. private final Map<String, String> properties = new HashMap<String, String>();
  39.  
  40. public MessageResource() {
  41. // reload();
  42. }
  43.  
  44. public void reload() {
  45. properties.clear();
  46. properties.putAll(loadTexts());
  47. }
  48.  
  49. protected Map<String, String> loadTexts() {
  50. Map<String, String> mapResource = new HashMap<String, String>();
  51. List<com.obs2.service.bean.Resource> resources = resourceService.findAll();
  52. for (com.obs2.service.bean.Resource item : resources) {
  53. String code = item.getName() + MAP_SPLIT_CODE + item.getLanguage();
  54. mapResource.put(code, item.getText());
  55. }
  56. return mapResource;
  57. }
  58.  
  59. private String getText(String code, Locale locale) {
  60. String localeCode = locale.getLanguage() + DB_SPLIT_CODE + locale.getCountry();
  61. String key = code + MAP_SPLIT_CODE + localeCode;
  62. String localeText = properties.get(key);
  63. String resourceText = code;
  64.  
  65. if(localeText != null) {
  66. resourceText = localeText;
  67. }
  68. else {
  69. localeCode = Locale.ENGLISH.getLanguage();
  70. key = code + MAP_SPLIT_CODE + localeCode;
  71. localeText = properties.get(key);
  72. if(localeText != null) {
  73. resourceText = localeText;
  74. }
  75. else {
  76. try {
  77. if(getParentMessageSource() != null) {
  78. resourceText = getParentMessageSource().getMessage(code, null, locale);
  79. }
  80. } catch (Exception e) {
  81. logger.error("Cannot find message with code: " + code);
  82. }
  83. }
  84. }
  85. return resourceText;
  86. }
  87.  
  88. @Override
  89. public void setResourceLoader(ResourceLoader resourceLoader) {
  90. this.resourceLoader = (resourceLoader != null ? resourceLoader : new DefaultResourceLoader());
  91. }
  92.  
  93. @Override
  94. protected MessageFormat resolveCode(String code, Locale locale) {
  95. String msg = getText(code, locale);
  96. MessageFormat result = createMessageFormat(msg, locale);
  97. return result;
  98. }
  99.  
  100. @Override
  101. protected String resolveCodeWithoutArguments(String code, Locale locale) {
  102. String result = getText(code, locale);
  103. return result;
  104. }
  105.  
  106. }

主要是重载AbstractMessageSource和ResourceLoaderAware,以实现Spring MVC的MessageSource国际化调用。

类中的reload()方法,我把它写到了一个ServletListener当中,让项目启动时,自动加载数据到static的map中。

4、这是Listener:

  1. package com.obs2.util;
  2.  
  3. import javax.servlet.ServletContext;
  4. import javax.servlet.ServletContextAttributeEvent;
  5. import javax.servlet.ServletContextEvent;
  6. import javax.servlet.ServletContextListener;
  7. import javax.servlet.http.HttpSessionEvent;
  8.  
  9. import org.springframework.web.context.WebApplicationContext;
  10. import org.springframework.web.context.support.WebApplicationContextUtils;
  11.  
  12. /**
  13. * 系统启动监听
  14. * @author Robin
  15. *
  16. */
  17. public class SystemListener implements ServletContextListener {
  18.  
  19. /**
  20. * context初始化时激发
  21. */
  22. @Override
  23. public void contextInitialized(ServletContextEvent e) {
  24. //------------------------------------------------------------
  25. // 取得ServletContext
  26. //------------------------------------------------------------
  27. ServletContext context = e.getServletContext();
  28. WebApplicationContext applicationContext = WebApplicationContextUtils .getWebApplicationContext(context);
  29.  
  30. //------------------------------------------------------------
  31. // 设置国际化多语言
  32. //------------------------------------------------------------
  33. MessageResource messageSource = applicationContext.getBean(MessageResource.class);
  34. messageSource.reload();
  35. }
  36.  
  37. /**
  38. * context删除时激发
  39. */
  40. @Override
  41. public void contextDestroyed(ServletContextEvent e) {
  42. }
  43.  
  44. /**
  45. * 创建一个 session时激发
  46. * @param e
  47. */
  48. public void sessionCreated(HttpSessionEvent e) {
  49. }
  50.  
  51. /**
  52. * 当一个 session失效时激发
  53. * @param e
  54. */
  55. public void sessionDestroyed(HttpSessionEvent e) {
  56. }
  57.  
  58. /**
  59. * 设置 context的属性,它将激发attributeReplaced或attributeAdded方法
  60. * @param e
  61. */
  62. public void setContext(HttpSessionEvent e) {
  63. }
  64.  
  65. /**
  66. * 增加一个新的属性时激发
  67. * @param e
  68. */
  69. public void attributeAdded(ServletContextAttributeEvent e) {
  70. }
  71.  
  72. /**
  73. * 删除一个新的属性时激发
  74. * @param e
  75. */
  76. public void attributeRemoved(ServletContextAttributeEvent e) {
  77. }
  78.  
  79. /**
  80. * 属性被替代时激发
  81. * @param e
  82. */
  83. public void attributeReplaced(ServletContextAttributeEvent e) {
  84. }
  85.  
  86. }

当然了,Listener需要加入到web.xml当中:

  1. <!-- 系统启动监听 -->
  2. <listener>
  3. <listener-class>com.obs2.util.SystemListener</listener-class>
  4. </listener>

4、Interceptor拦截器

  1. package com.obs2.util;
  2.  
  3. import java.text.MessageFormat;
  4. import java.util.Iterator;
  5. import java.util.Locale;
  6. import java.util.Map;
  7. import java.util.Map.Entry;
  8.  
  9. import javax.annotation.Resource;
  10. import javax.validation.MessageInterpolator;
  11.  
  12. import org.springframework.binding.message.MessageBuilder;
  13.  
  14. /**
  15. * 拦截Annotation验证信息
  16. * @author Robin
  17. *
  18. */
  19. public class MessageResourceInterpolator implements MessageInterpolator {
  20.  
  21. @Resource
  22. private MessageResource messageResource;
  23. public void setMessageResource(MessageResource messageResource) {
  24. this.messageResource = messageResource;
  25. }
  26.  
  27. @Override
  28. public String interpolate(String messageTemplate, Context context) {
  29.  
  30. String messageTemp = null;
  31. if(messageTemplate.startsWith("{") && messageTemplate.endsWith("}")) {
  32. messageTemp = messageTemplate.substring(1, messageTemplate.length() - 1);
  33. }
  34. else {
  35. return messageTemplate;
  36. }
  37.  
  38. String[] params = (String[]) context.getConstraintDescriptor().getAttributes().get("params");
  39.  
  40. MessageBuilder builder = new MessageBuilder().code(messageTemp);
  41. if (params != null) {
  42. for (String param : params) {
  43. builder = builder.arg(param);
  44. }
  45. }
  46.  
  47. String result = builder.build().resolveMessage(messageResource, Locale.ENGLISH).getText();
  48. return result;
  49. }
  50.  
  51. @Override
  52. public String interpolate(String messageTemplate, Context context, Locale locale) {
  53.  
  54. String messageTemp = null;
  55. if(messageTemplate.startsWith("{") && messageTemplate.endsWith("}")) {
  56. messageTemp = messageTemplate.substring(1, messageTemplate.length() - 1);
  57. }
  58. else {
  59. return messageTemplate;
  60. }
  61.  
  62. String[] params = (String[]) context.getConstraintDescriptor().getAttributes().get("params");
  63.  
  64. MessageBuilder builder = new MessageBuilder().code(messageTemp);
  65. if (params != null) {
  66. builder = builder.args(params);
  67. }
  68.  
  69. String result = builder.build().resolveMessage(messageResource, locale).getText();
  70. return result;
  71. }
  72.  
  73. }

事实上,不使用拦截器,上面的数据库MessageSource类已经可以工作了。但在使用hibernate的Annotation的validator时,不加入拦截器,是不行的,它不会触发。

这类里调用了一个jar包:spring-binding-2.3.1.RELEASE.jar

自行上网搜搜下载。

一切完成,测试下,写一个domain entity:

  1. package com.obs2.controller.bean;
  2.  
  3. import javax.validation.constraints.Min;
  4.  
  5. import org.hibernate.validator.constraints.NotEmpty;
  6.  
  7. import com.obs2.controller.validator.UserName;
  8.  
  9. public class Account {
  10.  
  11. @UserName(format="^[\\w_]+$", message="{valid.userName}", min=6, max=30)
  12. private String userName;
  13. @NotEmpty(message="{valid.required}")
  14. private String password;
  15. @Min(value=18, message="{valid.ageMin}")
  16. private int age;
  17.  
  18. public String getUserName() {
  19. return userName;
  20. }
  21. public void setUserName(String userName) {
  22. this.userName = userName;
  23. }
  24. public String getPassword() {
  25. return password;
  26. }
  27. public void setPassword(String password) {
  28. this.password = password;
  29. }
  30. public int getAge() {
  31. return age;
  32. }
  33. public void setAge(int age) {
  34. this.age = age;
  35. }
  36.  
  37. }

写一个简单的view(这里使用的是freemarker)

  1. <#assign c=JspTaglibs["http://java.sun.com/jsp/jstl/core"] />
  2. <#assign fmt=JspTaglibs["http://java.sun.com/jsp/jstl/fmt"] />
  3. <#assign fn=JspTaglibs["http://java.sun.com/jsp/jstl/functions"] />
  4. <#assign st=JspTaglibs["http://www.springframework.org/tags"] />
  5. <#assign form=JspTaglibs["http://www.springframework.org/tags/form"] />
  6. <head>
  7. <title>Login</title>
  8. </head>
  9.  
  10. <body>
  11. <@form.form action="${request.contextPath}/passport/login" method="post" modelAttribute="account">
  12. User name:<@form.input path="userName"/><@form.errors path="userName"/><br/>
  13. Password:<@form.password path="password"/><@form.errors path="password" /><br/>
  14. Age:<@form.input path="age"/><@form.errors path="age" /><br/>
  15. <input type="submit" value="Login" />
  16. </@form.form>
  17. </body>

将看到:

这种方法还有一个小BUG,就是在使用annotation validator时,如果使用了替换符,似乎不起作用。暂时没研究出来,谁搞出来了,麻烦留个言提示下。so thx.

代码中直接调用,可以这样写:

  1. resource.getMessage("valid.ageMin", new Object[]{"age",18}, request.getLocale())

[Spring MVC] - 从数据库读取MessageSource的更多相关文章

  1. Spring MVC 属性文件读取注入到静态字段

    目录(?)[-] servlet-contextxml configproperties 示例属性 ConfigInfo 对应的配置bean 使用   在项目中,有些参数需要配置到属性文件xxx.pr ...

  2. spring mvc中的service和controller中读取不到properties值

    根据web.xml读取配置文件中的顺序来看 controller层和service层来自于spring mvc.xml中读取,所以必须要在spring mvc.xml中配置读取资源文件夹方式

  3. Spring MVC程序中得到静态资源文件css,js,图片

    转载自:http://www.blogjava.net/fiele/archive/2014/08/24/417283.html 用 Spring MVC 开发应用程序,对于初学者有一个很头疼的问题, ...

  4. Spring MVC程序中得到静态资源文件css,js,图片文件的路径问题总结

    上一篇 | 下一篇 Spring MVC程序中得到静态资源文件css,js,图片 文件的路径 问题总结 作者:轻舞肥羊 日期:2012-11-26 http://www.blogjava.net/fi ...

  5. ssm整合说明与模板-Spring Spring MVC Mybatis整合开发

    ssm整合说明 spring+spring mvc+mybatis 说明 源码下载 由于之前存在ssh框架,spring+struts+hibernate,其中spring负责aop与ioc,所以一般 ...

  6. Spring MVC程序中怎么得到静态资源文件css,js,图片文件的路径问题

    问题描述 在用springmvc开发应用程序的时候.对于像我一样的初学者,而且还是自学的人,有一个很头疼的问题.那就是数据都已经查出来了,但是页面的样式仍然十分简陋,加载不了css.js,图片等资源文 ...

  7. spring boot --- 使用 注解 读取 properties 文件 信息

    1.前言 以前使用spring MVC框架 ,读取properties 配置文件需要写一大堆东西 ,也许 那时候 不怎么使用注解 ,现在使用spring boot ,发现了非常简便的办法---使用注解 ...

  8. Spring MVC基础知识整理➣Spring+SpringMVC+Hibernate整合操作数据库

    概述 Hibernate是一款优秀的ORM框架,能够连接并操作数据库,包括保存和修改数据.Spring MVC是Java的web框架,能够将Hibernate集成进去,完成数据的CRUD.Hibern ...

  9. Spring MVC篇二、使用JdbcTemplate进行数据库操作

    上一篇只是一个简单的Spring MVC框架,接下来添加一些跟数据库的交互. 一.添加jdbc相关配置   在maven中添加相关依赖后,配置数据库访问参数及数据源.数据库参数使用配置文件,代码如下: ...

随机推荐

  1. 重载运算符:类成员函数or友元函数

    类成员函数: bool operator ==(const point &a)const { return x==a.x; } 友元函数: friend bool operator ==(co ...

  2. 安装PLSQL,登录报“无法解析指定的连接标识符的错误”

    安装PLSQL,本地不需要安装oracle服务器,但要安装oracle客户端. 一.安装客户端需要配置服务命名,tnsnames.oRA文件和监听(因为我开始没有配置监听,所以一直报无法解析制定的连接 ...

  3. ASP.NET Repeater 控件分页

    protected void Page_Load(object sender, EventArgs e) { HttpContext context = HttpContext.Current; co ...

  4. oracle 将多字段数据合成一个

    1.系统默认 WMSYS.WM_CONCAT(A.ID), 2.再进行替换 REPLACE(WMSYS.WM_CONCAT(A.ID),',','|'), (张)

  5. sql server 2008中清除数据库日志的sql语句

    第一步: Use  数据库名 Select NAME,size From sys.database_files 将“数据库名”改为需要清除日志的数据库名字,点击“执行”查询出需要清除的日志名称:**_ ...

  6. mvc4 部署http错误403.14 forbidden

    1. 检查服务器上是否安装了“HTTP重定向”功能和“静态内容压缩”功能(在添加/删除程序或增加角色处安装).这是我所遇到的问题:2. 应用程序池要被配置为“集成”3. 把.net 4.0安装在iis ...

  7. Unity3D–RectTransfrom 记录笔记

    一.基本要点 部分来源:http://www.2fz1.com/post/unity-ugui-recttransform/ RectTransform继承于Trasnfrom , 在Trasnfor ...

  8. AIX上通过IPSEC进行IP包过滤

    AIX上的IPSEC 在AIX可以通过以下步骤打开IP Security smitty ipsec4 --> Start/Stop IP Security --> Start IP Sec ...

  9. myeclipse10中文注释乱码问题

    将别人的项目或JAVA文件导入到自己的Eclipse中时,常常会出现JAVA文件的中文注释变成乱码的情况,主要原因就是别人的IDE编码格式和自己的Eclipse编码格式不同. 总结网上的建议和自己的体 ...

  10. 用bugzilla统计BUG

    bugzilla—— reports—— Tabular reports—— 选择版本号啥的跟search一样 上面的行标Vertical Axis选Resolution:列标Horizontal A ...