struts2知识点

1,Struts1和Struts2的区别和对比 

1 Struts1要求Action类继承一个抽象基类。Strut1的一个普遍问题是使用抽象类编程而不是接口。 

2 Struts 2 Action类可以实现一个Action接口,也可实现其他接口,使可选和定制的服务成为可能。

  Struts2提供一个ActionSupport基类去 实现 常用的接口。Action接口不是必须的,

  任何有execute标识的POJO(javabean)对象都可以用作Struts2的Action对象。 

 

3 线程模式: 

 Struts1 Action是单例模式并且必须是线程安全的,因为仅有Action的一个实例来处理所有的请求。单例策略限制了Struts1 Action能作的事,

 并且要在开发时特别小心。Action资源必须是线程安全的或同步的。 

 Struts2 Action对象为每一个请求产生一个实例,因此没有线程安全问题。(实际上,servlet容器给每个请求产生许多可丢弃的对象,

 并且不会导致性能和垃圾回收问题) 

 

4 Servlet 依赖: 

  Struts1 Action 依赖于Servlet API ,因为当一个Action被调用时HttpServletRequest 和 HttpServletResponse 被传递给execute方法。 

  Struts 2 Action不依赖于容器,允许Action脱离容器单独被测试。如果需要,Struts2 Action仍然可以访问初始的request和response。

  但是,其他的元素减少或者消除了直接访问HttpServetRequest 和 HttpServletResponse的必要性。 

 

5 可测性: 

  测试Struts1 Action的一个主要问题是execute方法暴露了servlet API(这使得测试要依赖于容器)。

   一个第三方扩展--Struts TestCase--提供了一套Struts1的模拟对象(来进行测试)。 

  Struts 2 Action可以通过初始化、设置属性、调用方法来测试,"依赖注入"支持也使测试更容易。 

 

6 捕获输入: 

  Struts1 使用ActionForm对象捕获输入。所有的ActionForm必须继承一个基类。

  因为其他JavaBean不能用作ActionForm,开发者经 常创建多余的类捕获输入。

  动态Bean(DynaBeans)可以作为创建传统ActionForm的选择,但是,

  开发者可能是在重新描述(创建)已经存 在的JavaBean(仍然会导致有冗余的javabean)。 

  Struts 2直接使用Action属性作为输入属性,消除了对第二个输入对象的需求。

  输入属性可能是有自己(子)属性的rich对象类型。Action属性能够通过 web页面上的taglibs访问。

  Struts2也支持ActionForm模式。rich对象类型,包括业务对象,能够用作输入/输出对象。

  这种 ModelDriven 特性简化了taglib对POJO输入对象的引用。 

 

7  表达式语言: 

  Struts1 整合了JSTL,因此使用JSTL EL。这种EL有基本对象图遍历,但是对集合和索引属性的支持很弱。 

  Struts2可以使用JSTL,但是也支持一个更强大和灵活的表达式语言--"Object Graph Notation Language" (OGNL). 

 

8  绑定值到页面(view): 

  Struts 1使用标准JSP机制把对象绑定到页面中来访问。 

  Struts 2 使用 "ValueStack"技术,使taglib能够访问值而不需要把你的页面(view)和对象绑定起来。

  ValueStack策略允许通过一系列名称相同但类型不同的属性重用页面(view)。 

 

9  类型转换: 

  Struts 1 ActionForm 属性通常都是String类型。Struts1使用Commons-Beanutils进行类型转换。每个类一个转换器,对每一个实例来说是不可配置的。 

  Struts2 使用OGNL进行类型转换。提供基本和常用对象的转换器。 

 

10 校验: 

  Struts 1支持在ActionForm的validate方法中手动校验,或者通过Commons Validator的扩展来校验。同一个类可以有不同的校验内容,但不能校验子对象。 

  Struts2支持通过validate方法和XWork校验框架来进行校验。XWork校验框架使用为属性类类型定义的校验和内容校验,来支持chain校验子属性 

 

11 Action执行的控制: 

 Struts1支持每一个模块有单独的Request Processors(生命周期),但是模块中的所有Action必须共享相同的生命周期。 

 Struts2支持通过拦截器堆栈(Interceptor Stacks)为每一个Action创建不同的生命周期。堆栈能够根据需要和不同的Action一起使用。

 

2 Struts2请求流程 

1、客户端发送请求 (客户端初始化一个指向Servlet容器(如Tomcat)的请求)

2、请求经过一系列过滤器(如ActionContextCleanUp、SiteMesh等),ActionContextCleanUp-->FilterDispatcher 

