struts2

一、       Introduction

Struts2是一个基于MVC设计模式的web应用框架,本质上是一个servlet,发挥了controller的作用来建立模型与视图的数据交互。它是struts的下一代产品,是在struts和webwork的技术基础上进行了合并的全新的struts2框架。在javaweb三层的开发中,web层一般采用servlet,一般的web系统中包含一定量的客户请求,如果使用单个单个的servlet来出理与客户请求的交互,将产生大量的开发量和增大维护的难度。web层框架的出现就是为了解决这个问题,以达到低耦合,高内聚,简开发,易维护的效果。实际上,在web层框架中,采用了控制器模式,将单个单个的servlet的处理交给了框架处理,而在编程上,只需要处理好前端控制器的实现。Struts2框架的前端控制器是过滤器。这个不同于springmvc所采用的是一个总的servlet来控制请求的流程,依次通过处理器映射器、处理器适配器、控制器、视图解析器等实现请求和响应。

二、       基本步骤

1.       创建web项目。

2.       引入struts2的jar包。

3.       编写或引入jsp文件,注意jsp中访问action的写法,后缀名必须为action。

4.       在web.xml中配置前端控制器。

5.       编写action类和方法,方法必须有返回值,且为String类型。如果要转发或重定向,可以设置返回值的字符串,然后在struts.xml中配置result标签。

6.       配置struts.xml文件,必须名字为struts.xml。

7.       测试

8.       例子

创建项目,导入jar包略

Jsp文件

<body>

   <h3>哈哈哈</h3>

   <a href="${pageContext.request.contextPath }/haha.action" >哈哈哈</a>

</body>

web.xml中配置前端控制器的过滤器

  <filter>

      <filter-name>struts2</filter-name>

      <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>

  </filter>

  <filter-mapping>

      <filter-name>struts2</filter-name>

      <url-pattern>/*</url-pattern>

  </filter-mapping>

编写action类

public class HahaAction {

   /**

    * action类中方法的要求

    * 1,必须public

    * 2,返回值必须为字符串,必须有返回类型

    * 3,方法名称任意,但是不能有参数

    */

   public String haha(){

      System.out.println("哈哈");

      return "haah";

   }

}

配置struts.xml

<?xml version="1.0"encoding="UTF-8" ?>

<!DOCTYPE strutsPUBLIC

"-//ApacheSoftware Foundation//DTD Struts Configuration 2.3//EN"

"http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>

      <!-- 配置包结构

         使用默认的包管理action

       -->

      <package name="default"namespace="/" extends="struts-default">

          <!-- 配置action

          name:代表访问源的.action的名字,如haha.action,则name="haha"

          class:代表要访问的action类的全路径

          method:代表要访问的action类的方法的名字

          -->

          <action name="haha" class="com.struts2.action.HahaAction"method="haha" />

         <!-- 配置跳转页面,在这个action里面配置,result,底层通过反射实现,路径的写法,不管是转发还是重定向,都不要写项目名 -->

             <result name="haah">/jsp/haha.jsp</result>

      </package>

</struts>

测试略。

三、       Struts2的执行流程

在B/S框架中,当启动服务器的时候,会加载web.xml文件,文件中配置的struts2的核心过滤器就会被创建,init()方法执行,加载相关的配置文件,其中就包括struts.xml。

当请求达到服务器端后,在web.xml中的执行顺序是:listener---》filter---》struts拦截器---》servlet。当请求执行到struts拦截器的时候,实际上也是一个filter,会经过核心过滤器,也可以认为是前端控制器,StrutsPrepareAndExecuteFilter的类。然后,会执行struts2框架提供的很多拦截器filter,等这些拦截器执行完毕,就执行struts.xml,找到请求的路径,进而找到类,找到方法,通过反射的方式执行,如果return不为空,则根据strut.xml中的配置执行result跳转页面。

Struts2不同于springmvc中,是通过一个前端控制器的servlet,根据映射器处理器,找到controller处理器中映射的具体的方法,进而处理请求。可以认为二者的实现机制不同,struts2依赖于拦截器,而springmvc则依靠一个总的前端控制器的servlet。不同的文件配置也使得在具体的请求处理上,struts2每次都要访问action类,然后找到具体的方法,这使得同一个请求可以共用一些类级别的全局变量,然后也削弱了性能。而springmvc的url映射直接对应某个方法,在粒度上更细。

四、       Struts2框架配置文件的加载顺序

Struts2框架的核心是StrutsPrepareAndExecuteFilter过滤器,主要有两个功能:prepare,预处理,加载核心的配置文件;execute,执行,执行一部分拦截器。

1.       StrutsPrepareAndExecuteFilter过滤器加载的配置文件和顺序。

顺序

方法

加载的文件

1

init_DefaultProperties()

org/apache/struts2/default.properties

2

init_TraditionalXmlConfigurations()

struts-default.xml,struts-plugin.xml,struts.xml

3

init_LegacyStrutsProperties()

struts.properties

4

init_CustomConfigurationProviders()

用户自定义的配置提供者

5

init_FilterInitParameters()

web.xml

2.       重点配置文件的说明

default.properties

在org/apache/struts/目录下,代表配置的是struts2的常量的值

struts-default.xml

在struts2的核心包下,代表struts2核心功能的配置,如bean,拦截器,结果类型等

struts.xml

非常重要,代表web应用的默认配置,开发中,基本靠配置这个文件实现功能。可用来配置常量。

web.xml

配置前端控制器,可以用来配置常量

注意:在所有的配置文件中,前3个配置文件(default.properties,struts-default.xml,struts-plugin.xml)是struts2框架的默认配置文件,基本不需要修改。后3个配置文件(struts.xml,struts.properties,web.xml)可以修改struts2的常量,而且对于同样的常量,后加载的会覆盖先加载的。在开发中,基本上是在struts.xml中配置相关常量。

五、       struts.xml配置文件的配置

1.       <package>标签

name

包的名称,需要是唯一的,用来管理这个包的action配置

extends

继承,可以继承其他的包,就包含了继承的包的功能,一般使用struts-default。

namespace

名称空间用来约束action的访问路径,和<action>标签中的name一起形成访问路径。

如:namespace=”/”,表示根名称空间,即从项目名开始;namespace=”/haha”带有名称的,即表示项目名/haha/。

abstract

抽象的。表示被继承的。在java的接口有类似的概念。这个属性很少使用,值如果是true,表示包可以被继承。

2.       <action>标签

name

和<package>标签的namespace属性一起形成访问路径。

class

配置action类的全路径。默认值是ActionSupport类。

method

Action类中执行的方法,如果不指定,默认值是execute。

关于method默认值的例子:

如果在struts.xml中的action中没有配置method的值,则默认就是method=“execute”。

在action类中编写一个execute方法,当发起访问这个没有设置method值的action访问路径的请求时,就会执行这个action类中自编写的execute方法。

<action name="haha"class="com.struts2.action.HahaAction"  >

<!-- 配置跳转页面,在这个action里面配置,result,底层通过反射实现,路径的写法,不管是转发还是重定向,都不要写项目名 -->

       <result name="haah">/jsp/haha.jsp</result>

</action>
   public String execute(){

      System.out.println("默认值");

      return null;

   }

3.       <result>标签

name

返回结果的跳转视图的名称。

type

结果类型。默认值是转发,可以设置其他值。

注意:在一个action中可以配置多个result。

六、       配置struts2的常量

可以配置struts2常量的三个文件:struts.xml,struts.properties,web.xml。一般在struts.xml和web.xml中配置。相同的配置,后加载的覆盖先加载的。

