struts的message标签换成EL表达式

对于习惯于使用EL表达式的人来说,用struts的message标签简直是种倒退。message用到地方非常多,每次都敲<bean:message key="...."/>,在这个标签污染严重的时代可不是什么好事啊。

幸好,将其转换为EL表达式不难。

[b]要点:[/b]

EL表达式对java.util.Map对象的点运算符的递归调用。举例登录页面,${message.login.username}。
解释一下:
[quote][color=blue]只要request里面有个属性名叫"message"的Map,这个Map里有个字符串"login"的key,这个Key指向一个Map,而这个Map里有个字符串"username"的key,这个key指向一个字符串。[/color][/quote]
而这个字符串就是我们要的Message。我们要做的就是把这些MessageResource文件中的key转换成这样的格式 ----- [color=red]message.login.username[/color]。

唯一的缺点就是需要有一个"根"key在JSP的某个Context上下里(最好是Session,下面会讲到)。"message"就是"根"key,但我们可以让它更简便些${_msg.login.username}或者干脆${_.login.username}.这样,资源文件中的键值对就被转换到树形的Map群里了,这里我们给它个名字“[color=red]资源Map[/color]”。

好了,还有一个需要解决的问题,国际化。如果对struts有研究的话,应该会知道用户的语言种类是记录在HttpSession "org.apache.struts.action.LOCALE"(struts的org.apache.struts.Globals.LOCALE_KEY)属性中的java.util.Locale对象。通过HttpSessionAttributeListener可以侦测到其值变化(用户改变语言的时候)。这样,只需要一个全局的Map记住所有资源文件转换而成的“[color=red]资源Map[/color]”,key就是Locale.toString()。只要用户的Locale发生了变化,通过侦听器切换用户Session的“根”key指向“[color=red]资源Map[/color]”即可。

[b]废话不多说,开始行动:[/b]
第一个,先做一个读取资源文件并转换“[color=red]资源Map[/color]”的类MessagePreLoader,假设你已经用上Spring了。

package com.your.struts.base.bean;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

import org.springframework.beans.factory.InitializingBean;

