分享

JSF实现的自选语言界面

 chanvy 2009-01-02
JSF实现的自选语言界面

 


〖 作者:qjyong 〗〖 大小:1k 〗〖 发布日期:2007-12-16 〗〖 浏览:0 〗

  

Source: http://www./cwbwebhome/article/article2/21023.html?id=1735
问题描述:实现一个带自选语言栏的用户登录验证示例的国际化。对于这个实例分两部分来实现:先实现用户登录验证的国际化,再加上自选语言栏。
  
第一部分:实现用户登录验证
创建一个名为I18N_demoJSF Web项目。
1.         创建后台Bean
在项目中创建一个后台BeanRegistrationBean.java
package org.qiujy.web.controller;
 
import java.text.MessageFormat;
import java.util.Locale;
import java.util.ResourceBundle;
 
public class RegistrationBean {
    private String userName;
    private String password;
 
    //以下是属性的gettersetter方法
    ......
 
    public String validate() {
             boolean flag = true;
             if (!"test".equals(userName)) {
                       FacesMessage msg = MessageFactory.getMessage(FacesContext
                                         .getCurrentInstance(), "field_ISERROR",
                                         new Object[] { "userName" });
                       FacesContext.getCurrentInstance().addMessage(null, msg);
                       flag = false;
             }
             if (!"123456".equals(password)) {
                       FacesMessage msg = MessageFactory.getMessage(FacesContext
                                         .getCurrentInstance(), "field_ISERROR",
                                         new Object[] { "password" });
                       FacesContext.getCurrentInstance().addMessage(null, msg);
                       flag = false;
             }
 
             if (flag) {
                       return "success";
             } else {
                       return "failure";
             }
    }
}
这个Bean中提供跟页面绑定的属性,以及跟动作按钮绑定的动作处理方法validate(),在这个方法中需要注意的是,对用户名、密码都进行了相应的判断,如果是test123456,就是合法用户,返回结果字符串“success”,否则是非法用户,通过JSF提供的MessageFactory来获取并创建好一则本地化错误消息(消息“键”是“field_ISERROR”),添加到FacesContext中,然后返回结果字符串“failure”。这样到了失败页面就可以取出相应的经过本地化的错误消息。
2.         配置托管Bean和资源文件绑定
faces-config.xml文件中把RegistrationBean配置成托管Bean。同时为了支持国际化,指定了错误消息文件和资源文件,它们是同一个文件,就是存放在应用的org/qiujy/web/resources目录下的ApplicationMessages.properties文件,稍后再来看这个文件的内容:
<faces-config>
<application>
        <message-bundle>
org.qiujy.web.resources.ApplicationMessages
</message-bundle>
        <locale-config>
                 <default-locale>zh_CN</default-locale>
                 <supported-locale>en</supported-locale>
                 <supported-locale>zh_TW</supported-locale>
        </locale-config>
       
        <resource-bundle>
                 <base-name>
org.qiujy.web.resources.ApplicationMessages
</base-name>
                 <var>bundle</var>
        </resource-bundle>
</application>
        
         <managed-bean>
                   <managed-bean-name>registrationBean</managed-bean-name>
                   <managed-bean-class>
                            org.qiujy.web.controller.RegistrationBean
                   </managed-bean-class>
                   <managed-bean-scope>request</managed-bean-scope>
         </managed-bean>
         ......
</faces-config>
3.         创建页面和本地化资源文件
用户登录页面:userlogin.jsp
<%@ page language="java" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java./jsf/html" prefix="h"%>
<%@ taglib uri="http://java./jsf/core" prefix="f"%>
 