1.       在struts.xml中配置常量

使用<constant name=”key” value=”value”></constant>

例子:

       <!-- 配置常量 -->

       <constant name="struts.action.extension" value="haha,,"></constant>

2.       在web.xml中配置常量

方式是在前端控制器的过滤器中配置初始化参数。

例子:

  <filter>

      <filter-name>struts2</filter-name>

      <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>

      <init-param>

          <param-name>struts.action.extension</param-name>

          <param-value>haha,,</param-value>

      </init-param>

  </filter>

3.       常用的常量

struts.i18n.encoding=UTF-8

指定post请求的默认编码集,相当于request.setCharacterEncoding()方法。

struts.action.extension=action,,

指定struts2处理的请求的后缀名,默认为action,即匹配*.action。如果需要指定多个请求后缀,则多个后缀之间用,隔开,如=action,haha,hei,

struts.objectFactory.spring.autWire=true

设置整合到spring时用。

struts.multipart.maxSize=2097152

文件上传最大尺寸。

struts.multipart.saveDir=

临时文件的默认存储目录。

struts.configuration.browserCache=true

指定浏览器是否缓存静态内容,默认是true。开发时一般关闭。

struts.enable.DynamicMethodInvocation=false

指定是否采用动态方法方式。

struts.devMode=false

开发模式是否开启。

struts.configuration.xml.reload=false

指定当struts配置文件修改后,是否重新加载该文件,默认是false。

七、       分解struts.xml文件的方式

在有规模的应用开发中,为了避免struts.xml文件过于庞大,臃肿,提高可读性,可以将struts.xml分解为多个配置文件。然后在struts.xml中使用<include>标签引入其他struts_xx.xml文件。

例子:

<struts>

       <include file="com/struts/user/struts_haha.xml" />

</struts>

八、       Action类的三种编写方式

(一)            Action类就是一个pojo类

Pojo类,plain ordinary   java object,简单的java对象。没有继承某个类,没有实现接口的类。开发中不常用。

例子:

public class HahaAction {

   /**

    * action类中方法的要求

    * 1,必须public

    * 2,返回值必须为字符串,必须有返回类型

    * 3,方法名称任意,但是不能有参数

    */

   public String haha(){

      System.out.println("哈哈");

      return "haah";

   } 

   public String execute(){

      System.out.println("默认值");

      return null;

   }

}

(二)            Action类实现Action接口

Action定义了5个常量,5个常量对应5个逻辑常量视图跳转页面,还定义了一个execute方法。

static java.lang.String

ERROR

The action execution was a failure.

static java.lang.String

INPUT

The action execution require more input in order to succeed.

static java.lang.String

LOGIN

The action could not execute, since the user most was not logged in.

static java.lang.String

NONE

The action execution was successful but do not show a view.

static java.lang.String

SUCCESS

The action execution was successful.

例子:

编写action类实现Action接口

public class ActionTest1 implements Action{

   public String execute() throws Exception {

      System.out.println("实现了action的接口");

      //returnSUCCESS,相当于return "success";

      return SUCCESS;

   } 

}

配置action标签

          <action name="haha2" class="com.struts2.action.ActionTest1">

             <result name="success">/jsp/haha.jsp</result>

          </action>

(三)            Action类可以去继承ActionSupport类

开发中使用这个方法最多。它既有Action接口的方法,也有自己的一些方法。

例子:

编写action类继承actionsupport类。

public class ActionTest2 extends ActionSupport{

      @Override

      public String execute() throws Exception {

         System.out.println("继承了actionSupport类");

         return NONE;

      }

}

配置action

          <!-- 继承actionSupport类的方式 -->

          <action name="haha3" class="com.struts2.action.ActionTest2">

             <result name="none">/jsp/haha.jsp</result>

          </action>

九、       Action的访问方式

1.       传统的配置文件的方法。通过<action>标签中的method属性,访问Action类中具体的方法。

例子:

编写jsp页面

<body>

   <a href="${pageContext.request.contextPath }/queryUser.haha">查询用户</a><br />

   <a href="${pageContext.request.contextPath }/addUser.haha">添加用户</a>

</body>

编写action类

public class UserAction extends ActionSupport{

   public String query(){

      System.out.println("查询用户");

      return null;

   }

   public String add(){

      System.out.println("添加客户");

      return null;

   }

}

配置action

      <package name="haha"namespace="/" extends="struts-default">

          <action name="queryUser" class="com.struts2.action.user.UserAction"method="query"></action>

          <action name="addUser" class="com.struts2.action.user.UserAction"method="add"></action>

      </package>

使用传统的方式,配置action。每次访问一个method,都要配置这个method的类,这繁琐了开发,困难了维护。

2.       通配符的方式

访问的路径和方法的名称有某种联系。通配符就是用*代表任意的字符。

使用通配符可以简化配置文件的代码编写,而且易于扩展和维护。

例子:

编写jsp页面,访问路径请使用:共用的名称_区分名称.后缀名

   <a href="${pageContext.request.contextPath }/user_query.haha">查询用户</a><br />

   <a href="${pageContext.request.contextPath }/user_add.haha">添加用户</a>

编写action类

public class UserAction2 extends ActionSupport{

   public String query(){

      System.out.println("通配符查询用户");

      return "queryHaha";

   }

   public String add(){

      System.out.println("通配符添加客户");

      return "addHaha";

   }

}

配置action

          <!-- 通配符的方式

             {1}代表请求过来的路径中的第一个*对应的值,依次类推

          -->

          <action name="user_*" class="com.struts2.action.user.UserAction2"method="{1}">

             <result name="queryHaha">/jsp/haha.jsp</result>

             <result name="addHaha">/jsp/haha.jsp</result>

          </action>

3.       动态方法访问的方式

有的开发中使用。如果使用这个方式,需要开启一个常量,struts.enable.DynamicMethodInvocation= false,把值设置为true。

在struts.xml中开启该常量。<constant name=”struts.enable.DynamicMethodInvocation” value=”true”></constant>

例子:

开启动态方法的常量。

<constantname=”struts.enable.DynamicMethodInvocation” value=”true”></constant>

Jsp页面,访问路径,请使用action中name!action类中的方法.后缀名

   <a href="${pageContext.request.contextPath }/user!query.haha">查询用户</a><br />

   <a href="${pageContext.request.contextPath }/user!add.haha">添加用户</a>

编写action类

public class UserAction3 extends ActionSupport{

   public String query(){

      System.out.println("动态方法查询用户");

      return "queryHaha";

   }

   public String add(){

      System.out.println("动态方法添加客户");

      return "addHaha";

   }

}

配置action

          <!--

             动态方法访问的方式

             只需要配置访问路径中共用的名称。

           -->

          <action name="user" class="com.struts2.action.user.UserAction3">

              <result name="queryHaha">/jsp/haha.jsp</result>

              <result name="addHaha">/jsp/haha.jsp</result>

           </action>

十、       Struts2初步整合Hibernate

具体步骤:

1.       创建项目

2.       导入struts2和hibernate的jar包

3.       创建用于orm的pojo类

4.       创建hibernateUtil工具类

5.       配置hibernate的核心配置文件hibernate.cfg.xml

6.       配置orm文件

7.       配置web.xml的struts2的前端控制器

8.       依次编写jsp,action类,service层和dao层。

9.       配置struts.xml文件

10.    测试

十一、           Struts2中使用servlet的API

在Action类中可以获取到Servlet的一些常用的API。Struts2提供了两种方式。

(一)            完全解耦合的方式

Struts2提供了一个类,ActionContext类,该类提供了一些方法可以获取Servlet的API。

一些方法的列表

static  ActionContext  getContext()

获取ActionContext对象实例

java.util.Map<java.lang.String,java.lang.Object>  getParameters()

获取请求参数,相当于request.getParameterMap();

java.util.Map<java.lang.String,java.lang.Object>  getSession()

获取代表session域的Map集合,相当于操作session。

java.util.Map<java.lang.String,java.lang.Object>  getApplication()

获取代表application域的Map集合。

void  put(java.lang.String key, java.lang.Object value)

向request域中存入值。

例子:

Jsp页面

<body>

   <form action="${ pageContext.request.contextPath }/regist.haha" method="post">

                姓名:<input type="text" name="username"/><br/>

                密码:<input type="password" name="password"/><br/>

          <input type="submit"value="注册" />

    </form>

</body>

Action类

public class RegistAction extends ActionSupport{

   public String regist(){

      System.out.println("haha");

      ActionContext context=ActionContext.getContext();

      Map<String,Object> map=context.getParameters();

      Set<String> keys=map.keySet();

      for(String key:keys){

         String[] v=(String[])map.get(key);

         System.out.println(key+":"+Arrays.toString(v));

      }

      context.getSession().put("hh", "会话");

      context.getApplication().put("hk", "后k");

      //向request域存值

      context.put("kk","kkk");

      return SUCCESS;

   }

}

struts.xml

       <package name="haha2" namespace="/"extends="struts-default">

           <action name="regist"class="com.struts2.action.RegistAction" method="regist">

               <result name="success">/jsp/haha.jsp</result>

           </action>

       </package>

(二)            使用原生的servlet的API的方式

Struts2框架提供了一个类,ServletActionContext,有一些静态的方法。

static ActionContext

getActionContext(javax.servlet.http.HttpServletRequest req)

Gets the current action context

static ActionMapping

getActionMapping()

Gets the action mapping for this context

static javax.servlet.jsp.PageContext

getPageContext()

Returns the HTTP page context.

static javax.servlet.http.HttpServletRequest

getRequest()

Gets the HTTP servlet request object.

static javax.servlet.http.HttpServletResponse

getResponse()

Gets the HTTP servlet response object.

static javax.servlet.ServletContext

getServletContext()

Gets the servlet context.

static ValueStack

getValueStack(javax.servlet.http.HttpServletRequest req)

Gets the current value stack for this request

static void

setRequest(javax.servlet.http.HttpServletRequest request)

Sets the HTTP servlet request object.

static void

setResponse(javax.servlet.http.HttpServletResponse response)

Sets the HTTP servlet response object.

static void

setServletContext(javax.servlet.ServletContext servletContext)

Sets the current servlet context object

例子:

Jsp和struts.xml同上,略

Action类

public class RegistServletAction extends ActionSupport{

   public String regist(){

      HttpServletRequest request=ServletActionContext.getRequest();

      request.getSession().setAttribute("hh", "看看");

      ServletActionContext.getServletContext().setAttribute("kl", "看看了");

      HttpServletResponse response=ServletActionContext.getResponse();

      return SUCCESS;

   }

}

十二、           Struts2处理结果页面跳转

1.       结果页面的两种形式

根据action返回的结果的一致性与否,将结构页面分为全局结果页面和局部结果页面。

1)       全局结果页面:如果<package>包中的一些Action都返回同一个值,并且这个值都指向同一个JSP页面,这个jsp页面就是全局结果页面。

全局结果页面针对当前的包中的所有action,如果存在有局部页面跳转的,则使用局部跳转结果不使用全局跳转结果。

例子:

           <global-results>

              <result name="success">/jsp/haha.jsp</result>

              <result name="fail">/jsp/regist.jsp</result>

          </global-results>

2)       局部结果页面:即只有一个action跳转到这个结果页面。局部结果页面的优先级高于全局结果页面。

例子:

       <package name="haha2" namespace="/"extends="struts-default">

           <global-results>

              <result name="success">/jsp/haha.jsp</result>

              <result name="fail">/jsp/regist.jsp</result>

          </global-results>

           <action name="user_*"class="com.struts2.action.RegistServletAction" method="{1}">

           </action>

           <action name="user_regist"class="com.struts2.action.RegistServletAction"method="regist">

               <result name="success">/jsp/heihei.jsp</result>

           </action>

       </package>

2.       结果页面的类型

结果页面使用<result>标签,具有两个属性。name,逻辑视图的名称,即action类中return的值。type,跳转类型。可以到struts-default.xml中查找全部类型。

常用结果页面类型有:

dispatcher

转发。type的默认值即为dispatcher。可以从action类转到jsp。

redirect

重定向。从action定向到jsp。

chain

多个action之间的跳转,从一个action转发到另一个action。

redirectAction

多个action之间的跳转,从一个action重定向到另一个action。

stream

stream。用于下载文件。

重定向例子:

           <global-results>

              <result name="success" type="redirect">/jsp/haha.jsp</result>

              <result name="fail">/jsp/regist.jsp</result>

          </global-results>

重定向action的例子:

Action类

public class RedirectActionTest extends ActionSupport{

   public String haha(){

      System.out.println("haha");

      return SUCCESS;

   }

   public String redirect(){

      System.out.println("重定向过来");

      return NONE;

   }

}

配置文件

           <action name="redirectAction_*"class="com.struts2.action.RedirectActionTest"method="{1}">

               <result name="success"type="redirectAction">redirectAction_redirect</result>

           </action>

十三、           Struts2的数据封装

(一)            Struts2封装数据的两种方式

在struts2框架,请求的处理流程中,当请求到达struts2的过滤器后就执行一些拦截器,这些拦截器负责各种处理,如类型转换,字符编码。其中有一个拦截器负责封装请求的数据,如果在action类中设置set和get方法,那么这个拦截器可以通过调用set、get方法将参数封装进去。

按照struts2要求的编写action类的set和get的方法,通过拦截器就可以实现数据的封装。Struts2提供了两种数据封装的方式。

1.       属性驱动

属性驱动分为两种方式:

1)       提供对应属性的set方法进行数据的封装。

表单中的哪些数据需要封装,那么就在对应的action类中提供该属性的set方法。当表单的数据提交到action类,通过action中的setXxx方法,赋值给作为全局变量的属性。

这种方式的特点:

A.      采用拦截器帮助封装数据。

B.       有缺点,如果属性很多,需要提供很多set方法,而且要手动将数据存入对象。

C.       Action类,兼具了javabean的功能,违背了mvc思想模式,有抬高耦合性的风险。

例子:

编写jsp页面

<body>

   <form action="${ pageContext.request.contextPath }/user_registField1.haha" method="post">

                姓名:<input type="text" name="username"/><br/>

                密码:<input type="password" name="password"/><br/>

                年龄:<input type="text" name="age"/><br/>         

          <input type="submit"value="注册" />

    </form>

</body>

创建action类,将表单中需要传入的name的值作为类的属性并设置set方法。

public class RegistAction1 extends ActionSupport{

   private String username;

   private String password;

   private Integer age; 

   public voidsetUsername(String username){

      this.username = username;

   }

   public voidsetPassword(String password){

      this.password = password;

   }

   public voidsetAge(Integer age){

      this.age = age;

   }

   public String registField1(){

      System.out.println("执行了"+username+"--"+password+"--"+age);

      return null;

   }

}

2)       在jsp页面上,使用OGNL表达式进行封装数据

在jsp页面中使用OGNL表达式,可以直接将属性封装到一个javaBean的对象中。需要编写一个javabean,并提供set和get方法。Jsp页面的编写,使用OGNL表达式,形式如:<input type=”text” name=”user.username”/>,注意javabean的属性与表单name的一一对应。

特点:

A.      除了javabean需要提供set方法外,在action类中需要提供这个javabean类型的属性的get和set方法。

B.       执行action类时,会调用属性的get方法,判断是否有javabean类的属性的实例对象,如果没有,则调用set方法把拦截器创建的对象注入action类。依次将表单的值放入javabean对象。

例子:

编写jsp页面,使用OGNL表达式为表单的name赋值

<body>

   <form action="${ pageContext.request.contextPath }/user_registField2.haha" method="post">

                姓名:<input type="text" name="user.username"/><br/>

                密码:<input type="password" name="user.password"/><br/>

                年龄:<input type="text" name="user.age"/><br/>         

          <input type="submit"value="注册" />

    </form>

</body>

创建action类

public class RegistAction2 extends ActionSupport{

   private User user;

   public User getUser() {

      return user;

   }

   public voidsetUser(User user){

      this.user = user;

   }

   public String registField2(){

      System.out.println("执行了"+user);

      return null;

   }

}

2.       模型驱动

使用模型驱动,也是将表单中的数据直接封装到一个javabean的对象中,表单的写法不需要改变。实例化javabean类作为action类的属性。需要创建action的时候实现ModelDriven<T>接口,实现getModel()方法,在getModel()方法中返回javabean的实例对象。

例子:

编写jsp页面

<body>

   <form action="${ pageContext.request.contextPath }/user_registModel.haha" method="post">

                姓名:<input type="text" name="username"/><br/>

                密码:<input type="password" name="password"/><br/>

                年龄:<input type="text" name="age"/><br/>         

          <input type="submit"value="注册" />

    </form>

</body>

创建action类

public class RegistAction3 extends ActionSupport implementsModelDriven<User>{

   private User user=new User();

   public User getModel() {

      return user;

   }

   public String registModel(){

      System.out.println("执行了"+user);

      return null;

   }

}

(二)            将数据封装到集合中的方法

封装数据到集合中采用的是属性驱动中OGNL表达式的方式。

1.       将数据封装到List集合中

在action类中声明一个以数据pojo类为泛型的list集合的属性,创建set和get方法。在jsp页面,利用action类中集合属性的下标和泛型的属性为name赋值。

例子:

Jsp页面

<body>

   <form action="${ pageContext.request.contextPath }/user_registFieldList.haha" method="post">

                姓名:<input type="text" name="ulist[0].username"/><br/>

                密码:<input type="password" name="ulist[0].password"/><br/>

                年龄:<input type="text" name="ulist[0].age"/><br/> 

               

                姓名:<input type="text" name="ulist[1].username"/><br/>

                密码:<input type="password" name="ulist[1].password"/><br/>

                年龄:<input type="text" name="ulist[1].age"/><br/>        

          <input type="submit"value="注册" />

    </form>

</body>

创建action类

public class RegistAction4 extends ActionSupport{

   private List<User> ulist;

   public List<User> getUlist() {

      return ulist;

   }

   public voidsetUlist(List<User> ulist) {

      this.ulist = ulist;

   }



   public String registFieldList(){

      for(User u:ulist){

         System.out.println(u);

      }

      return null;

   }

}

2.       将数据封装到Map集合中

在action类中声明一个以数据pojo类为泛型的Map属性,创建set和get方法。在jsp页面,利用action类中集合属性的下标(属性的下标可以自定义,主要作为区分的作用)和泛型的属性为name赋值。

Jsp页面

<body>

   <form action="${ pageContext.request.contextPath }/user_registFieldMap.haha" method="post">

                姓名:<input type="text" name="umap['1'].username"/><br/>

                密码:<input type="password" name="umap['1'].password"/><br/>

                年龄:<input type="text" name="umap['1'].age"/><br/> 

               

                姓名:<input type="text" name="umap['2'].username"/><br/>

                密码:<input type="password" name="umap['2'].password"/><br/>

                年龄:<input type="text" name="umap['2'].age"/><br/>        

          <input type="submit"value="注册" />

    </form>

</body>

Action类

public class RegistAction5 extends ActionSupport{

   private Map<String,User> umap;

   public Map<String, User> getUmap() {

      return umap;

   }

   public voidsetUmap(Map<String, User> umap) {

      this.umap = umap;

   }

   public String registFieldMap(){

      System.out.println(umap);

      return null;

   }

}

十四、           Struts2的拦截器技术

1.       拦截器简介

拦截器,interceptor,是AOP的一种实现。AOP,面向切面编程。拦截器指某个方法或者字段在被访问之前,加入某些操作。

在struts2中,拦截器对action类的某些方法进行拦截,不能拦截jsp。

拦截器与过滤器的区别:

1)       过滤器基于函数回调。过滤器过滤的是从客服端发送的请求,在请求的流程中,相关的资源都可以进行过滤,如jsp、servlet、url、js、css等。过滤器依赖于servlet容器。

2)       拦截器基于反射机制,拦截器只对action其作用。

拦截器运行模式:拦截器采用责任链模式,在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。责任链的每一个节点,都可以继续调用下一个节点,也可以阻止流程继续执行。在struts2中可以定义很多个拦截器,将多个拦截器按照特定顺序组成拦截器栈。

Struts2的运行流程:当服务器开启的时候,struts2相关的配置文件解析加载完毕,如struts.xml等。并将配置文件交给Configuration Manager类管理。当客户端发起请求后,请求到达服务器,形成一个HttpServletRequest对象,然后根据struts2的过滤器经由ActionMapper,结合配置文件管理类生成ActionProxy对象。接下来,就开始经由ActionInvocation对象来管理流程经过拦截器栈,当拦截器执行完毕,然后执行委托对象,即真正的action对象,结束后形成结果视图,再经由拦截器后,最后,形成响应。

2.       自定义拦截器和配置拦截器

Struts2提供了Interceptor接口。

Interceptor接口的方法列表。

void

destroy()

Called to let an interceptor clean up any resources it has allocated.

void

init()

Called after an interceptor is created, but before any requests are processed using intercept , giving the Interceptor a chance to initialize any needed resources.

java.lang.String

intercept(ActionInvocation invocation)

Allows the Interceptor to do some processing on the request before and/or after the rest of the processing of the request by the ActionInvocation or to short-circuit the processing and just return a String return code.

一般通过继承Interceptor接口的实现类的方式自定义拦截器。常用的实现类有:AbstractInterceptor,MethodFilterInterceptor等。

配置拦截器有两种方式,第一种,在struts.xml中声明一个拦截器,使用<interceptor>标签,然后在需要拦截的action标签中引入这个拦截器。第二种,自定义配置拦截器栈,引入自定义的拦截器。如果使用了自定义的拦截器或者拦截器栈,需要手动引入默认的拦截器栈,否则不执行默认的拦截器栈,导致失去很多重要的功能,如封装数据,设置编码等。

自定义拦截器的例子:

编写Action类

public class InterceptorAction1 extends ActionSupport{

   public String interceptor1(){

      System.out.println("测试拦截器");

      return NONE;

   }

}

编写自定义拦截器

public class Interceptor1 extends AbstractInterceptor{

   public String intercept(ActionInvocation invocation) throws Exception {

      System.out.println("action方法之前");

      String result=invocation.invoke();

      System.out.println("action方法之后");

      return result;

   } 

}

配置拦截器

       <package name="haha3" namespace="/"extends="struts-default">

           <!-- 声明一个拦截器 -->

           <interceptors>

               <interceptor name="interceptor1"class="com.struts2.interceptor.Interceptor1"></interceptor>

           </interceptors>

           <action name="inter_*"class="com.struts2.action2.InterceptorAction1"method="{1}">

               <!-- 引入拦截器 -->

               <interceptor-ref name="interceptor1"></interceptor-ref>

               <!-- 引入默认的拦截器栈 -->

               <interceptor-ref name="defaultStack"></interceptor-ref>

           </action>

       </package>

使用配置自定义拦截器栈的例子:

Action类和拦截器类同上。

配置拦截器栈。

       <package name="haha3" namespace="/"extends="struts-default">

           <!-- 声明一个拦截器 -->

           <!--<interceptors>

               <interceptorname="interceptor1"class="com.struts2.interceptor.Interceptor1"></interceptor>

           </interceptors> -->

           <!-- 自定义一个拦截器栈 -->

           <interceptors>

               <interceptor name="interceptor1"class="com.struts2.interceptor.Interceptor1"/>

               <interceptor-stack name="interceptorStack1">

                   <interceptor-ref name="interceptor1"></interceptor-ref>

                   <interceptor-ref name="defaultStack"></interceptor-ref>

               </interceptor-stack>

           </interceptors>

           <action name="inter_*"class="com.struts2.action2.InterceptorAction1"method="{1}">

               <!-- 引入拦截器栈 -->

               <interceptor-ref name="interceptorStack1"></interceptor-ref>         

           </action>

       </package>

3.       使用拦截器实现登录认证

自定义拦截器

/**

 * 判断应用系统是否登录,如果登录调到主页,没有登录,跳到登录页面。

 * @author Administrator

 *

 */

public class UserInterceptor extendsMethodFilterInterceptor{

   protected String doIntercept(ActionInvocation invocation) throws Exception {

      User user=(User)ServletActionContext.getRequest().getSession().getAttribute("user");

      if(user==null){

         //如果为空,没有登录,返回字符串,则不会继续执行请求。

         return "login";

      }

      return invocation.invoke();

   } 

}

编写登录action

public class UserAction extends ActionSupport{

   UserService us=new UserServiceImpl();

   public String login(){

      HttpServletRequest request=ServletActionContext.getRequest();

      Map<String,String[]>map=request.getParameterMap();

      User user=new User();

      User userExist=null;

      try {

         BeanUtils.populate(user, map);

         userExist=us.login(user);

         if(userExist!=null){

            request.getSession().setAttribute("user", userExist);

            return "index";

         }

         request.setAttribute("msg", "用户名或密码错误");

         return "login";

      } catch (Exception e) {

         e.printStackTrace();

      }

      request.setAttribute("msg", "系统繁忙,请稍后再试");

      return "login";

   }

}

配置拦截器

       <package name="hhh" namespace="/"extends="struts-default">

           <!-- package中的标签请按照一定的顺序配置 -->

           <interceptors>

               <interceptor name="login"class="com.haha.interceptor.UserInterceptor"></interceptor>

           </interceptors>

           <global-results>

               <result name="login">/login.jsp</result>

           </global-results>

           <action name="user_*"class="com.haha.action.UserAction" method="{1}">

               <result name="index">/index.jsp</result>

               <!-- <result name="login">/login.jsp</result>-->

               <!-- 引入拦截器,请手动配置默认拦截器栈 -->

               <interceptor-ref name="login">

                   <!-- 配置不拦截的方法,为登录action放行 -->

                   <param name="excludeMethods">login</param>

               </interceptor-ref>

               <interceptor-ref name="defaultStack"></interceptor-ref>

           </action>

           <action name="customer_*"class="com.haha.action.CustomerAction" method="{1}">

               <result name="saveSuccess"type="redirectAction">customer_list</result>

               <result name="listSuccess">/jsp/customer/list.jsp</result>

               <!-- 任何的系统操作都进行登录认证 -->

               <interceptor-ref name="login">

                   <!-- 配置不拦截的方法,为登录action放行 -->

                   <param name="excludeMethods">login</param>

               </interceptor-ref>

               <interceptor-ref name="defaultStack"></interceptor-ref>

           </action>

       </package>

十五、           Struts2的OGNL表达式

1.       OGNL概述

Struts2提供了值栈,把查询的数据存入到值栈中,转发到JSP页面上,在jsp页面上就可以从值栈中获取值。

OGNL是Object  Graphic Navigation  Language的缩写。所谓对象图,即以任意一个对象为根,通过OGNL可以访问这个对象相关联的其他对象。

OGNL是一种功能强大的表达式语言,通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。它使用相同的表达式去存取对象的属性。它比EL强大。它本来也是一种单独的语言。Struts2觉得它好用,就把它搞成了自己的一个部分。

OGNL的五大功能:支持对象方法调用;支持类静态的方法调用和值访问;访问OGNL上下文(OGNL context)和ActionContext;支持赋值操作和表达式串联;操作值对象。

存取值的例子:

   public voidtest1() throwsOgnlException{

      //ognl上下文对象

      OgnlContext context=new OgnlContext();

      //获取根对象

      Object root=context.getRoot();

      //存储数据

      context.put("hah","hah好");

      //获取值

      Object value=Ognl.getValue("#hah",context,root);

      System.out.println(value);

   }

使用OGNL调用方法的例子:

   public voidtest2() throwsOgnlException{

      //ognl上下文对象

      OgnlContext context=new OgnlContext();

      //获取根对象

      Object root=context.getRoot();

      //存储数据

      context.put("hah","hah好");

      //获取值

      Object value=Ognl.getValue("'hehi看看'.length()",context,root);

      System.out.println(value);

   }

使用OGNL获取root栈的值

   public voidtest3() throwsOgnlException{

      //ognl上下文对象

      OgnlContext context=new OgnlContext();

      User u=new User();

      u.setUsername("hhaa");

      context.setRoot(u);

      String name=(String) Ognl.getValue("username",context,context.getRoot());

      System.out.println(name);

   }

2.       Jsp页面使用OGNL表达式

步骤:

1)       引入struts2的标签库

<%@taglib prefix="s" uri="/struts-tags" %>

2)       使用struts2的标签库

例子:

<%@ page language="java" contentType="text/html;charset=utf-8"

    pageEncoding="utf-8"%>

<%@ taglib prefix="s" uri="/struts-tags"%>

<html>

<head>

<meta http-equiv="Content-Type"content="text/html; charset=utf-8">

<title>Insert title here</title>

</head>

<body>

   <h2>从jsp页面中获取值栈中已经存的值</h2>

   <!-- 使用property标签从值栈中取值 -->

   <s:property value="username"/>

</body>

</html>

十六、           Struts2的值栈

1.       什么是值栈

值栈相当于struts2框架的数据的中转站,可以向值栈中存入一些数据,从值栈中获取这些数据。Struts2提供了ValueStack接口,及其实现类OgnlValueStack,来操作值栈。在struts2中Action是多例的,有一个请求,就创建一个Action实例,创建一个ActionContext对象,代表的是Action的上下文对象,还会创建一个ValueStack对象。Struts2框架把ValueStack对象保存在名为”struts.valueStack”的请求属性中,Request中(值栈对象是request的一个属性)。比如:ValueStackvs=(ValueStack)request.getAttribute(“struts.valueStack”);

获取valueStack实例对象的例子:

public class ValueStackAction extends ActionSupport{

   public String execute() throws Exception {

      HttpServletRequest request=ServletActionContext.getRequest();

      ValueStack vs1=(ValueStack)request.getAttribute("struts.valueStack");

      System.out.println(vs1);

      return NONE;

   }

}

2.       值栈的内部结构

值栈由两部分组成:root栈和context栈。root,struts2通过root把动作和相关对象压入ObjectStack中。Root本质上是一个list集合。Context,struts2通过context把各种各样的映射关系(一些map类型的对象)压入contextMap中。

默认情况下,struts2会把以下映射压入ContextMap中。

parameters

该Map中包含当前请求的参数。比如name=xxx&password=xxx

request

其中包含当前request对象的所有属性

session

其中包含session对象中的所有属性

appli cation

其中包含application对象中的所有属性

attr

全域查找,该Map按如下顺序来检索某个属性:request,session,application

注意:request代表的Map集合的key值,value的值其实也是一个Map集合。

ValueStack中存在root属性(CompoundRoot)、context属性(OgnlContext)。CompoundRoot就是ArrayList。OnglContext就是Map。

OGNL表达式访问值栈中的数据:访问root栈中数据时不需要加#,访问context栈中的数据时需要加#。一般讲操作值栈,默认情况下就是操作root元素。

3.       值栈的创建以及值栈和ActionContext对象的关系

值栈对象是请求时创建的。

ActionContext是绑定到当前的线程上的,在每个拦截器或者Action中获取到的ActionContext是同一个。

ActionContext中存在一个Map集合,该Map集合和ValueStack的context是同一个地址。

ActionContext中可以获取到ValueStack的引用,以后再开发,使用ActionContext来获取到值栈对象。

请查看源代码理解ValueStack和ActionContext的关系。

当执行struts2的核心过滤器的时候,在doFilter方法中,有一个prepare.createActionContext(request,response);的方法。

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException,ServletException {        try {

            if (excludedPatterns != null&& prepare.isUrlExcluded(request,excludedPatterns)){

                chain.doFilter(request, response);

            } else {

                prepare.setEncodingAndLocale(request, response);

                prepare.createActionContext(request, response);

               ……

            }

        } finally {

            prepare.cleanupRequest(request);

        }

    }

在createActionContext的方法中,如果没有老的context对象,则获取值栈对象,然后获取context栈,并压入默认map。然后,有一个new ActionContext(stack.getContext());的方法。将context栈中的数据传入ActionContext中。那么,以后就可以用ActionContext来操作栈。方便了。

    public ActionContextcreateActionContext(HttpServletRequest request, HttpServletResponse response) {

        ActionContext ctx;

        Integer counter = 1;

        Integer oldCounter = (Integer) request.getAttribute(CLEANUP_RECURSION_COUNTER);

        if (oldCounter != null){

            counter = oldCounter + 1;

        }

        ActionContext oldContext = ActionContext.getContext();

        if (oldContext != null){

            // detected existing context, so we are probably in a forward

            ctx = new ActionContext(new HashMap<String, Object>(oldContext.getContextMap()));

        } else {

            ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();

            stack.getContext().putAll(dispatcher.createContextMap(request, response, null));

            ctx = new ActionContext(stack.getContext());

        }

        request.setAttribute(CLEANUP_RECURSION_COUNTER,counter);

        ActionContext.setContext(ctx);

        return ctx;

}

在ActionContext类中,有一个有参的构造函数。

    public ActionContext(Map<String, Object> context) {

        this.context = context;

    }

4.       使用ActionContext来获取值栈对象

public class ValueStackAction extends ActionSupport{

   public String execute() throws Exception {

      /*HttpServletRequestrequest=ServletActionContext.getRequest();

      ValueStackvs1=(ValueStack)request.getAttribute("struts.valueStack");

      System.out.println(vs1);*/

      ValueStack vs=ActionContext.getContext().getValueStack();

      System.out.println(vs);

      return NONE;

   }

}

5.       向值栈中保存数据

Struts2主要提供了2个方法向值栈中存数据。

1)       valueStack.push(Object  obj);

push方法的底层盗用root对象的push方法,将元素添加到root栈的0位置,以后添加元素,从0位置依次压入栈内。

例子:

      ValueStack vs=ActionContext.getContext().getValueStack();

      System.out.println(vs);

      vs.push("haha");

      vs.push("h看看");

2)       valueStack.set(String  key, Object  obj);

在源码中获取map集合(已经存在的,或者新创建的),把map集合push到栈顶,再把数据存入到map集合中。

例子:

      ValueStack vs=ActionContext.getContext().getValueStack();

      System.out.println(vs);

      vs.push("haha");

      vs.push("h看看");

      vs.set("hh", "hhhkk看看");

6.       从值栈获取值

1)       使用push方法存入数据时

创建action类和save方法

public class ValueStackAction extends ActionSupport{

   public String save() throws Exception{

      //获取值栈对象

      ValueStackvs=ActionContext.getContext().getValueStack();

      vs.push("hah好");

      return SUCCESS;

   } 

}

配置struts.xml文件

       <package name="valueStack" namespace="/" extends="struts-default">

           <action name="save" class="com.struts2.action.ValueStackAction"method="save">

              <result name="success">/jsp/vsSuccess.jsp</result>

           </action>          

       </package>

编写jsp页面

<%@ page language="java" contentType="text/html;charset=UTF-8"

    pageEncoding="UTF-8"%>

<%@ taglib prefix="s" uri="/struts-tags"%>   

<!DOCTYPE htmlPUBLIC "-//W3C//DTDHTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type"content="text/html; charset=UTF-8">

<title>Insert title here</title>

</head>

<body>

   <span>从值栈中获取值</span><br />

   <s:property value="[0].top" />

   <!-- s:debug的作用是在jsp页面查看值栈的内部结构 -->

   <s:debug></s:debug>

</body>

</html>

2)       使用set方法存入数据时

创建action类的方法

   public String save() throws Exception{

      //获取值栈对象

      ValueStack vs=ActionContext.getContext().getValueStack();

      //vs.push("hah好");

      vs.set("msg","会话");

      return SUCCESS;

   }

配置struts.xml文件略

编写jsp页面

<body>

   <span>从值栈中获取值</span><br />

   <!--

      获取使用push方法放入的栈顶的字符串值

      <s:propertyvalue="[0].top" />

    -->

   <s:property value="[0].top.msg"/>

   <!-- s:debug的作用是在jsp页面查看值栈的内部结构 -->

   <s:debug></s:debug>

</body>

3)       获取对象的值

A.      使用push方式存入对象时

创建action类的方法

   public String save()throwsException{

      //获取值栈对象

      ValueStack vs=ActionContext.getContext().getValueStack();

      //vs.push("hah好");

      //vs.set("msg","会话");

      User user=new User();

      user.setUsername("哈哈");

      user.setPassword("1234");

      user.setAge(123);

      vs.push(user);

      returnSUCCESS;

   } 

配置struts.xml略,创建pojo类略

编写jsp页面

<body>

   <span>从值栈中获取值</span><br />

   <!--

      获取使用push方法放入的栈顶的字符串值

      <s:propertyvalue="[0].top" />

    -->

   <!--

      获取使用set方法放入的栈顶的map集合的值

      <s:propertyvalue="[0].top.msg" />

    -->

   <!--

      获取使用push方法放入的栈顶的对象的值

    -->

   <s:property value="[0].top.username"/>

   <!-- s:debug的作用是在jsp页面查看值栈的内部结构 -->

   <s:debug></s:debug>

</body>

注意:在jsp页面中获取push方式存放的对象时,可以省略[0].top,直接写需要的属性,如:<s:property value="username"/>

struts2提供了findValue的方法会直接查找属性名对应的值,直到找到就不找了。也就是重名的属性值取先找到的。

B.       使用set方式存入对象时