public class MessagePreLoader implements InitializingBean {
/**
* 默认资源Map对应的Key
*/
private static final String DEFAULT_LOCAL_KEY = "default";
/**
* 全局的Map,所有资源Map的挂载点。
*/
private Map resourceHolder = new HashMap();
/**
* struts的资源文件的位置。假设struts的配置是:
* <message-resources parameter="com.your.struts.message.ApplicationResources" >
* 那么此处则是com/your/struts/message/ApplicationResources
* 所有“.”换成“/”
*/
private String resourceName ;
/**
* 所支持的语言对象集合.
*/
private String[] locales = {};
/**
* 设定资源文件是xml格式还是普通的properties文件。此处默认是xml格式(不用借助插件就可以直接用XML编辑器编辑)
*/
private boolean xmlResouce=true;

public boolean isXmlResouce() {
return xmlResouce;
}

public void setXmlResouce(boolean xmlResouce) {
this.xmlResouce = xmlResouce;
}

public String[] getLocales() {
return locales;
}

public void setLocales(String[] locales) {
this.locales = locales;
}

public String getResourceName() {
return resourceName;
}

public void setResourceName(String resourceName) {
this.resourceName = resourceName;
}

public Map getResourceHolder() {
return resourceHolder;
}

private void addMap(String localeKey) throws Exception{
String name=null;
if(DEFAULT_LOCAL_KEY.equals(localeKey)){
name=this.resourceName+(xmlResouce?".xml":".properties");
}else{
name=this.resourceName+"_"+localeKey+(xmlResouce?".xml":".properties");
}
Map map = new HashMap();
this.resourceHolder.put(localeKey, map);
ClassLoader classLoader =
Thread.currentThread().getContextClassLoader();

if (classLoader == null) {
classLoader = this.getClass().getClassLoader();
}

InputStream is = classLoader.getResourceAsStream(name);
Properties props = new Properties();
if(xmlResouce){
props.loadFromXML(is);//此处是因为本人项目所用的资源文件是xml,方便编辑而不必用特殊的插件。
}else{
props.load(is);//不用InputStreamReader的方式是因为struts资源文件本身就只使用InputStream方式。
}
for(Iterator iter = props.keySet().iterator();iter.hasNext();){
String key = (String)iter.next();
String[] strs=key.split("\\.");
String value = props.getProperty(key);
Map last = map;
for (int j = 0; j < strs.length; j++) {
Object o=last.get(strs[j]);
if(o==null){
if(j!=strs.length-1){//不是最后一个key
o=new HashMap();
last.put(strs[j], o);
last=(Map)o;
}else{//最后一个Key
last.put(strs[j], value);
}
}else{
if(j!=strs.length-1){//不是最后一个key
if(o instanceof String)throw new Exception(" is a java.lang.String ,expact java.util.Map," +
"cause by key conflict,such as: \"x.y.z\" and \"x.y\" all exists. current key:"+key);
last=(Map)o;
}else{//最后一个Key
throw new Exception(" dulpicat key exists , current key:"+key);//此类情况应该永远不会发生
}
}
}
}
}

public void afterPropertiesSet() throws Exception {
this.addMap(DEFAULT_LOCAL_KEY);
for (int i = 0; i < locales.length; i++) {
this.addMap(locales[i]);
}
}

public Map getLocaleMessageSet(String localeKey){
Object obj=this.resourceHolder.get(localeKey);
return (Map)(obj==null?this.resourceHolder.get(DEFAULT_LOCAL_KEY):obj);
}




[b]Spring 配置:[/b]

<bean id="messagePreLoader" class="com.your.struts.base.bean.MessagePreLoader">
<property name="xmlResouce" value="false"></property>
<property name="resourceName" value="com/your/struts/message/ApplicationResources"></property>
<property name="locales">
<list>
<value>zh_CN</value>
<value>en</value>
</list>
</property>
</bean>

[b]制作SessionListener的委派类:[/b]
SessionListenerDelegate用于侦听locale信息的改变。

package com.your.servlet.listener;

import java.util.Locale;

import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.Globals;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.your.struts.base.bean.MessagePreLoader;

public class SessionListenerDelegate implements HttpSessionAttributeListener{
/**
* Session里面资源Map的Key
*/
public static final String MESSAGE_SESSION_KEY="_msg";


public SessionListenerDelegate() {
super();
}

private static final Log logger = LogFactory.getLog(SessionListenerDelegate.class);
/**
* 侦测语言属性的变化,并设置用户对应的资源Map
* @param bindingEvent
*/
private void setLocale(HttpSessionBindingEvent bindingEvent) {
if(bindingEvent.getName().equals(Globals.LOCALE_KEY)){
HttpSession session=bindingEvent.getSession();
Locale locale = (Locale)session.getAttribute(Globals.LOCALE_KEY);
ApplicationContext ctx = (ApplicationContext) WebApplicationContextUtils.getRequiredWebApplicationContext(session.getServletContext());
MessagePreLoader messagePreLoader = (MessagePreLoader) ctx.getBean("messagePreLoader");
String localeKey=null;
if(locale!=null){
localeKey=locale.toString();
}
Object localeMsgSet= messagePreLoader.getLocaleMessageSet(localeKey);
session.setAttribute(MESSAGE_SESSION_KEY, localeMsgSet);
}
}

public void attributeAdded(HttpSessionBindingEvent bindingEvent) {
setLocale(bindingEvent);
if(logger.isDebugEnabled())logger.debug("attribute added. name:{"+bindingEvent.getName()+"} old value:"+bindingEvent.getValue()+" new value:"+bindingEvent.getSession().getAttribute(bindingEvent.getName()));
}


public void attributeRemoved(HttpSessionBindingEvent bindingEvent) {
if(logger.isDebugEnabled())logger.debug("attribute remove. name:{"+bindingEvent.getName()+"} value:"+bindingEvent.getValue());
}

public void attributeReplaced(HttpSessionBindingEvent bindingEvent) {
this.setLocale(bindingEvent);
if(logger.isDebugEnabled())logger.debug("attribute replace. name:{"+bindingEvent.getName()+"} old value:"+bindingEvent.getValue()+" new value:"+bindingEvent.getSession().getAttribute(bindingEvent.getName()));
}

}



web.xml里面:

<listener>
<listener-class>
com.your.servlet.listener.SessionListenerDelegate
</listener-class>
</listener>


这样。我们就可以在JSP中使用${_msg....}这样的EL表达式来访问国际化的资源信息了。

<table>
<tr><td>${_msg.commons.login.username}:</td><td><input type='text' name='j_username' value='<c:if test="${not empty param.login_error}"><c:out value="${lastUserName}"/></c:if>'/></td></tr>
<tr><td>${_msg.commons.login.password}:</td><td><input type='password' name='j_password'></td></tr>
</table>


没有了message标签,输入也方便了。何乐不为?

最后,需要注意的地方,你的message文件中不能出现这样的打架现象:

commons.login=User Login
commons.login.username=User Name


这样小小的请求,我想你是可以忍受的。

另外,如果觉得这个方式对你项目没有帮助,请勿使用。。。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值