3、FilterDispatcher通过ActionMapper来决定这个Request需要调用哪个Action 

4、如果ActionMapper决定调用某个Action,FilterDispatcher把请求的处理交给ActionProxy,

5、ActionProxy通过Configuration Manager询问Struts配置文件(Struts.xml),找到需要调用的Action类。

6、ActionProxy创建一个ActionInvocation的实例 

7、ActionInvocation调用真正的Action,当然这涉及到相关拦截器的调用 

8、Action执行完毕,ActionInvocation创建Result并返回,返回结果

 

 

3步骤

 

 

一 导包

二 web.xml  配置过滤器

   <filter>

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

        <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-   class>

 

  </filter>

 

  <filter-mapping>

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

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

  </filter-mapping>

 

 

 

三   src目录下建立 struts.xml

     <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"

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

 <struts>

<include file="struts-default.xml" />

<package name="取个名字" extends="struts-default" >

<action name="取个名字" >

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

</action>

</package>

    </struts>

 

4一些常识:

   可以有多个包,每个包有一个命名空间

   一个包里有多个action,一个action里有多个result

   访问action时先以命名空间查找

  开发模式的常量设置:将<constant name="struts.devMode" value="false" />中的value值改为true。  

 

 

     .action 

    不带类名与包名  逐层访问路径  默认 result  success  继承extends="struts-default"(为什么呢,后面拦截器会有说明)

    包名 命名空间  寻找顺序(最精确匹配)

    先找命名空间,如果在该命名空间不存在该action则报错[unknown location]

   ,当命名空间存在该action时,则可以在该命名空间下后面紧跟其它路径逐层访问 当逐层访问路径与有命名空间冲突时,以有命名空间的为主。

     <constant name="struts.action.extension" value="action" />修改后缀名的常量

 

  5 <jsp:forward  问题  struts2 jsp:forward 404错误 

   原因: struts 2   使用 filter 实现, <jsp:forword /> 的机制是 servlet 

   目前解决办法是: 

      1、用form表单提交

      2、<meta http-equiv="refresh" content="0;URL=xxx.action">; 

      3、<script language="javascript">location.replace(URL)</script> 

      4、通过过滤器改变请求地址。 

        配置web.xml 

<filter-mapping> 

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

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

  <dispatcher>REQUEST</dispatcher> 

  <dispatcher>FORWARD</dispatcher>   

</filter-mapping>     

 

       5、可以用s:url标签 

 

   6  类名 

     实现Action与不实现action接口

     不extends ActionSupport   重写execute方法 

     extends ActionSupport     重写execute方法

      ?传值注意  method=post

       表单提交  用 method=post

 

    7  struts2 中 Actionsupport 的作用 

      (1)实现Action接口 具备5个常量

      (2)数据校验,Action接口的基础上还定义了一个validate()方法

      (3)国际化

 

   8    Action 跟 Actionsupport 的区别 

    当我们在写action的时候,可以实现Action接口,也可以继承Actionsupport这个类.到底这两个有什么区别呢? 

Action接口有: 

public static final java.lang.String SUCCESS = "success"; 

public static final java.lang.String NONE = "none"; 

public static final java.lang.String ERROR = "error"; 

public static final java.lang.String INPUT = "input"; 

public static final java.lang.String LOGIN = "login"; 

public abstract java.lang.String execute() throws java.lang.Exception; 

而Actionsupport这个工具类在实现了Action接口的基础上还定义了一个validate()方法,

重写该方法,它会在execute()方法之前执行,如校验失败,会转入input处,必须在配置该Action时配置input属性。 

另外,Actionsupport还提供了一个getText(String key)方法还实现国际化,该方法从资源文件上获取国际化信息. 


  9从  action属性到页面的传值  bean list  bena中bean  bean中list  list中bean map 
      action属性必须提供get方法

<s:iterator value="list" status="xxx">
<s:property value="name"/>
</s:iterator>

<s:iterator value="map">
<s:property value="value.name" />
</s:iterator>

<s:property value="tb.name"/>
<s:property value="tb.sex"/>
<s:property value="tb.age"/>个

字符串判断
<s:if teest='属性名=="男"'>
数字类型判断
<s:if teest='属性名==111'>

10动态方法
   1感叹号定位方法  action名!方法名.action
   2 method定位方法   配置多个action 
   3 通配符匹配法(action中的name  class  method都支持通配符 result也支持)

  action的匹配顺序 先找最精确匹配 当用通配符匹配时 配置在前面的优先匹配

11

  全局结果与局部结果 ----- 全局异常与局部异常
  <global-results><result name="ggg">/ggg.jsp</result></global-results>
  全局结果 所有的action共用   局部结果 自己的action用 当两者重名时,优先选择局部结果


全局异常与局部异常(附件 struts1.x中的异常处理.txt)
 <global-exception-mappings>
<exception-mapping result="geror"(此处的geror是指result中的配置(包含局部与全局 ,然后跳转到result中的配置中的jsp页面)) 
exception="异常类型如java.lang.Exception" >
</exception-mapping>
</global-exception-mappings> 

如假设有result中配置<result name="geror">/geror.jsp</result>

则在geror.jsp页面可以使用Struts2的标签来输出异常信息
<s:property value="exception.message"/>
<s:property value="exceptionStack"/>
全局异常 所有的action共用  局部异常 自己的action用 当两者重名时,优先选择局部异常


12类型转换
     1 内建类型转换器   
     
        常规类型的转换:
      比如表单提交的信息有 用户名,生日, 年龄, Action中对应的数据类型分别是 String, Date, int. Struts2会自动完成.
      Struts2内建了常用的类型转换器,如String ,boolean,char,int,long,float,double,Date, 
        数组(假定元素是String类型), 集合(假定元素是String类型,用ArrayList封装)


        利用ognl的内建支持  
      <1>直接把页面属性转换成action中的bean属性,页面属性分开,假设action中bean属性名为user  则如下
         <input type=text name="user.username">
         <input type=text name="user.password">
       在页面输入值后  action中bean属性名为user可以直接拿到值
      <2>直接把页面属性转换成action中的集合属性,不需要转换器
       map版
         第一个用户名:<input type="text" name="action中的集合属性名['one'].name"/>
         第一个密码:<input type="text" name="action中的集合属性名['one'].pass"/>
         第二个用户名:<input type="text" name="action中的集合属性名['two'].name"/>
         第二个密码:<input type="text" name="action中的集合属性名['two'].pass"/>
       list或数组版本
         第一个用户名:<input type="text" name="action中的集合属性名[0].name"/>
         第一个密码:<input type="text" name="action中的集合属性名[0].pass"/>
         第二个用户名:<input type="text" name="action中的集合属性名[1].name"/>
         第二个密码:<input type="text" name="action中的集合属性名[1].pass"/>




    2 自定义
      从范围来讲 有局部转换器和全局转换器  从实现的角度而言有基于ognl的转换和基于strut2转换
        
        
       (1) 写自定义类型转换类 

      ognl的转换   extends DefaultTypeConverter 重写convertValue方法

         举例 把字符串转换成bean对象 bean作为action中的一个属性 bean名为User,action中的bean属性名为user
         假设把页面上的用户名和密码,用户名和密码在同一个文本框输入,用,好隔开, 代码如下
         public Object convertValue(Map context, Object value, Class toType)
{
        if (toType == User.class )
{
String[] params = (String[])value;
User user = new User();
String[] userValues = params[0].split(",");
user.setName(userValues[0]);
user.setPass(userValues[1]);
return user;

        }
else if (toType == String.class )
{
User user = (User) value;
return "<" + user.getName() + "," + user.getPass() + ">";
        } 
        return null ;
      } 


       基于struts2的转换  extends StrutsTypeConverter  编写convertFromString与convertToString方法

         public Object convertFromString(Map context, String[] values, Class toClass)
{
User user = new User();
String[] userValues = values[0].split(",");
user.setName(userValues[0]);
user.setPass(userValues[1]);
return user;
    }

        @Override
        public String convertToString(Map context, Object o)
{
User user = (User)o;
return "<" + user.getName() + "," + user.getPass() + ">";

        }



         
      (2) 配置类型转换(局部配置与全局配置)
          局部类型转换器只在本action内有效,全局类型转换器在所有action内有效
         如果是配置局部类型转换器,则在与Action类同包目录下建立Action类名-conversion.properties文件,里面配置
            action中的bean属性名=包名.转换器类名
        如果是配置全局类型转换器,则在src目录下建立xwork-conversion.properties,里面配置
             包名.被转换的类名(action中的bean属性类名)=包名.转换器类名


     
      
   

     
        把页面属性转换成action中的集合属性   有2种实现方式
        (1 action中集合属性使用泛型指定里面元素类型 2 在局部配置文件配置Element_action中的集合属性名=包名.集合元素里的类名)
        页面信息
        请输入用户1信息:<input type="text" name="action中的集合属性名"/>
        请输入用户2信息:<input type="text" name="action中的集合属性名"/>
    
       


    3 错误处理
       当类型转换出现错误,自动转发到input页面,  在页面用<s:fielderror />显示全部错误
       在资源文件修改默认的错误显示信息
       xwork.default.invalid.fieldvalue={0}字段类型转换失败!
      
13 校验
1 继承Actionsupport 重写validate方法
             this.addFieldError("username", this.getText("xxx"));
 this.addFieldError("username1", "yyy");

     在页面用<s:fielderror />显示全部错误
     显示某个错误
      <s:fielderror>
      <s:param value="%{'username1'}" />
      </s:fielderror>
  2 validateXxx方法
  3 strut2的校验流程
    
  4 校验框架
    每个Action类有一个校验文件,命名 Action类名-validation.xml,且与Action类同目录,
 当校验文件的取名为ActionClassName-validation.xml时,会对 action中的所有处理方法实施输入验证。
 如果你只需要对action中的某个action方法实施校验,那么,校验文件的取名应为:ActionClassName-ActionName-validation.xml,
 其中ActionName为struts.xml中action的名称。例如:在实际应用中,常有以下配置: 
  <action name="user_*" class="cn.itcast.action.UserAction" method="{1}“ > 
  <result name="success">/WEB-INF/page/message.jsp</result> 
   <result name="input">/WEB-INF/page/addUser.jsp</result> 
   </action> 
   UserAction中有以下两个处理方法: 
    public String add() throws Exception{ 
     .... 
   } 
    public String update() throws Exception{ 
    .... 
   }  
要对add()方法实施验证,校验文件的取名为: UserAction-user_add-validation.xml 
要对update()方法实施验证,校验文件的取名为: UserAction-user_update-validation.xml ld> 

   客户端校验:功能不咋的  不建议使用
     1,form的主题(theme)一定不能设定为simple
     2,将form的validate属性设置为true

字段校验  字段用什么校验器来校验  
非字段校验是用校验器校验什么字段  
通俗点讲: 字段校验:校验谁,用什么方法 非字段校验:用什么校验,校验谁 



     字段校验   
        举例  

   内建的校验器在 xwork  lib包中  如 xwork-2.0.7\com\opensymphony\xwork2\validator\validators\default.xml  文件中


         <?xml version="1.0" encoding="GBK"?>
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN"
"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">

<validators>
<field name="name">
<field-validator type="requiredstring">
<param name="trim">true</param>
<message>必须输入名字</message>
</field-validator>
<field-validator type="regex">
<param name="expression"><![CDATA[(\w{4,25})]]></param>
<message>您输入的用户名只能是字母和数组,且长度必须在4到25之间</message>
</field-validator>
</field>
<field name="pass">
<field-validator type="requiredstring">
<param name="trim">true</param>
<message>必须输入密码</message>
</field-validator>
<field-validator type="regex">
<param name="expression"><![CDATA[(\w{4,25})]]></param>
<message>您输入的密码只能是字母和数组,且长度必须在4到25之间</message>
</field-validator>
</field>
<field name="age">
<field-validator type="int">
<param name="min">1</param>
<param name="max">150</param>
<message>年纪必须在1到150之间</message>
</field-validator>
    </field>
<field name="birth">
<field-validator type="date">
<param name="min">1900-01-01</param>
<param name="max">2050-02-21</param>
<message>年纪必须在${min}到${max}之间</message>
</field-validator>
</field>
</validators>

    非字段校验 
   <validator type="校验器名称">
  <param name="fieldName">需要被检验的字段</param>
  <param name="参数名">参数值</param>
  <message key="i18nkey">校验错误信息</message>
 </validator>


举例
    <validators>

<validator type="requiredstring">
<param name="fieldName">name</param>
<param name="trim">true</param>
<message>${getText("name.requried")}</message>
</validator>
<validator type="regex">
<param name="fieldName">name</param>
<param name="trim">true</param>
<param name="expression"><![CDATA[(\w{4,25})]]></param>
<message>${getText("name.regex")}</message>
</validator>
<validator type="requiredstring">
<param name="fieldName">pass</param>
<param name="trim">true</param>
<message>${getText("pass.requried")}</message>
</validator>
<validator type="regex">
<param name="fieldName">pass</param>
<param name="trim">true</param>
<param name="expression"><![CDATA[(\w{4,25})]]></param>
<message>${getText("pass.regex")}</message>
</validator>
<validator type="int">
<param name="fieldName">age</param>
<param name="min">1</param>
<param name="max">150</param>
<message>${getText("age.range")}</message>
</validator>
<validator type="date">
<param name="fieldName">birth</param>
<param name="min">1900-01-01</param>
<param name="max">2050-02-21</param>
<message>${getText("birth.range")}</message>
</validator>

