`

Struts 2核心技术与Java EE框架整合开发实战

阅读更多
17.3  Struts 2整合JSF
目前基于JSF规范较成熟的框架有两个,一个Sun的JSFUI,另一个是Apache的MyFaces框 架。因为Struts 2提供了对MyFaces更好的插件支持,因此本示例采用Apache的MyFaces。整合之前让我们先来比较一下这两种表示层的框架。
17.3.1  Struts 2整合JSF的优点
下面从不同方面比较一下Sturts 2与JSF各自的特点。
首先,在标签库方面,Struts 2的标签库相对要少一些,且不可以自定义;而JSF可以自定义标签。JSF框架拥有丰富的页面组件,如果需要的话可以自己编写相应的组件,或者 扩展组件;而在JSP的页面中JSF提供了页面验证标签,可以做简单的长度和类型的验证。Struts 2的验证可以有两种方式,form验证与validator验证,功能上要比JSF强大。JSF的组件都是绑定到Bean的,而且数据验证的方法也可以绑 定,这一点可以增强验证的功能。而对于验证的错误提示信息,它们都提供了国际化,使得验证更人性化。
其次比较一下导航,二者之间的导航功能的相同点是都通过在XML文件中配置导航规则。Struts 2的XML中配置页面跳转的类型,如转发,重 定向,由Action返回的字符串来决定导航的目标;而JSF在导航规则中设定页面导航,当某个页面请求到来时,根据导航规则调用指定的Action方法进行处理,并返回一个逻辑视图,然后跳转到与逻辑视图对应的页面。JSF同时支持在页面中绑定按钮触发Action的具体方法,导航原理也是一样的。
最后比较一下Struts 2与JSF处理请求的方式。Struts 2调用指定的方法处理请求(如果没有指定具体方法则默认调用excute方法)。JSF采用了普通的POJO类作为它的Action,将Action类绑定到页面组件,通过值变监听与事件监听进行请求处理。相比之下,JSF处理请求的方式要比Struts2复杂,不方便系统升级。
总而言之,如果将JSF做为Struts 2的视图层,用Struts 2的Action做模型,可以开发出完美的应用系统。
接下来就将讲解Struts 2与JSF 的结合使用。
17.3.2  Struts 2与JSF整合过程
每种框架都有它独到的设计之处,Struts 2的可扩展性使得它的生命力非常顽强。Struts 2提供了多种框架的插件包,它与MyFaces 整合就是利用插件来实现的。下面我们介绍如何进行二者的结合应用。
首先下载Struts 2的JSF插件,下载地址是 http://struts.apache.org/ downloads.html。目前最高的插件版本是2.0.11,我们使用这个最新的版本与myfaces进行整合。
Apache的MyFaces下载地址是http://myfaces.apache.org. /download.html,目前的最高版本是1.2.2,本示例使用的是1.1.5。下载后得到名为myfaces-core-1.1.5的压缩文 件,将该文件解压,得到lib包下的运行库文件(.jar文件)。
17.3.3  整合应用实例
2008年是奥运年,因此我们采用目前最流行的奥运啦啦队员的选拔活动为主题,设计一个Struts 2+JSF应用的示例。
奥运啦啦队员选拔队员的设计分为3种功能:增加选手、查询选手、修改选手。
按如下的顺序创建示例程序。
(1)配置环境:配置Struts 2+JSF整合过程的运行环境。
(2)配置struts.xml文件:配置JSF拦截器与请求的Action。
(3)创建页面:注册选手页面,显示所有选手列表页面,修改选手页面。
(4)创建JavaBean。选手信息类PlayerInfo与控制器类OlympicAction。
(5)配置Web应用文件:配置Struts 2请求转发控制器。
(6)发布运行:演示发布运行后的结果页面。
下面详细介绍各个环节的实现过程。
(1)配置应用程序运行环境。
添加Struts 2核心资源包、Struts 2的JSF 插件包、MyFaces资源包。
(2)配置struts.xml。
利用Struts 2+JSF开发视图层,需要的配置文 件是struts.xml。这个文件配置信息分为两个部分,一个是JSF 拦截器的配置,另一个是Struts 2的Action配置。
首先看一下JSF拦截器的配置:
在struts.xml文件中需要配置JSF的拦截器,使得所有的JSF的请求都能被正确处理。这个拦截器在Struts的插件包中已经定义好了,继承这个包就可以使 用这些拦截器。拦截器的配置如代码17-17所示。
代码17-17  struts.xml中JSF拦截器的配置
<!-- 重写拦截器,将其命名在包myJSF中 -->
<package name="myJSF" extends="JSF-default">
                  <interceptors>
                            <interceptor-stack name="JSFFullStack">
                                     <interceptor-ref name="params" />
                                     <interceptor-ref name="basicStack" />
                                     <interceptor-ref name="JSFStack" />
                            </interceptor-stack>
                  </interceptors>
                  <default-interceptor-ref name="JSFFullStack" />
</package>
接下来配置请 求的Action。
在请求的Action配置中需要继承myJSF拦截器,用来处理JSF页面的组件。
本应用中来自页面的请求共有4种,如下所示。
l         welcome.action:请求显示欢迎页面。配置的 result类型为JSF,使用JSF解析welcome.jsp页面中的组件。
l         view.action:请求显示所有选手列表。配置的result类型为JSF,使用JSF解析view.jsp页面中的组件,显示所有已报名选手的列 表信息。
l         register.action:请求增加选手。配置两种result。
result的name=“JSF”,使用JSF解析register.jsp页面中的组件。
result 的name=“view”、type类型为chain,即增加选手后直接请求显示所有选手类表的view.action。
l         findone.aciton:请求显示修改选手信息
result类型为“JSF”,使用JSF解析 findone.jsp页面中的组件。
result 的name=“view”、type类型为“chain”,即修改选手后直接请求显示所有选手类表的view.action。
struts.xml的详细配置,如代码17-18所示。
代码17-18  struts.xml的详细配置
         <!--定义我们的Action的包,并且要继承myJSF  -->
         <package name="olympic" extends="myJSF">
             <!--首次进入的欢迎页面-->
             <action name="welcome">
                  <result type="JSF"/>
                  </action>
                  <!--显示所有选手--> 
             <action name="view" class="com.sunyang.olympic.OlympicAction">
                            <result name="success" type="JSF" />
                  </action>
                  <!--选手报名-->
                  <action name="register" class="com.sunyang.olympic.OlympicAction">
                            <result name="success" type="JSF" />
                            <result name="view" type="redirect">view.action</result>
                  </action>  
                  <!--修改信息-->
                  <action name="findone" class="com.sunyang.olympic.OlympicAction" method="findone">
                            <result name="success" type="JSF" />
                            <result name="view" type="redirect">view.action</result>
                  </action>                     
         </package>
(3)创建页面。
示例程序共设计4个页面,分述如下。
l         welcome.jsp。欢迎页面。该页面显示两种链接:“我现在就要报名”链接到新增加选手页面;“我想看看都谁报名了”链接到查看所有选手列表信息页 面。
l         register.jsp。增加用户页面。单击欢迎页面的“我现在就要报名”,跳转到本页面。该页面显示增加选手的信息,页面使用JSF输入组件标签,表 单提供用户编号、姓名、年龄、性别与联络方式,所有的信息都由选手填写,而且实现数据验证功能,对于不合法的数据类型同时提供错误信息。
l         view.jsp。查看所有选手列表信息。该页面采用JSF制表标签,循环遍历显示所有选手信息。该页面还提供了另一个链接“这里还没有我”,单击该链接 跳转到增加选手页面。
l         findone..jsp。该页面用来提供选手修改个人信息。
单击查 看所有选手列表信息页面的选手编号,跳转到本页面。本页面采用JSF输入类标签,显示该选手编号对应的详细信息,如选手编号、选手姓名、性 别、年龄及联系方式,供选手修改。修改后单击“我确定修改”,跳转到显示所有选手类表页面。
①欢迎页面welcome.jsp,如代码17-19所示。
代码17-19  welcome.jsp
<%@ page language="java" import="java.util.*" pageEncoding="GBK"%>
<%@ taglib prefix="f" uri="http://java.sun.com/JSF/core" %>
<%@ taglib prefix="h" uri="http://java.sun.com/JSF/html" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>My JSP 'welcome.jsp' starting page</title>
  </head> 
  <body>
   <f:view>
       <h3>奥运啦啦队员海选报名啦!!!</h3>         
       <h3>请选择:</h3>
       <h:outputLink value="register.action">                             
       <h:outputText value="我现在就要报名!!!" />
                          </h:outputLink>
       <h:outputLink value="view.action">                                 
       <h:outputText value="我想看看都谁报名了!!!" />
       </h:outputLink>         
         </f:view>
         </body>
</html>
②增加选手的注册页面register.jsp。
单击“我现在就要报名”跳转到注册页面,这个页面的代码很多,标签中的“value”值就是配置在Action中注入的 player的各种属性值,如代码17-20所示。
代码17-20  register.jsp
<%@ page language="java" contentType="text/html; charset=GBK"%>
<%@ taglib prefix="f" uri="http://java.sun.com/JSF/core" %>
<%@ taglib prefix="h" uri="http://java.sun.com/JSF/html" %>
<html>
         <head>
                <title>注册信息</title>       
         </head>
         <body>
         <f:view> 
       <h3>同一个世界,同一个梦想</h3>  
       <h3>感谢您对奥运的支持,请填写下列信息......</h3>       
       <h:form>                           
                <h:panelGrid columns="3">
                    <h:outputText value="选手编号" />
                          <h:inputText id="id" size="30" value="#{action.player.id}" required="true" />
                          <h:message for="id" />                         
                          <h:outputText value="选手姓名" />
                          <h:inputText id="name" size="30" value="#{action.player.name}"
required="true">
                              <f:validateLength minimum="2" maximum="100" />
                          </h:inputText>
                          <h:message for="name" />                             
                          <h:outputText value="选手性别" />
                          <h:inputText id="sex" size="30" value="#{action.player.sex}" required="true">
                              <f:validateLength minimum="1" maximum="6" />
                          </h:inputText>
                          <h:message for="sex" />
                          <h:outputText value="选手年龄" />
                          <h:inputText id="age" size="30" value="#{action.player.age}" required="true">
                              <f:validateLength minimum="1" maximum="100" />
                          </h:inputText>
                          <h:message for="age" />
                          <h:outputText value="联系方式" />
                          <h:inputText id="tel" size="30" value="#{action.player.tel}" required="true">
                              <f:validateLength minimum="2" maximum="13" />
                          </h:inputText>
                          <h:message for="tel" />
                </h:panelGrid>                   
                <h:commandButton value="报名了" action="#{action.save}" />
                <br/>
       </h:form>
         </f:view>
         </body>
</html>
③查看所有选手信息列表页面view.jsp。
在注册选手页面,填写选手信息后,单击“报名了”跳转到查看所有选手的页面,该页面将所有选手信息遍历显示到 表格中。标签<h:dataTable>用来显示表格,<f:facet>用来显示表头,<h:column>用来 显示表列,详细的设计如代码17-21所示。
代码17-21  view.jsp
<%@ page language="java" contentType="text/html; charset=GBK"%>
<%@ taglib prefix="f" uri="http://java.sun.com/JSF/core" %>
<%@ taglib prefix="h" uri="http://java.sun.com/JSF/html" %>
<html>
         <head>
                <title>查看所有选手报名信息</title> 
         </head>
         <body>
         <f:view>
       <h3>已经有这么多人报名了!!!!!</h3>     
       <h3>这里有我吗?没有请单击加入他们</h3>
       <h:dataTable value="#{action.select}" var="p" style="text-align:center;width:500px"
border="1">
                <h:column>
                          <f:facet name="header">
                                   <h:outputText value="选手编号" />
                          </f:facet>
                          <h:outputLink value="findone.action">
                                   <f:param name="playerid" value="#{p.id}" />
                                   <h:outputText value="#{p.id}" />
                          </h:outputLink>
                </h:column>
                  <h:column>
                          <f:facet name="header">
                                   <h:outputText value="选手姓名" />
                          </f:facet>
                          <h:outputText value="#{p.name}" />
                </h:column>
                  <h:column>
                          <f:facet name="header">
                                   <h:outputText value="选手性别" />
                          </f:facet>
                          <h:outputText value="#{p.sex}" />
                </h:column>
                <h:column>
                          <f:facet name="header">
                                   <h:outputText value="选手年龄" />
                          </f:facet>
                          <h:outputText value="#{p.age}" />
                </h:column>
                <h:column>
                          <f:facet name="header">
                                   <h:outputText value="联系方式" />
                          </f:facet>
                          <h:outputText value="#{p.tel}" />
                </h:column>
       </h:dataTable>   
       <p>         
        <h:outputLink value="register.action">                                    
                                   <h:outputText value="这里还没有我!!" />
                          </h:outputLink>    
       </p>
         </f:view>
         </body>
</html>
④修改选手页面findone.jsp。
单击查看显示所有选手列表页面中的选手编号,跳转到修改选手信息页 面。
在findone.jsp中需要增加一个<h:inputHidden>标签用来隐式的标识“playerid”。将选手编号为“playerid”的属性值显示到页面中。最后提交action的modify方法,详细的设计如 代码17-22所示。
代码17-22  findone.jsp
<%@ page language="java" contentType="text/html; charset=GBK"%>
<%@ taglib prefix="f" uri="http://java.sun.com/JSF/core" %>
<%@ taglib prefix="h" uri="http://java.sun.com/JSF/html" %>
<html>
         <head>
                <title>修改信息</title>       
         </head>
         <body>
         <f:view> 
       <h3>同一个世界,同一个梦想</h3>  
       <h3>感谢您对奥运的支持,请修改下列信息>>></h3>      
       <h:form>
           <h:inputHidden value="#{action.playerid}"/>                           
                <h:panelGrid columns="3">
                <h:outputText value="选手编号" />
                <h:inputText id="id" size="30" value="#{action.player.id}" required="true" />
           <h:message for="id" />                           
                <h:outputText value="选手姓名" />
                <h:inputText id="name" size="30" value="#{action.player.name}" required="true">
                          <f:validateLength minimum="2" maximum="100" />
                          </h:inputText>
                          <h:message for="name" />                             
                          <h:outputText value="选手性别" />
                          <h:inputText id="sex" size="30" value="#{action.player.sex}" required="true">
                              <f:validateLength minimum="2" maximum="6" />
                          </h:inputText>
                          <h:message for="sex" />
                          <h:outputText value="选手年龄" />
                          <h:inputText id="age" size="30" value="#{action.player.age}"
required="true">
                              <f:validateLength minimum="1" maximum="100" />
                          </h:inputText>
                          <h:message for="age" />
                          <h:outputText value="联系方式" />
                          <h:inputText id="tel" size="30" value="#{action.player.tel}" required="true">
                              <f:validateLength minimum="2" maximum="13" />
                          </h:inputText>
                          <h:message for="tel" />
                </h:panelGrid>
                <h3>感谢您对奥运的支持,提交前请确认您的信息</h3>                    
                <h:commandButton value="我确定修改!!!" id="modifyCommand" action=
"#{action.modify}" />
                <br/>                
       </h:form>
         </f:view>
         </body>
</html>
(4)创建JavaBean,包括选手信息类PlayerInfo与控制器类OlympicAction。
①首先创建选手信息类PlayerInfo.java。
该类中定义选手的各种属性,包括id(编号)、name(名称)、age(年龄)、sex(性别)、 tel(联系方式),如代码17-23所示。
代码17-23  PlayerInfo.java
package com.sunyang.olympic;
public class PlayerInfo {
         private int id;
         private String name;
         private int age;
         private String sex;
         private int tel;
        
         //定义默认的构造函数
         public PlayerInfo(){}
         //重写构造函数
         public PlayerInfo(int id,String name,String sex,int age,int tel){
                  this.id=id;
                  this.name=name;
                  this.sex=sex;
                  this.age=age;
                  this.tel=tel;
                 
         }
         //省略属性的getter和setter方法
}
②然后创建控制器类OlympicAction.java。
OlympicAction.java用 来处理增加选手页面、修改选手页面、 显示所有选手列表页面、修改选手信息页面功能的各种请求。该类需要继承ActionSupport,注入选手信息类PlayerInfo对象。添 加处理页面表单的方法如下。
l         预存储数据:本应用没有持久化,因此 这里采用预先填写3条数据,存储在List对象中。
l         增加选手:单击增加选手页面中的“报名了”,触发该方法。本应用中的所有选手信息,除了预先存储的数据以外,新增加的选手数据,均存储在会话 session当中。
l         查询所有选手:单击“我想看看都谁报名了”或是在修改选手页面中更新选手信息后,单击“我确定修改!”时触发此方法,此方法调用存储在List中的数据, 如果会话已经被创建,就返回会话当中的列表List;否则返回预先存储的列表List。
l         查找单个选手:该方法根据页面表单中选手的编号,遍历会话session中存储的选手对象,并将该对象中的数据返回给修改选手信息页面,供选手修改。
l         修改选手信息:当选手在修改信息页面中更新当前信息后, 点击“我确定修改!”提交到本方法。 此方法将根据提交的选手编号,更新存 储在会话session中的对象信息,并跳转到查看所有选手信息列表页面。
具体如代码17-24所示。
代码17-24  OlympicAction.java
package com.sunyang.olympic;
public class OlympicAction extends ActionSupport {
   // 注入选手POJO
   private PlayerInfo player;
   // 实例化选手对象
   public OlympicAction(){
   player=new PlayerInfo(); }
   // 定义选手的id属性,用来接受页面值信息
   private int playerid;
   // 省略他们的getter和setter
   //定义封装选手对象的list                 
   List <PlayerInfo> list=new ArrayList<PlayerInfo>();
   // 硬性地存储3条数据,
   public List<PlayerInfo> setValue(){
            // 定义会话session
            HttpSession session  = ServletActionContext.getRequest().getSession();
                  if(session.getAttribute("player")==null){
                  PlayerInfo no1=new PlayerInfo(2008,"Andy","man",25,1111111111);
                  PlayerInfo no2=new PlayerInfo(2009,"Lily","female",25,22222222);
                  PlayerInfo no3=new PlayerInfo(2010,"Kaka","man",25,1111111111);
                  list.add(no1);
                  list.add(no2);
                  list.add(no3);
                  session.setAttribute("player", list);
                  }      
                  list=(List)session.getAttribute("player"); 
                  return list;
   }
   // 遍历所有的选手并将其传值到页面
         public List<PlayerInfo> getSelect(){                        
                  List listValue=new ArrayList();
                  listValue=setValue();     
                  return list;
         }
         // 增加选手对象
         public String save(){
                  HttpSession session  = ServletActionContext.getRequest().getSession();
                  if(session!=null){                           
                            list=setValue();
                            list.add(player);
                            session.setAttribute("player",list);                           
                  }
                  return "view";
         }
         // 遍历单个选手,并将其值传到页面
         public String findone(){
                  HttpSession session  = ServletActionContext.getRequest().getSession();
                  if(session!=null){
                            list=(List)session.getAttribute("player");
                            for(int i=0;i<list.size();i++){
                                     PlayerInfo p=list.get(i);
                                     if(p.getId()==playerid){
                                              this.player=p;                                         
                                     }                                  
                            }
                  }
                            return "success";
         }
         // 用来修改选手信息
         public String modify(){
                  HttpSession session  = ServletActionContext.getRequest().getSession();
                  if(session!=null){
                            list=(List)session.getAttribute("player");
                            for(int i=0;i<list.size();i++){
                                     PlayerInfo p=list.get(i);
                                     if(p.getId()==player.getId()){
                                              list.remove(p);
                                              list.add(player);
                                     }                                  
                            }
                  }
                  return "view";
         }      
}
(5)配置Web应用文件。
Struts 2中使用的JSF的UI标签、JavaBean的绑定功能,都需要使用JSF的Servlet来处理。因此在Web应用文件中需要配置的JSFSevlet处理.action的所有请求,同时要配置 Struts 2的请求转发。如代码17-25所示。
代码17-25  web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="JSF" version="2.4"
         xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <filter>
        <filter-name>struts</filter-name>
        <filter-class>org.apache.Struts 2.dispatcher.FilterDispatcher</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>struts</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <listener>
        <listener-class>org.apache.myfaces.webapp.StartupServletContextListener</listener-class>
    </listener>
         <!--JSF的servlet -->
         <servlet>
                  <servlet-name>faces</servlet-name>
                  <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
                  <load-on-startup>1</load-on-startup>
         </servlet>
         <!--配置所有的.action的请求都有JSF的servlet处理  -->
                  <servlet-mapping>
                  <servlet-name>faces</servlet-name>
                  <url-pattern>*.action</url-pattern>
         </servlet-mapping>     
</web-app>
(6)最后发布运行。

单击“我想看看都谁报名了”后,进入到查看所有队员信息的页面。
              

单击欢迎页面的“我现在就要表名!!!”或者页面的“这里还没有我”后进入到增加新的啦啦队 选手的页面。
当单击“报名了”后,跳转到查看所有选手信息的页面。
         

单击选手编号,可以修改选手的各项信息。
单击“我确定修改!!!”按钮后跳转到查看所有选手页面。
               

至此,Struts 2和 JSF的整合就完成了,发布运行后,得到预期的效果。但要注意的是,示例中我们将值存储在session会话中,并 没有被真正的持久化,如果要想将数据持久化,就需要增 加持久层及业务层相应代码,这些操作可以参考其它整合持久化框架的章节。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics