• Struts2详讲


    一 概述

    1.什么是Struts2?

    Struts2是一个在WebWork框架基础上发展起来开源MVC框架。

    2.StrutsPrepareAndExecuteFilter

    StrutsPrepareAndExecuteFilter本质上是一个过滤器,配置在web容器中,该过滤器作为Struts框架的启动项,将符合扩展名要求的请求转发给Struts框架处理,将处理结果返回给浏览器。

    对于那些符合扩展名要求的请求,StrutsPrepareAndExecuteFilter直接将其转发给Struts框架,没有沿着过滤器链向下传递,所以配置在其后的过滤器不起作用。那些不符合扩展名要求的请求将沿过滤器链正常执行。

    3.Struts2的基本结构与执行过程

    StrutsPrepareAndExecuteFilter(为便于表述,以下称作struts启动项)将符合扩展名要求的请求转发到Struts框架中,首先生成一个ActionMapping,该ActionMapping代表了需要调用的Action对象,基于ActionMapping返回一个ActionProxy,proxy通过配置管理器查询配置文件struts.xml,返回一个ActionInvocation对象,由Invocation对象具体调用action中的方法。在action方法调用前以及调用后都会执行一系列拦截器,最后将响应结果反馈给浏览器。

    4.Action

    ⑴角色地位

    Action是Struts2框架的控制器,将请求分发给响应的业务逻辑。每请求一次,创建一个对象。

    ⑵继承关系

    创建Action对象时推荐继承ActionSupport,因为ActionSupport实现了很多接口,继承该类可以拥有国际化、数据验证等功能。Struts2也支持不继承任何类的POJO对象,只能实现一些简单的功能,如表单注入,实现类型转化、数据验证、拦截器、国际化、文件上传等特殊功能时必须继承ActionSupport。

    ⑶动态Action

    在请求url中加入方法名以访问Action中指定方法的机制。
    高版本的Struts禁用了动态Action,可以使用通配符,动态地调用action中的方法:

    • url:actionName_method;
    • 配置文件:<action name="action_*"method="{1}">;

    ⑷数据存储

    • 属性保存在值栈中。
    • 成员变量保存在context区域的action对象中,访问方式#action.name。

    5.struts.xml文件

    struts.xml是Action对象的默认配置文件。
    格式:

    <struts>
       <package name="resultList"extends="struts-default"abstract="true">
         <global-results>
            <result name="">/xxx.jsp</result>
         </global-results>
       </package>
    
      <include file="newFile.xml"></include>
      <contant name="struts.devMode"value="true"></constant>
      <package name="packageName"extends="struts-default"> 
         <global-results>
            <result name="">xxxx</result>
         </global-results>
    
         <action name="url*"class="完整包名{1}">
            <result name="res" type="">/xxx.jsp</result> 
            <result name=""type="redirect">
               <param name="location">/xxx.jsp</parame>
               <param name="key">value</param>
            </result>
            <result name=""type="redirectAction">
               <param name="actionName">actionName</param>
               <param name="key">value</param>
            </result>
        </action>
      </package>    
    </struts>

    标签说明:

    ⑴<include>

    为不同的模块设定不同的配置文件,最后集中到默认的配置文件struts.xml中。

    ⑵<constant>

    设定struts框架的属性。

    ⑶<package>

    • name:指定包名,以便引用此包。
    • extends:通过包名继承其他包。由于配置文件从上向下读取,父包必须放在子包上方。由于"struts.default"包定义了action对象的基本信息,任何一个包都必须直接或者间接地继承该包。
    • namespace:命名空间。Struts允许不同包中的action拥有相同的名称,为了区分相同名称的action,为action所在的包添加一个属性,即namespace,格式“/xxx”,访问此包下的action需要通过此路径在没有使用名称空间的时候,action对象的路径默认为“/name”,访问时可以直接使用名称name,如<a href="name">。一旦设定了名称空间路径变成“namespace/name”,访问时必须使用该路径。

    ⑷<action>

    • name:设定访问action对象的url。
    • class:action对象的类名,加载时使用,未指定,默认加载ActionSupport类,该类execute方法的返回值为success。
    • method:设定请求action对象时,调用Action对象中的哪一个方法,默认是execute方法。
    • converter:指定此Action对象使用的类型转换器。
    • <global-results>:如果包内的Action对象返回相同的视图,可以为这些Action对象统一设定视图。该设定在整个包范围内有效,也可以在包外定义,即应用范围的全局视图。

    ⑸<result>

    name:设定一个名称,当action对象返回的字符串与该名称值相同时,返回对应的文件(如jsp、html)给浏览器,name默认值为success。返回文件采用以“/”开头相对于项目的路径形式。
    type:设定页面跳转的类型:

    • dispatcher:将请求转向一个视图。
    • redirect:重定向到一个视图。
    • chain:请请求转发给另一个Action。
    • redirectAction:重定向到另一个Action。

    二 表单注入

    1.分散注入

    在Action中定义与表单输入同名的属性,底层自动调用setter方法将输入注入到属性中。

    2.DomainModel 

    创建一个封装了表单输入的类,在Action中引用该类的对象,并为对象提供getter/setter方法。要求表单输入必须指明所属的对象,实现方式将表单输入的名称定义为“obj.name”,obj是Action中封装对象的引用变量。

    底层实现过程:域模型为表单输入指明了所属的对象,Action对象创建完成以后,调用getter方法,如果存在对象,则返回,不存在,
    接着调用setter方法创建对象,对象创建完成以后,调用对象中的setter方法为对象属性赋值。

    如果表单输入可以被封装到一个类的多个对象中,那么可以使用域模型将输入注入到向Action对象的List集合中,实现如下:
    在表单输入中使用List集合引用变量与下标给表单输出指定所属的对象:

    <input type="text"name="list[0].name">

    3.ModelDriven

    Action对象实现ModelDriven接口中的getModel方法,getModel方法负责接收表单输入,将输入注入到实体对象中,并返回实体对象不需要在表单输入中指明将要注入的对象,即表单输入名称前不再加对象的引用变量。

    三 与Servlet API交互

    1.获取Map类型的交互对象

    Struts2提供了Map类型的request、session、application,通过ActionContext对象获取,首先获取ActionContext对象:

    ActionContext context = ActionContext.getContext();

    获取request、session、application对象的通用方法,以request为例:

    Map<Object Object> request=context.get("request");

    获取session对象的专有方法:

    Map<Object,Object> session=context.getSession();

    获取application对象的专有方法:

    Map<Object,Object> application=context.getApplication();

    2.获取直接对象

    Struts提供了一个ServletActionContext类,利用该类的静态方法可以获取requestsessionapplication对象:

    HttpServletRequest request=ServletActionContext.getRequest();
    HttpSession session=request.getSession();
    ServletContext servletContext=ServletActionContext.getServletContext();

    四 ActionContext 

    1.单例

    一个线程,一个ActionContext;一个Action,一个ActionContext,ActionContext是线程安全的。

    2.结构

    3.值栈

    对应于OGNL的根,使用OGNL表达式可以直接获取其中的数据。数据结构:

    ⑴获取值栈

    ActionContext context = ActionContext.getContext();
    ValueStack valueStack = context.getValueStack();

    ⑵向值栈中添加数据

    valueStack.push(Object obj);//将数据放到栈顶
    valueStack.set(Object key,Object value);//如果顶层存在Map集合,则放入Map集合中;不存在,创建一个,再将数据放入其中

    ⑶获取数据

    valueStack.peek();// 获取栈顶元素
    valueStack.pop();// 获取并删除该栈顶元素 

    如果栈中的对象包含多个属性,获取属性值时不需要通过对象引用的形式,可以直接使用属性名,系统从栈顶开始检索,找到第一个属性名称相同的属性,将其值返回。
    4.request、session、application(Map类型的集合):在OGNL中,采用#request.key获取属性值。
    5.parameters:存放请求参数,通过#parameters.name获取请求参数的值。
    6.attr:不指定属性的范围,可以通过#attr.key获取属性的值,检索顺序request、session、application。
    7.action对象:获取其中的数据<s:property value="#action.varName"/>。

    五 OGNL

    1.OGNL是什么?

    Object Graph Navigation Language,可以自动导航对象的结构,访问对象,为对象赋值。

    • 自动导航对象结构:访问对象中的变量时不需要通过对象引用,仅有变量名即可,OGNL将自动检索对象,找到变量。
    • OGNL本身不具有向页面输出的能力,需要与Struts标签配合才能向页面输出内容。

    2.OGNL的结构层次

    OGNL的核心是OGNL上下文,OGNL上下文相当于一个Map类型的容器,可以存储任何类型的数据。OGNL分层次,有一个区域是OGNL的根,可以直接访问根中数据,访问其他区域的数据需要在前面加“#”。

    3.OGNL的作用

    • 获取OGNL上下文中的数据。
    • 为变量赋值。
    • 操作集合:访问集合中的数据,判读集合是否为空,获取集合的长度。
    • 访问对象的方法。
    • 访问静态方法。

    4.OGNL的使用范围

    • OGNL是为Struts框架开发的,只能用于从Action对象中获取数据。
    • OGNL上下文对应于Struts的ActionContext,用于从ActionContext中获取数据。
    • OGNL表达式语言与EL、JSTL等各种表达式语言、标签库一样只能用在JSP中,减少java代码,不能用在HTML中。

    5.OGNL的使用

    ⑴${xxx}

    • 这种与EL表达式相同的形式并不是EL表达式,而是OGNL表达式。
    • 既可以访问值栈中的数据,也可以访问valueContext除parameters以外的数据。
    • 可用在struts.xml文件中。
    • 只能直接访问对象,不能在对象前加作用域,比如request、action等,不能加#。
    • 访问优先级request>valueStack>context>session>application。

    ⑵%{xxx}

    当指定内容有可能被执行环境当做字符串时,告知指定内容是OGNL表达式。

    ⑶访问静态属性与方法

    @完整类名@属性名::访问静态变量。
    @完整类名@method():访问静态方法。

    Struts默认情况下不允许访问静态方法,如需访问需要在配置文件中做如下设置:

    <constant name="struts.ognl.allowStaticMethodAccess"value="true"/>

    访问java.lang.Math中的静态方法,可以由@java.lang.Math@method()简写为@@method()。

    ⑷访问数组

    arr[index]:获取数组指定索引位置的元素。
    arr.length:获取数组的长度。

    ⑸访问List、Map集合

    • list[index]:List集合有序,可以按照操作数组的方式通过索引访问数据。
    • map.key:通过指定的key获取value。
    • map.keys:以数组形式返回map集合中的全部key。
    • map.values:以数组的形式返回map集合中的全部value。
    • list/map.isEmpty:判断集合是否为空。
    • list/map.size():获取集合长度。

    ⑹投影

    • 作用:获取集合的某一列,返回一个集合。
    • 操作方式:list.{attr02}(针对值栈中的对象)。

    ⑺选择

    获取集合中满足条件的对象,针对行的操作,返回一个集合。
    操作方法:

    • list.{?#this.attr>value}:获取满足条件的全部元素。
    • list.{^#this.attr>value}:获取满足条件的第一条元素。
    • list.{$#this.attr>value}:获取满足条件的最后一个元素。

    六 Interceptor

    1.继承关系

    创建拦截器对象时,如果直接实现Interceptor接口,需实现其中的三个方法,而这三个方法在实际中并不是全部需要的。AbstractInterceptor是一个抽象类,实现了Interceptor接口,实现了init、destroy方法,因此自定义拦截器对象时,继承该方法,只实现intercept方法即可。

    2.分离原则

    拦截器对象的生命与引用分离,先声明,后引用。

    3.显式引用问题

    在不做其他特殊设定的情况下,使用了自定义的拦截器,系统默认的拦截器失效。由于系统默认的拦截器比较重要,实现重要功能不可缺少,因此应该将系统默认的拦截器包含进去,并且放在其他自定义拦截器前面。

    4.拦截器配的定义

    ⑴分散式

    分别定义与引用多个拦截器。

    ----------------拦截器声明------------------------
    <interceptors>
         <interceptor name="interceptor01"class=""/>
         <interceptor name="interceptor02"class=""/>
    </interceptors>
    ----------------拦截器引用------------------------
    <action>
         <interceptor-ref name="defaultStack"/>
         <interceptor-ref name="interceptor01"/>
         <interceptor-fef name="interceptor01"/>
    </action>

    ⑵集中式

    将多个拦截器集中在拦截器栈中,引用拦截器栈。拦截器栈相当于拦截器集合。

    ----------------拦截器声明------------------------
    <interceptors>
        <interceptor name="interceptor01"class=""/>
        <interceptor name="interceptor02"class=""/>
        <interceptor-stack name="myStack">
           <interceptor-ref name="defaultStack"/>
           <interceptor-ref name="interceptor01"/>
           <interceptor-fef name="interceptor01"/>
        </interceptor-stack>
    </interceptors>
    ----------------拦截器引用------------------------
    <action>
         <interceptor-ref name="myStack"/>
    </action>

    ⑶默认式

    将拦截器集中在默认拦截器中,对包中所有的Action有效。

    ----------------拦截器声明------------------------
    <interceptors>
        <interceptor name="interceptor01"class=""/>
        <interceptor name="interceptor02"class=""/>
        <interceptor-stack name="myStack">
            <interceptor-ref name="defaultStack"/>
            <interceptor-ref name="interceptor01"/>
            <interceptor-fef name="interceptor02"/>
        </interceptor-stack>
    </interceptors>
    <default-interceptor-ref name="myStack"/>

    5.MethodFilterInterceptor

    直接继承AbstractInterceptor创建的拦截器对所有方法都进行拦截,继承MethodFilterInterceptor创建的拦截器可以指定拦截的方法。
    引用方式:

    <interceptor-ref name="interceptor01"class="">
         <param name="includeMethods">methodName01,methodName02</param>//指定拦截的方法
         <param name="excludeMethods">methodName01,methodName02</param>//指定不拦截的方法    
    </interceptor-ref>

    七 类型转换器

    1.内置类型转换器

    Struts内置了许多类型转化器,主要是将字符串转化为基本数据类型及其包装类,将字符串转化为日期。系统默认的日期格式是yyyy-MM-dd HH:mm:ss,当输入的字符串符合该格式时,自动转化为日期。

    2.自定类型转换器创建

    public class MyDateConverter extends DefaultTypeConverter {
    
        @Override
        public Object convertValue(Object value, Class toType) {
            // TODO Auto-generated method stub
            return super.convertValue(value, toType);
        }
    
    }

    该方法分为两部分,有时执行两次:

    • 判断输入格式是否满足要求,满足,将格式类型存到ActionContext中;不满足,抛出TypeConversionException。
    • 将转换后的数据还原,回显到浏览器。

    3.TypeConversionException

    发生类型转换异常,会返回值input,需要在配置文件中定义input对应的返回页面。input只在抛出TypeConversionException时才返回,因此需要在自定义类型转换器中抛出该异常,可以先判断表单输入的格式是否是允许的格式,如果不是允许格式,抛出该异常。

    4.注册

    ⑴局部类型转换器

    文件命名方式ActionClassName-conversion.properties,放在Action包中,属性文件内容:

    属性名=类型转换器全限定性类名

    ⑵全局类型转换器

    文件命名方式xwork-conversion.properties,放在src目录下,属性文件内容:

    属性类型(如java.util.Date)=类型转换器全限定性类名

    5.回显提示信息

    修改类型验证返回的提示信息,创建ActionClassName.properties文件,放在Action包中,内容:

    invalid.fieldvalue.fieldname=数据验证失败提示信息

    八 数据验证机制

    1.手动验证器

    ActionSupport实现了Validatable接口,对其中的方法validate只是空实现,因此手动编写验证器时,继承ActionSupport类,重写validate方法。手动验证器默认对对象内的所有方法都进行验证。

    public class MyValidator extends ActionSupport{
        public void validate(){
           if(xxxxxx)//验证如果未通过
              this.addFieldError("字段名","显示的错误提示信息");
        }
    }
    • 手动验证默认对Action对象中的全部方法有效,如果需要只对某个方法有效,可以修改validate方法的方法名,修改为validate+方法名(首字母大写)。
    • 自定义验证器不支持数据回显。

    2.文件验证

    验证文件的命名规则:

    ActionClassName-validation.xml:对Action对象中所有方法都进行验证。
    ActionClassName-AliasName(配置中的名称)-validation.xml:只对指定的方法进行验证。

    验证文件的编写:

    <validators>
        <field name="fieldName">
            <field-validator type="requiredstring">
                <message>验证未通过时输出的信息</message>
            </field-validator>
        </field>
    <validators>

    验证未通过时,Action返回值“input”,因此需要在<action>标签内部配置返回值为“input”时的返回页面。

    3.优先级

    如果为同一个方法同时定义了多个数据验证方式,执行的优先级:基于XML的针对方法的验证>基于XML的针对对象的验证>手动编写的针对方法的验证>手动编写的针对对象的验证

    九 Struts标签库

    引用:

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

    主要标签:
    1.<s:debug/>:在页面中显示ActionContext中的内容。
    2.<s:property value=""/>:

    • 向页面输出内容,或者取值传递。
    • 无论是否含有“#”,都首先从值栈中寻找数据,未找到,再到context中寻找。
    • <s:property/>:未明确赋值的情况下,从值栈栈顶取值。

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

    • 先从request中搜索,再从值栈中搜索,最后从context搜索。
    • 为了保证请求结束以后,值栈以及context所占内容清空,值栈与context与request建立起了联系,使得通过request可以访问值栈与context中的数据。

    4.<s:set name=""value="''"scope=""/>:赋值语句,字符串必须在内层使用‘',外层使用"",未指定作用域时放在context。
    5.<s:iterator value=""/>:将遍历对象放到值栈栈顶。
    6.<s:property value="'s' in #list/>:判断某个数据是否在列表中,相应地,还有不存在判断not in。
    7.<s:push value=""/>:将数据压入栈中,以便以后访问,该标签不稳定,减少使用。 

    十 防止表单重复提交

    1.令牌机制

    首次访问表单页面,如果该页面采用了令牌机制,token拦截器生成一个随机数,将这个随机数在浏览器与服务器端各保存一份。首次提交表单时,token拦截器对比两个参数,相同,完成提交,然后服务器单方面修改该随机数,不通知浏览器。浏览器再次提交,两个参数值不相同,token拦截器返回invalid.token值,跳转到该值对应的页面,请求未到达Action对象,这样就防止了重复提交。

    2.令牌机制实现

    • 必须在表单内部插入<s:token/>,以存放服务器端生成的随机数,底层生成了一个name为token的隐藏域。(struts表单默认以post方式提交)
    • 必须使用系统创建的token拦截器,由于该拦截器不在默认的拦截器之列,需要手动添加。

    十一 国际化

    1.什么是国家化?

    使同一个事物适应多种国际环境,就叫做国际化,在Web应用程序开发中就是使页面能够按照多种语言来显示。

    2.Struts实现国际化的原理

    Struts提供了一个拦截器I18N,该拦截器会自动获取与国际化相关的请求参数,根据参数值选取相应地资源文件为程序内部的变量赋值,赋值完成后,页面按赋值结果显示。这个请求参数是request_locale,将其追加到URL后面,并按照格式request_locale=language_country赋值。

    3.Struts标签

    实现国际化需要使用Struts标签建立页面。

    4.资源文件命名

    国际化的实现依赖于资源文件,一种语言一个资源文件,资源文件的命名决定了其作用范围,共有三种命名方式:

    ⑴baseName_language_country.properties

    全局范围资源文件,对整个应用都有效。baseName可以自定义,放在scr目录下,在配置文件中配置:

    <constant name="struts.sustom.i18n.resources"value="baseName"/>

    ⑵package_language_country.properties

    包范围资源文件。 

    ⑶ActionClassName_language_county

    Action范文资源文件,放在包内。

    • 优先级由高到底:Action范围、包范围、全局范围。
    • language_country:已经被被标准化,使用时从标准中选取。

    5.资源文件的内容

    • key=value
    • key相当于变量名,命名方式:资源文件名+资源中的位置+用途。

    6.动态参数

    ⑴定义

    在资源文件中定义动态参数:keyName={0},valueContext,其中占位符从0开始。

    ⑵在java代码中赋值

    在java文件中,采用以下形式为动态参数赋值:

    String str=this.getText("key",String[] args);

    其中args是一个数组,为资源文件中的占位符赋值,这样就可以理解为什么不使用*,而且从0开始了。

    ⑶在JSP页面赋值

    <s:text name="key">
         <s:param><s:property value=""></s:param>//为第一个占位符赋值
        <s:param><s:property value=""></s:param>//为第二个占位符赋值
    </s:text>

    <s:param>标签用作传递参数,<s:property>用来取值。

    7.引用

    • JSP页面表单外:<s:text name="key"/>。
    • JSP表单内:所有表单输入标记显示文本的属性统一为key,key="key(资源文件中key)"。
    • 程序内部:String str=this.getText("key")(该方法只有继承了ActionSuppor才有效)。

    8.指定资源文件

    <s:i18n name="资源文件名相对于src的路径">
             -------指定资源-------
    </s:i18n>

    十二 注解式开发

    常用注释:

    • @ParentPackage(value=""):指定父包。
    • @Namespace(value=""):指定名称空间。
    • @Action(name="",results={@Result(name="",type="")}):配置<action>。
    • @Results({@Result(name="",type="",location="")}):配置全局<result>。
    • @InterceptorRef(name=""value=""):配置<interceptor-ref>。
    • @InterceptorRefs({@Interceptor()}):配置全部<interceptorRef>。
  • 相关阅读:
    centos7系统初始化脚本
    git上传项目到github
    requests的使用
    zip函数
    mongodb基本操作
    mongodb的安装与配置启动(转)
    jupyter插件与主题
    map函数
    centos7 安装 ffmpeg
    centos7 下 yum 安装Nginx
  • 原文地址:https://www.cnblogs.com/tonghun/p/7199970.html
Copyright © 2020-2023  润新知