</validators>

      
  校验国际化配置<message key="name.regex"/> 如该种方式出错,则采用${getText("key名")} 
  向资源文件传递参数 ${getText("key名",{'aa','bb'})}

  
   模型驱动的校验 
   模型驱动的配置 需要为模型驱动的action中bean提供get方法,当然喜欢加上set方法也可以
   配置
    <field name="action中bean属性名.name">
<field-validator type="requiredstring">
<message>模型驱动用户的:</message>
</field-validator>





    visitor校验   2个校验文件  当属性为javabean时的校验  区别于模型驱动
     
     第一个校验文件  Action类名-validation.xml中的配置如下
       <validators>
<field name="action中的bean属性名">
<field-validator type="visitor">
<param name="context">userContext</param>
<param name="appendPrefix">true</param>
<message>用户的:</message>
</field-validator>
</field>
   </validators>
     jsp页面输入框示例
     <input type=text name="action中的bean属性名.bean中的属性"> 如
    <input type=text name="user.name"> 

     第2个校验文件 bean类名-第一个校验文件context参数值-validation.xml 如User-userContext-validation.xml,
     该文件中就可以写校验bean中的属性,如同前面的校验
       
 

14访问 servletapi
    1.  非IoC方式

   要获得上述对象,关键Struts 2.0中com.opensymphony.xwork2.ActionContext类。我们可以通过它的静态方法getContext()获取当前Action的上下文对象。 
   另外,org.apache.struts2.ServletActionContext作为辅助类(Helper Class),可以帮助您快捷地获得这几个对象。 
                             HttpServletRequest request = ServletActionContext.getRequest(); 
                             HttpServletResponse response = ServletActionContext.getResponse(); 
                             HttpSession session = request.getSession();

   如果你只是想访问session的属性(Attribute),你也可以通过ActionContext.getContext().getSession()获取或添加session范围(Scoped)的对象。

    2. IoC方式
       要使用IoC方式,我们首先要告诉IoC容器(Container)想取得某个对象的意愿,通过实现相应的接口做到这点
       实现相关接口SessionAware, ServletRequestAware, ServletResponseAware
      private Map att;
      private HttpServletRequest request;
      private HttpServletResponse response;    
   
  publicvoid setSession(Map att) {
      this.att = att;
  }
  
  publicvoid setServletRequest(HttpServletRequest request) {
      this.request = request;
  }
  
  publicvoid setServletResponse(HttpServletResponse response) {
      this.response = response;
  }

 
15 struts2  中的ognl 以及标签语法
   
   两个栈  第一个是值栈ognl上下文(value stack)  第2个是ActionContext 栈 访问里面的数据ActionContext 栈通过前面加上 #号实现  
   
 Struts 2中的表达式语言

Struts 2支持以下几种表达式语言:

1.      OGNL(Object-Graph Navigation Language),可以方便地操作对象属性的开源表达式语言; 

2.      JSTL(JSP Standard Tag Library),JSP 2.0集成的标准的表达式语言; 

3.      Groovy,基于Java平台的动态语言,它具有时下比较流行的动态语言(如Python、Ruby和Smarttalk等)的一些起特性; 

4.      Velocity,严格来说不是表达式语言,它是一种基于Java的模板匹配引擎,具说其性能要比JSP好。 

Struts 2默认的表达式语言是OGNL,原因是它相对其它表达式语言具有下面几大优势:

1.      支持对象方法调用,如xxx.doSomeSpecial(); 

2.      支持类静态的方法调用和值访问,表达式的格式为@[类全名(包括包路径)]@[方法名 |  值名],例如:@java.lang.String@format('foo %s', 'bar')或@tutorial.MyConstant@APP_NAME; 


3.      支持赋值操作和表达式串联,如price=100, discount=0.8, calculatePrice(),这个表达式会返回80; 

4.      访问OGNL上下文(OGNL context)和ActionContext; 

5.      操作集合对象。 


  “#”主要有三种用途:  
    1.      访问OGNL上下文和Action上下文,#相当于ActionContext.getContext();下面有几个ActionContext中有用的属性: 

 parameters
 包含当前HTTP请求参数的Map
 #parameters.id[0]作用相当于request.getParameter("id")
 
request
 包含当前HttpServletRequest的属性(attribute)的Map
 #request.userName相当于request.getAttribute("userName")
 
session
 包含当前HttpSession的属性(attribute)的Map
 #session.userName相当于session.getAttribute("userName")
 
application
 包含当前应用的ServletContext的属性(attribute)的Map
 #application.userName相当于application.getAttribute("userName")
 