<f:view>
         <html>
                   <head>
                            <title><h:outputText value="#{bundle.title_login}" /></title>
                   </head>
 
                   <body>
                            <h:form id="loginForm">
                                     <h:panelGrid columns="2">
                                               <h:graphicImage url="#{bundle.login_logo}"
                                                                                    width="220" height="160"/>
                                    
                                               <h:panelGrid columns="3">
                                                        <f:facet name="caption">
                                                                 <h:outputText value="#{bundle.title_login}" />
                                                        </f:facet>
        
                                                        <h:outputText value="#{bundle.login_userName}" />
                                                        <h:inputText id="textName"
                                                                 value="#{registrationBean.userName}"
                                                                 required="true">
                                                                          
                                                        </h:inputText>
                                                        <h:message for="textName" style="color:red" />
        
                                                        <h:outputText value="#{bundle.login_password}" />
                                                        <h:inputSecret id="textPwd"
                                                                 value="#{registrationBean.password}"
                                                                 required="true">
                                                                 <f:validateLength minimum="6" maximum="20"/>
                                                        </h:inputSecret>
                                                        <h:message for="textPwd" style="color:red" />
        
                                                        <f:facet name="footer">
                                                                 <h:panelGroup>
                                                                           <h:commandButton value="#{bundle.button_submit}"
                                                                                    action="#{registrationBean.validate}" />
                                                                           <h:outputText value=" "></h:outputText>
                                                                           <h:commandButton value="#{bundle.button_reset}"
                                                                                    type="reset" />
                                                                 </h:panelGroup>
                                                        </f:facet>
                                               </h:panelGrid>
                                     </h:panelGrid>
                            </h:form>
                   </body>
         </html>
</f:view>
在这个页面中,所有静态文本,错误消息都通过值表达式用资源文件的别名“bundle”来获取的。所有的资源消息“键”在本地化资源文件中都配置了相应的“值”,如下:
代码片段7.15 缺省的资源文件ApplicationMessages.properties
button_submit=Submit
button_reset=Reset
button_back=Back
 
title_login=User Login Page
login_userName=UserName:
login_password=Password:
login_logo=/images/jsf_i18n_en.gif
 
success_welcome=Welcome:
failure_error=Failure!
field_ISERROR= {0} is error.
         英文的资源文件ApplicationMessages_en.properties的内容跟这个相同。下面再来看简体中文的资源文件:
简体中文的资源文件ApplicationMessages_zh_CN.properties
button_submit=提交
button_reset=重置
button_back=后退
 
title_login=用户登录页面
login_userName=用户名:
login_password=密码::
login_logo=/images/jsf_i18n_zh_CN.gif
 
success_welcome=欢迎:
failure_error=失败!
field_ISERROR= {0} 不正确
         需要注意是,使用是别忘了进行Uncodei编码转换。至于繁体中文的资源文件也跟这个文件差不多,在此不再赘述。
         另外要对标准的错误消息进行国际化,可以把SUNRI实现中的错误消息全部复制到本地化资源文件中,对简体中文的资源进行汉化,由于内容较多,在这就不帖出代码了,具体可能看本例的源代码。
接下来看登录成功后的页面的代码:success.jsp
                
<%@ page language="java" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java./jsf/html" prefix="h"%>
<%@ taglib uri="http://java./jsf/core" prefix="f"%>
<f:view>
         <html>
                   <head>
                            <title><h:outputText value="#{bundle.success_welcome}"/></title>
                   </head>
                   <body>
                            <h2>
                                     <h:outputText value="#{bundle.success_welcome}" />
                                     <h:outputText value="#{registrationBean.userName}" />
                            </h2>
                   <jsp:useBean id="currentDate" class="java.util.Date" scope="request"/>
                            <h:outputText value="#{currentDate}">
                                     <f:convertDateTime type="both"/>
                            </h:outputText>
                   </body>
         </html>
</f:view>
在这个页面中,为了演示日期时间的国际化,先创建了一个日期对象,然后用Output组件标签输出,并给这个标签注册了DateTimeConverter,这样就能实现日期时间的国际化了。
最后再来看登录失败页面的代码:failure.jsp
<%@ page language="java" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java./jsf/html" prefix="h" %>
<%@ taglib uri="http://java./jsf/core" prefix="f" %>
<f:view>
         <html>
                   <head>
                            <title><h:outputText value="#{bundle.failure_error}"/></title>
                   </head>
                   <body>
                            <h2><h:outputText value="#{bundle.failure_error}"/></h2>
                            <h:messages style="color:red"/><br/>
                            <h:outputLink value="userlogin.faces">
                                     <h:outputText value="#{bundle.button_back}"/>
                            </h:outputLink>
                   </body>
         </html>