创建action类的方法

   public String save() throws Exception{

      //获取值栈对象

      ValueStack vs=ActionContext.getContext().getValueStack();

      //vs.push("hah好");

      //vs.set("msg","会话");

      User user=new User();

      user.setUsername("哈哈");

      user.setPassword("1234");

      user.setAge(123);

      //vs.push(user);

      vs.set("user",user);

      return SUCCESS;

   } 

配置struts.xml文件略,创建pojo类略

编写jsp页面

<body>

   <span>从值栈中获取值</span><br />

   <!--

      获取使用push方法放入的栈顶的字符串值

      <s:propertyvalue="[0].top" />

    -->

   <!--

      获取使用set方法放入的栈顶的map集合的值

      <s:propertyvalue="[0].top.msg" />

    -->

   <!--

      获取使用push方法放入的栈顶的对象的值

      <s:propertyvalue="[0].top.username" />

    -->

   <s:property value="[0].top.user.username"/>

   <!-- s:debug的作用是在jsp页面查看值栈的内部结构 -->

   <s:debug></s:debug>

</body>

同样的,在jsp页面可以省略[0].top。struts2会自动查找key值。如:<s:propertyvalue="user.username" />。

4)       获取使用action类的属性对象的值

在action类中创建自定义类的成员属性,并提供set、get方法

public class ValueStackAction extends ActionSupport{

   User user=new User("action","1234",1223);

   public User getUser() {

      return user;

   }

   public voidsetUser(User user){

      this.user = user;

   }

   public String save() throws Exception{

      //获取值栈对象

      ValueStack vs=ActionContext.getContext().getValueStack();

      //vs.push("hah好");

      //vs.set("msg","会话");

      User user=new User("set","1234",13);

      //vs.push(user);

      vs.set("user",user);

      return SUCCESS;

   } 

}

配置struts.xml和创建pojo略

编写jsp页面

<body>

   <span>从值栈中获取值</span><br />

   <!--

      获取使用push方法放入的栈顶的字符串值

      <s:propertyvalue="[0].top" />

    -->

   <!--

      获取使用set方法放入的栈顶的map集合的值

      <s:propertyvalue="[0].top.msg" />

    -->

   <!--

      获取使用push方法放入的栈顶的对象的值

      <s:propertyvalue="[0].top.username" />

    -->

   <!--

      获取使用set方法存入的栈顶的对象的值

      <s:propertyvalue="[0].top.user.username" />

      或者

      <s:propertyvalue="user.username" />

    -->

   <s:property value="[1].top.user.username"/>

   <!-- s:debug的作用是在jsp页面查看值栈的内部结构 -->

   <s:debug></s:debug>

</body>

5)       获取list集合的值和遍历list集合

A.      使用push方法存入list时

创建action类的方法

   public String save() throws Exception{

      //获取值栈对象

      ValueStack vs=ActionContext.getContext().getValueStack();

      //vs.push("hah好");

      //vs.set("msg","会话");

      //User user=newUser("set","1234",13);

      //vs.push(user);

      //vs.set("user",user);

      List<User> ulist=new ArrayList<User>();

      ulist.add(new User("user1","12",123));

      ulist.add(new User("user2","13",63));

      ulist.add(new User("user3","14",133));

      ulist.add(new User("user4","16",83));

      vs.push(ulist);

      return SUCCESS;

   } 

编写jsp页面

<body>

   <span>从值栈中获取值</span><br />

   <!--

      获取使用push方法放入的栈顶的字符串值

      <s:propertyvalue="[0].top" />

    -->

   <!--

      获取使用set方法放入的栈顶的map集合的值

      <s:propertyvalue="[0].top.msg" />

    -->

   <!--

      获取使用push方法放入的栈顶的对象的值

      <s:propertyvalue="[0].top.username" />

    -->

   <!--

      获取使用set方法存入的栈顶的对象的值

      <s:property value="[0].top.user.username"/>

      或者

      <s:propertyvalue="user.username" />

    -->

   <!--

      获取action类中成员属性的值的方法

      <s:propertyvalue="[1].top.user.username" />

    -->

   <!--  -->

   <s:property value="[0].top[0].username"/>

   <s:property value="[0].top[1].username"/>

   <!-- s:debug的作用是在jsp页面查看值栈的内部结构 -->

   <s:debug></s:debug>

</body>

B.       使用set方法存入数据时

创建action类的方法

   public String save() throws Exception{

      //获取值栈对象

      ValueStack vs=ActionContext.getContext().getValueStack();

      //vs.push("hah好");

      //vs.set("msg","会话");

      //User user=newUser("set","1234",13);

      //vs.push(user);

      //vs.set("user",user);

      List<User> ulist=newArrayList<User>();

      ulist.add(new User("user1","12",123));

      ulist.add(new User("user2","13",63));

      ulist.add(new User("user3","14",133));

      ulist.add(new User("user4","16",83));

      //vs.push(ulist);

      vs.set("ulist",ulist);

      return SUCCESS;

   }

编写jsp页面

<body>

   <span>从值栈中获取值</span><br />

   <!--

      获取使用push方法放入的栈顶的字符串值

      <s:propertyvalue="[0].top" />

    -->

   <!--

      获取使用set方法放入的栈顶的map集合的值

      <s:property value="[0].top.msg"/>

    -->

   <!--

      获取使用push方法放入的栈顶的对象的值

      <s:propertyvalue="[0].top.username" />

    -->

   <!--

      获取使用set方法存入的栈顶的对象的值

      <s:propertyvalue="[0].top.user.username" />

      或者

      <s:propertyvalue="user.username" />

    -->

   <!--

      获取action类中成员属性的值的方法

      <s:propertyvalue="[1].top.user.username" />

    -->

   <!--

      获取使用push方法存入的栈顶的list集合的值

      <s:propertyvalue="[0].top[0].username" />

      <s:propertyvalue="[0].top[1].username" />

    -->

   <s:property value="ulist[0].username"/>

   <s:property value="ulist[1].username"/>

   <!-- s:debug的作用是在jsp页面查看值栈的内部结构 -->

   <s:debug></s:debug>

</body>

C.       迭代list集合的方法

Struts2提供了s:iterator标签。value:从值栈中获取的迭代的集合。var:迭代的对象。如果写var,则将迭代产生的对象压入context栈,这时需要写#。如果不写var,则将迭代的对象压入root栈。

a)       写var时

Jsp页面

   <!--

      s:iterator标签

      value:从值栈中获取的迭代的集合

      var:迭代的对象。如果写var,则将迭代产生的对象压入context栈,这时需要写#。如果不写var,则将迭代的对象压入root栈。

    -->

   <s:iterator value="ulist"var="user">

      <s:property value="#user.username"/>

      <s:property value="#user.password"/>

   </s:iterator>

b)       不写var时

   <s:iterator value="ulist">

      <!--

         不省略书写栈顶的方式

         <s:propertyvalue="[0].top.username" />

         <s:propertyvalue="[0].top.password" />

       -->

      <s:property value="username"/>

      <s:property value="password"/><br />

   </s:iterator>

6)       从context栈中获取值

从context栈中获取值时,记得要加#。

Context栈底层已经封装request,session,application,parameters,attr等对象。从context栈取值,需要先手动向request,session,application等域中存入值。

A.      从request,session,application等域中取值