attr
 用于按request > session > application顺序访问其属性(attribute)
 #attr.userName相当于按顺序在以上三个范围(scope)内读取userName属性,直到找到为止
 
2.      用于过滤和投影(projecting)集合,如books.{?#this.price<100}; 
       <s:iterator value="books.{?#this.price > 35}">
            <li><s:property value="title" /> - $<s:property value="price" /></li>
        </s:iterator>
    <s:property value="books.{?#this.title=='Code Complete, Second Edition'}.{price}[0]"/>

  问题:?#this的多个判断问题  &&


3.      构造Map,如#{'foo1':'bar1', 'foo2':'bar2'}。  之前讲过
 

 %的特性  计算表达式   类似javascript中的eval函数  可用s:url举例说明%用法  
“%”符号的用途是在标志的属性为字符串类型时,计算OGNL表达式的值

   <s:textfield key="state.label" name="state" value="%{'CA'}" />
   计算boolean值(带有转义符的):
 <s:select key="state.label" name="state" multiple="%{true}"/>
  带有属性的:
 <s:select key="state.label" name="state" multiple="allowMultiple"/>
 既带有转义符又带有属性的:
 <s:select key="state.label" name="state" multiple="%{allowMultiple}"/>

表示式语言符号
  1.在Freemarker、Velocity或者JSTL的表达式语言的JavaBean对象的标准文本
  <p>Username: ${user.username}</p>
  2.在值栈中的一个username属性
 <s:textfield name="username"/>
  3. 引用值栈中的属性的另一种方式
 <s:url id="es" action="Hello">
 <s:param name="request_locale">
    es
 </s:param>
</s:url>
<s:a href="%{es}">Espanol</s:a>
  4. 在Session Context中获得user对象的userName属性
 <s:property name="#session.user.username" />
  5. 在一个静态map中,像("username","trillian")一样
  <s:select label="FooBar" name="foo" list="#{'username':'trillian', 'username':'zaphod'}" />

  
$”有两个主要的用途
1.      用于在国际化资源文件中,引用OGNL表达式,参考前面的国际化校验配置
2.      在Struts 2配置文件中,引用OGNL表达式,如 
<action name="AddPhoto" class="addPhoto">
            <interceptor-ref name="fileUploadStack" />            
            <result type="redirect">ListPhotos.action?albumId=${albumId}</result>
        </action>


16拦截器
    拦截器,用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。
    拦截器是AOP(Aspect-Oriented Programming 面向方面编程)中的一种实现策略。
    1 用代理模式与动态代理编写拦截器
      

       所谓Dynamic Proxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,
       然后该class就宣称它实现了这些interface。你当然可以把该class的实例当作这些interface中的任何一个来用。
       当然啦,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,
       在生成它的实例时你必须提供一个handler,由它接管实际的工作
        那么如何实现动态代理呢
1 写一个动态代理,implements InvocationHandler接口,实现方法
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 
  method.invoke(sub,args);
return null;
}
2 调用 ,
真实实现类名 xxx = new 真实实现类名(); // 在这里指定被代理类
InvocationHandler ds = new DynamicSubject(xxx); // 初始化代理类
接口  接口变量= (接口) Proxy.newProxyInstance(xxx.getClass().getClassLoader(), xxx.getClass().getInterfaces(), ds);
                       接口变量.方法
 
               /**
* 从以上可以看出,动态代理可以任意指定被代理的类,即真实对象类,而代理模式则无法实现该功能,
* 因为他把真实对象的写死在代理类里,如果要按照上述的方法使用代理模式,那么真实角色必须是事先已经存在的,并将其作为代理对象的内部属性。但是
* 实际使用时,一个真实角色或其接口必须对应一个代理角色,如果大量使用会导致类的急剧膨胀
*/

      
    2  struts2拦截器
      解压strut2的核心包,根目录下struts-default.xml中有struts2的拦截器配置
    

       拦截器几乎完成了Struts2框架70%的工作,包括解析请求参数、将请求参数赋值给Action属性、执行数据校验、
       文件上传……,Struts2设计的灵巧性,更大程度地得益于拦截器设计,当需要扩展Struts2功能时,只需要提供对应拦截器,
       并将它配置在Struts2容器中即可;如果不需要该功能时,也只需要取消该拦截器的配置即可。
       这种可插拔式的设计,正是软件设计领域一直孜孜以求的目标。
实际上,Struts2的精髓就在于拦截器,掌握了Struts2的拦截器机制,你就可以说精通了Struts2。
从某个角度来看,我们可以把Struts2框架理解成一个空壳,而这些拦截器像一个一个抽屉,随时可以
插进入,也可以拔出来——这是软件产品一直追求的目标。
如果你喜欢,你可以把Struts2的全部插件拔出,那么Struts2就成了一个空容器——
而这种空,正是 Struts2的魅力,你可以把任何自己想要的东西填入进去,甚至包括自己完全实现这个框架。