</f:view>
在这个页面,用<h:message>标签输出了登录失败的原因,这个错误消息是在后台Bean中的validate()方法中从资源文件中引用的经过本地化后的消息。
4.         配置导航规则
导航规则比较简单,直接看代码:
<navigation-rule>
         <from-view-id>/userlogin.jsp</from-view-id>
         <navigation-case>
                   <from-outcome>success</from-outcome>
                   <to-view-id>/success.jsp</to-view-id>
         </navigation-case>
         <navigation-case>
                   <from-outcome>failure</from-outcome>
                   <to-view-id>/failure.jsp</to-view-id>
         </navigation-case>
</navigation-rule>
第二部分: 实现自选语言栏
实现页面的语言可以让用户根据自己的喜好进行选择,也是在做web应用时比较常见的一个功能。下面就来完成这个任务。
1.         创建后台Bean
在这个应用中添加一个处理用户自选语言的后台BeanLanguageSelectorBean,代码如下:
package org.qiujy.common;
 
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
 
import javax.faces.context.FacesContext;
import javax.faces.event.ValueChangeEvent;
 
public class LanguageSelectorBean {
         private String currentLocale;
 
         // 本应用支持的语言Map
         private Map<String, Locale> supportLocals;
 
         public LanguageSelectorBean() {
                   supportLocals = new HashMap<String, Locale>();
                   supportLocals.put("zh_CN", Locale.CHINA);
                   supportLocals.put("zh_TW", Locale.TAIWAN);
                   supportLocals.put("en", Locale.ENGLISH);
 
                   this.currentLocale = FacesContext.getCurrentInstance().getViewRoot()
                                     .getLocale().toString();
         }
 
         public String getCurrentLocale() {
                   return currentLocale;
         }
 
         public void setCurrentLocale(String currentLocale) {
                   this.currentLocale = currentLocale;
         }
 
         // 改变当前语言区域的事件处理方法
         public void changeLocale(ValueChangeEvent event) {
                   String currentLocale = (String) event.getNewValue();
                   // 设置当前的语言区域
                   Locale myLocale = this.supportLocals.get(currentLocale);
                   FacesContext.getCurrentInstance().getViewRoot().setLocale(myLocale);
 
                   // 把自定义语言存放到Session
                   HttpServletRequest request = (HttpServletRequest) FacesContext
                                     .getCurrentInstance().getExternalContext().getRequest();
                   request.getSession().setAttribute("myLocale", myLocale);
         }
}
         在这个后台Bean中有一个值改变事件处理方法changeLocale(),它根据用户选中的语言代码来更改当前FacesContext中的视图的默认语言区域。同时,为了让当前用户的整个会话过程的语言区域都是用户的自行选择的,需要把用户选择的语言区域对象存放到Session中。
2.         创建阶段事件监听器来设置自选语言环境
用户设置好语言环境后,要想在当前会话的后续请求中继续生效,就要在所有JSF请求处理生命周期的“呈现响应阶段”发生前更改当前FacesContext中的视图的默认语言区域,这个任务交由阶段事件监听器来实现。所在,在本应用中还要添加一个阶段事件监听器的实现类。如:
package org.qiujy.common;
 
import java.util.Locale;
 
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import javax.servlet.http.HttpServletRequest;
 
/**
 * 阶段事件监听器实现类:主要是用来设置自选语言环境
*/
@SuppressWarnings("serial")
public class MyPhaseListener implements PhaseListener {
         /**
          * 结束某个阶段时会调用到的方法
          */
         public void afterPhase(PhaseEvent pe) {
         }
 
         /**
          * 开始某个阶段时会调用到的方法
          */
         public void beforePhase(PhaseEvent pe) {
                   System.out.println("this is Phase: " + pe.getPhaseId().toString());
                   // 呈现响应阶段,设置自选语言环境
                   HttpServletRequest request = (HttpServletRequest) FacesContext
                                     .getCurrentInstance().getExternalContext().getRequest();
 
                   Locale myLocale = (Locale) request.getSession().getAttribute("myLocale");
                   System.out.println("current request locale is: "
                                     + FacesContext.getCurrentInstance().getViewRoot().getLocale()
                                                        .toString());
 
                   if (myLocale != null) {
                            FacesContext.getCurrentInstance().getViewRoot().setLocale(myLocale);
 
                            System.out.println("current Custom locale is: "
                                               + FacesContext.getCurrentInstance().getViewRoot()
                                                                 .getLocale().toString());
                   }
         }
 
