Using resource bundle for validation messages in Spring

本文探讨了在Spring MVC中实现国际化配置时遇到的问题及解决方案,重点介绍了如何正确配置消息来源,解决找不到国际化消息的问题,并提供了动态加载多语言资源文件的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

What i am trying to do is
1. putting up the messages file in WEB-INF/i18/validationMessages_en.properties and trying to validate the messages on login.

The dispatcher-servlet.xml contains
  1. <context:component-scanbase-package="com.practise.controller"/>
  2. <beanid="userValidator"class="com.practise.validator.UserValidator">
  3. </bean>
  4. <beanclass="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
  5. <beanclass="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
  6. <beanid="viewResolver"class="org.springframework.web.servlet.view.UrlBasedViewResolver">
  7. <propertyname="viewClass"value="org.springframework.web.servlet.view.JstlView"/>
  8. <propertyname="prefix"value="/WEB-INF/jsp/"/>
  9. <propertyname="suffix"value=".jsp"/>
  10. </bean>
  11. <beanid="messageSource"class="org.springframework.context.support.ResourceBundleMessageSource">
  12. <propertyname="basenames"value="/WEB-INF/i18n/validationMessages_en">
  13. </property>
  14. </bean>


  1. @RequestMapping(value="/login",method=RequestMethod.GET)
  2. publicModelAndViewauthenticateUser(HttpServletRequestrequest,
  3. HttpServletResponseresponse,
  4. @ModelAttribute("loginbean")LoginBeanloginbean,
  5. BindingResultresult){
  6. ModelMapobjModel=newModelMap();
  7. userValidator.validate(loginbean,result);
  8. objModel.addAttribute("loginbean",loginbean);
  9. if(result.hasErrors()){
  10. returnnewModelAndView("home",objModel);
  11. }
  12. returnnewModelAndView("practise",objModel);
  13. }


the valdation class

  1. publicclassUserValidatorimplementsValidator{
  2. @Override
  3. publicbooleansupports(ClassaClass){
  4. returnLoginBean.class.equals(aClass);
  5. }
  6. @Override
  7. publicvoidvalidate(Objectarg0,Errorserrors){
  8. ValidationUtils.rejectIfEmptyOrWhitespace(errors,"username","username.required");
  9. ValidationUtils.rejectIfEmptyOrWhitespace(errors,"password","password.required");
  10. }



validationMessages.properties
  1. username.required=UserNameisarequiredfield.
  2. password.required=Passwordisarequiredfield.


below is the error console
org.springframework.context.NoSuchMessageException: No message found under code 'username.required' for locale 'en_US'.
at org.springframework.context.support.AbstractMessageSource.getMessage(AbstractMessageSource.java:161)
at org.springframework.context.support.AbstractApplicationContext.getMessage(AbstractApplicationContext.java:1196)
at org.springframework.web.servlet.support.RequestContext.getMessage(RequestContext.java:553)
at org.springframework.web.servlet.support.BindStatus.initErrorMessages(BindStatus.java:177)
at org.springframework.web.servlet.support.BindStatus.getErrorMessages(BindStatus.java:273)
at org.springframework.web.servlet.tags.form.ErrorsTag.exposeAttributes(ErrorsTag.java:173)
at org.springframework.web.servlet.tags.form.AbstractHtmlElementBodyTag.writeTagContent(AbstractHtmlElementBodyTag.java:48)
at org.springframework.web.servlet.tags.form.AbstractFormTag.doStartTagInternal(AbstractFormTag.java:102)
at org.springframework.web.servlet.tags.RequestContextAwareTag.doStartTag(RequestContextAwareTag.java:79)
at org.apache.jsp.WEB_002dINF.jsp.home_jsp._jspService(home_jsp.java:112)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:377)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:313)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:260)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:646)
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:436)
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:374)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:302)
at org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:238)
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:250)
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1047)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:817)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:549)

______________________________________________________________
But when i put my properties file under src folder and change my dispatcher-servelet as
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames" value="validationMessages_en">
</property>
</bean

all seems to work fine.

What may be the problem if i use i18n and put my properties file under this folder


Thanks Jaspreet ----- Nothing is permanent

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

I would like to mimic the Grails way of resolving i18n messages.

In WEB-INF/i18n/ I have the following directories:

admin/messages_EN.properties

admin/messages_FR.properties

website/messages_EN.properties

website/messages_FR.properties

please ignore the language endings ( EN and FR ) in this example

in my xml configuration I currently have:

<!-- Register the welcome.properties -->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
 <property name="defaultEncoding" value="utf-8" />
 <property name="basename" value="/WEB-INF/i18n/" />
</bean>

What I am looking for here, is a way to tell Spring to look for .properties files under i18n but without explicitly telling it what each subdirectory is. That is without a list of basenames that points to /WEB-INF/i18n/admin/ and /WEB-INF/i18n/website/

I want the WEB-INF/i18n/ directory to be dynamic, and that bundles ( directories ) can be created without having to remodify the xml configuration file.

I am not trying to solve this particular example with admin and website sub directories

Is this possible?

Thanks!

share | improve this question

54% accept rate
You'll probably have to extend ReloadableResourceBundleMessageSource to introduce some sort of discover property that causes the message source to search the basename directory, instead of loading files directly.Paul Grime Jun 20 at 10:51
@PaulGrime I have implemented something based on your suggestion and edited my question to include the suggested implementation. Something along these lines should work right? Missing something? Thanks!Hamidam Jun 20 at 15:17
feedback

1 Answer

up vote 0 down vote accepted

Here is the solution:

package com.mypackage.core.src;

import java.io.File;
import java.util.ArrayList;

import javax.servlet.ServletContext;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;

public class UnderDirectoryReloadableResourceBundleMessageSource extends ReloadableResourceBundleMessageSource {

  @Autowired
  ServletContext servletContext;

  public void setWorkingDirectory(String directoryPath) {
    File rootDir = new File( servletContext.getRealPath(directoryPath) );
    ArrayList<String> baseNames = new ArrayList<String>();
    iterateScanDirectoryAndAddBaseNames(baseNames, rootDir);
    setBasenames(baseNames.toArray(new String[baseNames.size()]));
  }

  private void iterateScanDirectoryAndAddBaseNames(ArrayList<String> baseNames, File directory) {
    File[] files = directory.listFiles();

    for (File file : files) {
      if (file.isDirectory()) {
        iterateScanDirectoryAndAddBaseNames(baseNames, file);
      } else {
        if (file.getName().endsWith(".properties")) {
          String filePath = file.getAbsolutePath().replaceAll("\\\\", "/").replaceAll(".properties$", "");
          filePath = filePath.substring(filePath.indexOf("/WEB-INF/"), filePath.length());
          baseNames.add(filePath);
          System.out.println("Added file to baseNames: " + filePath);
        }
      }
    }
  }

}

XML config:

<bean id="messageSource" class="com.mypackage.core.src.UnderDirectoryReloadableResourceBundleMessageSource">
 <property name="defaultEncoding" value="utf-8" />
 <property name="workingDirectory" value="/WEB-INF/webspring/i18n" />
 <property name="cacheSeconds" value="3" />
 <property name="fallbackToSystemLocale" value="false" />
</bean>

Enjoy!





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值