另一方面,因为Struts2的插件机制,Struts2提供了无限扩展的可能性,你可以把自己想要的任何
东西做成插件,然后填入Struts2——这样的结果是:一个企业,一个团队,可以把自己业务相关的东西
做成插件,随时随地地复用。
也就是说:如果你想要,你可以把Struts2改造成属于自己的框架。

当然,Struts2也内建了大量的拦截器,这些拦截器以name-class对的形式配置在struts-default. xml文件中,其中name是拦截器的名字,就是以后使用该拦截器的唯一标识;class则指定了该拦截器的实现类,如果我们定义的package继承了Struts2的默认struts-default包,则可以自由使用下面定义的拦截器,否则必须自己定义这些拦截器。
 3  自定义拦截器
     (1)编写拦截器类,继承AbstractInterceptor类 重写intercept(ActionInvocation arg0)方法
          调用用参数类ActionInvocation的invoke方法,即 String result= arg0.invoke();  返回该result=
          invoke就是回调使用了该拦截器的action得相应方法,此时可在该方法执行前后加入我们想要的代码,达到我们拦截action的目的
 利用 arg0.getAction()方法还可以得到拦截器拦截的action实例 
public String intercept(ActionInvocation arg0) throws Exception {
//  LoginAction loginaction=LoginAction(arg0.getAction());
  System.out.println("执行ction之前");
 String result= arg0.invoke();
  System.out.println("执行ction之后");
return result;
}
    、(2)在struts.xml配置拦截器
        <package name="default" extends="struts-default" namespace="/">
<!--配置拦截器  -->
<interceptors>
<interceptor name="拦截器名" class="包名.拦截器类名">
   <!--设置拦截器类属性值,如没有则不用设置  -->
  <param name="拦截器类属性名">属性值</param>
</interceptor>
</interceptors>
<action name="login"  class="com.LoginAction" >
<result name="success">/welcome.jsp</result>
<result name="error">/error.jsp</result>
<interceptor-ref name="defaultStack"></interceptor-ref>
<!--使用拦截器  -->
<interceptor-ref name="拦截器名"></interceptor-ref>
</action>
</package>

     多个拦截器在一起组成一个拦截器栈
          <interceptor-stack name="拦截器栈">
                <interceptor-ref name="拦截器名1"/>
                <interceptor-ref name="拦截器名2"/>
                <interceptor-ref name="拦截器名3"/>
            </interceptor-stack>

    使用拦截器栈 与 使用拦截器一样语法

     当配置一个包时,可以为其指定默认的拦截器,每个包只能有一个默认的拦截器,一旦为某个包指定了默认的拦截器,
     如果该包中的action没有指定
     自己的拦截器,则action使用包指定的默认拦截器,但是一旦为action指定了自己拦截器,
     则包的默认拦截器将会失效,如果还想
     使用包的默认拦截器,则必须显示的指定,我们的包继承另一个包时,也继承了另一个包的默认拦截器,
     当然我们可以定义自己包的默认拦截器覆盖之
     从这里可以解释为什么我们刚刚开始学struts2的时候老是extends="struts-default" 
     因为struts-default包中的默认拦截器是个好东东

     配置默认拦截器 在 包package中 <default-interceptor-ref name="拦截器名或拦截器栈"></default-interceptor-ref> 放后面
      
     
        上面拦截器会拦截action中的所有方法 要想拦截某个方法怎么办  拦截指定方法  
 编写拦截器类,extends MethodFilterInterceptor   MethodFilterInterceptor是AbstractInterceptor的子类
 重写doIntercept方法
    public String doIntercept(ActionInvocation invocation)
throws Exception
{
//  LoginAction loginaction=LoginAction(arg0.getAction());
      System.out.println("执行action方法之前");
      String result= arg0.invoke();
     System.out.println("执行action方法之后");
return result;
}
     
       使用配置指定拦截的方法
         <!-- 拦截器一般配置在result元素之后! -->