         /**
          * 只监听"呈现响应阶段"
          */
         public PhaseId getPhaseId() {
                   return PhaseId.RENDER_RESPONSE;
         }
}
这个类实现了PhaseListener接口,通过在getPhashId()方法中返回PhaseId.RENDER_RESPONSE来监听“呈现响应阶段”事件,在开始“呈现响应阶段”事件时,会调用本类的beforePhase()方法,在这个方法中,通过从Session对象中取出用户设置好的语言环境,来更改当前FacesContext中的视图的默认语言区域。这样,当前会话的后续响应都会用用户选择的语言环境来呈现视图了。注意,要把此监听器类配置在faces-config.xml中,它的作用才生效,如:
<lifecycle>
         <phase-listener>
                   org.qiujy.common.MyPhaseListener
         </phase-listener>
</lifecycle>
3.         配置托管Bean和资源文件绑定
像其它托管Bean一样,把它配置在faces-config.xml文件中,但要注意一点的是,这个托管Bean的存放范围应该选择session,这样才能保证对语言区域的选择在当前用户的整个会话过程中都有效。
<managed-bean>
         <managed-bean-name>languageSelectorBean</managed-bean-name>
         <managed-bean-class>
                   org.qiujy.common.LanguageSelectorBean
         </managed-bean-class>
         <managed-bean-scope>session</managed-bean-scope>
</managed-bean>
4.         创建页面和本地化资源文件
接下来创建一个语言选择栏页面:
<%@ page language="java" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java./jsf/html" prefix="h"%>
<%@ taglib uri="http://java./jsf/core" prefix="f"%>
 
<f:subview id="languageView">
         <h:form id="languageForm"
                   style="background-color:#bbbbbb; padding-top:4px; padding-bottom:4px;">
                   <h:outputText value="#{bundle.selectYourLocale}"></h:outputText>
                   <h:selectOneMenu value="#{languageSelectorBean.currentLocale}"
                            immediate="true" onchange="submit();"
                            valueChangeListener="#{languageSelectorBean.changeLocale}">
                            <f:selectItem itemValue="zh_CN" itemLabel="#{bundle.zh_CNText}" />
                            <f:selectItem itemValue="zh_TW" itemLabel="#{bundle.zh_TWText}" />
                            <f:selectItem itemValue="en" itemLabel="#{bundle.enText}" />
                   </h:selectOneMenu>
         </h:form>
</f:subview>
这个页面的特殊之处有三处:
它的根视图标签是<f:subview>,而不是常用的<f:view>了,这是因为这个页面经常是用来内嵌到其它页面的,而JSF规范又要求一个页面只能有一个<f:view>顶层视图,所以就只能用<f:subview>来创建一个子视图。
selectOneMenu组件添加了一个值改变事件监听器,同时添加了一个JavaScriptonchange事件来提交表单,这样在改变下拉菜单的选中项时,会提交表单,同时会触发值改变事件。这样就能实现改变语言区域的功能了。
selectOneMenu组件的immediate属性值设置为true,这样可以使这个组件提交表单时,请求处理生命周期的应用请求阶段就会调用值改变事件的处理方法,从而把应用验证“短路”掉,这样即使页面的一些必填字段(本例中的用户名,密码)没有输入值,也不会报错了。
最后,还要在所有的本地化资源文件中分别加上这个页面中出现的消息“键-值”对,例如在缺省的资源文件中添加如下代码:
zh_CNText=Chinese,Simplify
zh_TWText=Chinese,Traditional
enText=English
selectYourLocale=Select Language:
5.         在页面上包含自选语言栏页面
在用户登录页面中用JSPinclude动作把自选语言栏页面包含进来,在userlogin.jsp页面body体的首行添加如下代码:
<jsp:include page="languageSelector.jsp"/>
6.         运行查看效果
到此整个应用开发完毕,项目目录结构如图
自选语言项目目录结构图
重新部署应用,运行,访问主页:
      
中文主页图
通过在下拉列表选中“英文”来更新想要的英文界面:



英文主页图

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多