创建action类并向request等域中存入值

   public String save() throws Exception{

      //获取值栈对象

      ValueStack vs=ActionContext.getContext().getValueStack();

      //vs.push("hah好");

      //vs.set("msg","会话");

      //User user=newUser("set","1234",13);

      //vs.push(user);

      //vs.set("user",user);

      List<User> ulist=new ArrayList<User>();

      ulist.add(newUser("user1","12",123));

      ulist.add(newUser("user2","13",63));

      ulist.add(newUser("user3","14",133));

      ulist.add(newUser("user4","16",83));

      //vs.push(ulist);

      vs.set("ulist",ulist);

      HttpServletRequest request=ServletActionContext.getRequest();

      request.setAttribute("haha", "会话");

      request.getSession().setAttribute("haha", "看看");

      return SUCCESS;

   } 

编写jsp页面

   <!-- 从context栈中取值 -->

   <s:property value="#request.haha"/>

   <s:property value="#session.haha"/>

B.       从parameters对象中取值

向页面传入parameters参数

http://127.0.0.1:8080/struts01/save.haha?haha=参数

jsp页面

       <s:propertyvalue="#parameters.haha" />

C.       从attr对象中取值

       <s:propertyvalue="#attr.haha" />

7)       使用EL表达式从值栈中取值

使用el表达式结合jstl标签使用,在eclipse开发下注意导入jstl的jar包。

创建action类的方法

   public String save() throws Exception{

      //获取值栈对象

      ValueStack vs=ActionContext.getContext().getValueStack();

      List<User> ulist=new ArrayList<User>();

      ulist.add(newUser("user1","12",123));

      ulist.add(newUser("user2","13",63));

      ulist.add(newUser("user3","14",133));

      ulist.add(newUser("user4","16",83));

      //vs.push(ulist);

      vs.set("ulist",ulist);

      return SUCCESS;

   } 

编写jsp页面,使用el表达式取值

   <c:forEach items="${ulist }"var="user">

      ${user.username }====${user.password }<br />

   </c:forEach>

为什么EL也能访问值栈中的内容

采用了装饰者模式对封装进行了增强。在StrutsPrepareAndExecuterFilter的doFilter代码中request=prepare.wrapRequest(request);对request 对象进行了包装,StrutsRequestWrapper增强了request的getAttribute方法。

Objectattribute = super.getAttribute(s);

if(attribute == null) {

attribute =stack.findValue(s);

}

当使用el表达式访问request范围的数据时,如果数据找不到,就去值栈中找。这就使el表达式具备了访问值栈数据的能力(查找root栈数据)。

十七、           Struts2的标签指引

Struts2提供了通用的标签和UI标签等。

Generic Tag Reference

Struts Generic Tags control the executionflow as pages render.

Control Tags

  • if
  • elseif
  • else
  • append
  • generator
  • iterator
  • merge
  • sort
  • subset

Data Tags

  • a
  • action
  • bean
  • date
  • debug
  • i18n
  • include
  • param
  • property
  • push
  • set
  • text
  • url

UI Tags

UI Tag Reference

Struts UI Tags display data in rich andreusable HTML.

Form Tags

  • checkbox
  • checkboxlist
  • combobox
  • datetextfield
  • doubleselect
  • head
  • file
  • form
  • hidden
  • inputtransferselect
  • label
  • optiontransferselect
  • optgroup
  • password
  • radio
  • reset
  • select
  • submit
  • textarea
  • textfield
  • token
  • updownselect

Non-Form UI Tags

  • actionerror
  • actionmessage
  • component
  • div
  • fielderror

Ajax Tags

  • a
  • autocompleter
  • bind
  • datetimepicker
  • div
  • head
  • submit
  • tabbedPanel
  • textarea
  • tree
  • treenode

十八、           OGNL表达式的特殊符号

1.       #号的用法

1)       获得contextMap中的数据

如:

   <!-- 从context栈中取值 -->

   <s:property value="#request.haha"/>

   <s:property value="#session.haha"/>

2)       构建一个Map集合

例子:

   <s:form action=""method="post">

      <%--<s:radio name="sex" list="{'男','女'}" /> --%>

      <%--使用#构建Map集合 --%>

      <s:radio name="sex"list="#{'0':'男','1':'女' }" />    

   </s:form>

2.       %号的用法

强制将字符串解析成OGNL表达式

例子:

   <%--使用%{''}将OGNL强制转换成字符串输出而不是从值栈取值 --%>

   <s:property value="%{'aaa'}"/>

   <%--直接以单引号表示的字符串也是被强制转换成字符串输出而不是OGNL --%>

   <s:property value="'aaa'"/>

3.       $号的用法

在jsp页面中使用$可以使用EL表达式时使用。

在配置文件中可以使用使用$号引用OGNL表达式。在配置文件下载时就会用到$号。

例子:

<action name="download1" class="com.struts2.haha.DownloadAction">
            <result name="success" type="stream">
                <param name="contentType">${contentType}</param>
                <param name="contentDisposition">attachment;filename=${downFilename}</param>
            </result>
</action>

十九、           Struts2下使用ajax

Struts2没有提供封装的ajax功能。在struts2下使用ajax,基本同单个servlet使用ajax的方式。如果使用eclipse请导入相关jar包。

例子使用ajax实现页面加载数据字典功能:

在jsp页面使用jquery的ajax

   function loadSelect(typecode,positionId,selectname,selectId){

      var $select = $("<select name="+selectname+"></select>");

      $select.append($("<option value=''>--请选择--</option>"));

      $("#"+positionId).append($select);

   $.post("${pageContext.request.contextPath}/BaseDictAction",{dict_type_code:typecode},function(data){

         //alert("Data loaded:"+data);

         $.each(data,function(i,json){

            //alert(json["dict_item_name"]);

            var $option=$("<option value='"+json['dict_id']+"'>"+json['dict_item_name']+"</option>");

            if(json["dict_id"] == selectId){

                $option.attr("selected","selected");

            }

            $select.append($option);

         });

      },"json");

   }

编写ajax的url路径的专门用于加载数据字典的action类的方法,在方法中,return为null。

public class BaseDictAction extends ActionSupport{

   private String dict_type_code;

   private BaseDictService baseDictService;

   @Override

   public String execute() throws Exception {

      List<BaseDict> list=baseDictService.getListByTypeCode(dict_type_code);

      String json=JSONArray.fromObject(list).toString();

   ServletActionContext.getResponse().setContentType("application/json;charset=utf-8");

      ServletActionContext.getResponse().getWriter().write(json);     

      return null;

   }

   public String getDict_type_code() {

      return dict_type_code;

   }

   public voidsetDict_type_code(String dict_type_code) {

      this.dict_type_code = dict_type_code;

   }

   public voidsetBaseDictService(BaseDictService baseDictService) {

      this.baseDictService = baseDictService;

   } 

}

在struts.xml中配置action

<action name="BaseDictAction" class="baseDictAction" method="execute"></action>

二十、           Struts2实现文件上传

Struts2封装了用于文件上传的拦截器,在实现上相对比较简单。以上传图片为例。

在jsp页面做文件上传,需要满足3个条件,1,表单传输方式为post,2,表单提交类型enctype必须为多段式,即enctype=”multipart/form-data”,3,文件上传使用<input type=”file” name=”filename” />标签。

在action类中,需要声明以上传文件的name为名字的File类属性,如果需要使用源文件的名字和类型,则声明以name开头的字符串FileName和ContentType属性。提供这些属性的setter和getter方法。然后,在需要上传的地方使用这些属性。使用file类的renameTo(new File());方法。

例子:

Jsp页面

<form action=”” method=”post” enctype=”multipart/form-data” >

<input type="file" name="photo"/>

</form>

Action类中

   private File photo;

   private String photoFileName;

   private String photoContentType;

   set和get方法略

   public String add()throws Exception{

      photo.renameTo(newFile("f:/upload/"+photoFileName));

      cs.save(customer);

      return "toList";

   }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值