<interceptor-ref name="拦截器名1">
<param name="excludeMethods">execute,haha</param>         <!-- 不拦截! -->
<param name="includeMethods">execute</param>               <!-- 拦截! -->
</interceptor-ref>


      可以重复使用一个拦截器,拦截器的执行顺序是在方法执行前,先配先执行,在方法执行后,后配先执行


      拦截结果的监听 是在action结束后,返回result之前的一个监听器,可以在该监听器里写我们的代码,以便在返回结果前执行,
      这个监听器通过手动注册在拦截器内部的
      监听器示例代码  implements PreResultListener
        public class MyPreResultListener implements PreResultListener
         {
public void beforeResult(ActionInvocation invocation,String resultCode)
{
System.out.println("返回的逻辑视图为:" + resultCode);
}
      }

         拦截器示例代码
   public class BeforeResultInterceptor extends AbstractInterceptor
           {
   public String intercept(ActionInvocation invocation) throws Exception
{
invocation.addPreResultListener(new MyPreResultListener()); //注册监听器
System.out.println("execute方法执行之前的拦截...");
String result = invocation.invoke();
System.out.println("execute方法执行之后的拦截......");
return result;

     }
           }

     监听器代码在action结束后,返回结果前执行,和在action结束后在拦截器内部写的代码相比, 监听器代码把action结束后的代码
     放到监听器似乎更精确和清晰些

       

     给拦截器栈传递参数时会出现一个问题,当拦截器栈中拦截器类中的属性名相同时,不知道这个参数到底要传给那个拦截器,为了
     解决这个问题,可作如下配置
         <interceptor-ref name="拦截器栈名">
<param name="拦截器名(不是类名,注意哦).属性名">属性值</param>
</interceptor-ref>



17 struts2的四个主题
simple,xhtml(默认主题),css_xhtml和ajax,这4个主题的模板文件放在Struts2的核心类库里(struts2-core.jar包)。template目录下
      也可以自定义自己的主题,建议继承它的已有主题
      simple主题是最简单的主题,它是最底层的结构,主要用于构建附加的功能或者行为(例如在此主题基础上进行扩展),
      使用simple主题时,每个UI标签只生成一个简单的HTML元素,不会生成其他额外的内容。

Struts2的xhtml, css_xhtml主题都是对simple主题的包装和扩展。

xhtml主题是Struts2的默认主题,它对simple主题进行扩展,在该主题的基础上增加了如下附加的特性:

1,针对HTML标签(如textfield和select标签)使用标准的两列表格布局。

2,每个HTML标签的Label,即可以出现在HTML元素的左边,也可以出现在上边,这取决于labelposition属性的设置。

3,自动输出校验错误信息。

4,输出JavaScript的客户端校验。

css_xhtml主题则对原有的xhtml主题进行了扩展,在xhtml主题基础上加入了CSS样式控制。

ajax主题目对xhtml主题目进行了扩展,在xhtml主题上为每个标签提供了额外的Ajax支持。
ajax主题的Ajax支持是以Dojo和DWR为基础的。ajax主题在xhtml主题基础上增加了如下特性:

1,支持Ajax方式的客户端校验。

2,支持远程表单的异步提交(最好和submit标签一起使用)。

3,提供高级的div标签,允许实现局部更新部分HTML的功能。

4,提供高级的a标签,允许动态加载并执行远端的javaScript代码。

5,提供支持ajax的tabbedPanel。

6,提供"富客户端"模型的pub-sub事件模型。

5,Struts2的表单标签

18零配置
    零配置  约定大于配置原则 使用注解编程替代xml配置     首先要澄清一点,这里说的零配置并不是一点配置都没有,只是说配置很少而已
     
      2.0的零配置
      web.xml配置加载的action所在的包名,在过滤器中作如下修改
      <filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
<init-param>
<param-name>actionPackages</param-name>
<param-value>com</param-value>
</init-param>
</filter>

  表名要加载com包下的aciton   命名空间默认为"/"

  
   在action类中配置
        @Namespace("/aaa")
        @Results({
        @Result(name="success", type=NullResult.class, value="/success.jsp")
})

     例如
       @Results({
@Result(name="success",type=NullResult.class,value="/xxx.jsp")
      })
    public class Test extends ActionSupport {
public String execute() throws Exception {
return super.execute();
}

   直接访问http://localhost:8080/struts20zero/类名(首字母小写).action
    
    当类名以Action结尾时候,则Action可以省略

    如类名XxxAction,则访问 直接访问http://localhost:8080/struts20zero/xxx.action
    如果有Xxx类的action。如果实在同一命名空间下,前面的应该会得到匹配
    如果是早不同的包名下,则与包名的字母排列顺序有关,后面的一半会执行


     

  19Convention Plugin插件
   
        包命名习惯来指定Action位置
" 命名习惯制定结果(支持JSP,FreeMarker等)路径
" 类名到URL的约定转换
" 包名到命名空间(namespace)的约定转换
" 遵循SEO规范
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值