struts2学习笔记

1、struts2环境的简单搭建

   

  •     必须的jar包有

           

  •   struts.xml文件格式

 

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>

</struts>
  • web.xml文件的格式
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    id="WebApp_ID" version="2.5">
    <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>
</web-app>

 以上为简单配置,然后部署启动如果在控制台没有发现错误则环境OK,此处使用的版本是struts-2.3.24,上面的jar包经测试都是必须的jar包。

知识点:

struts.xml文件:

  •     使用package对Action进行管理
  •     package的name必须唯一,继承时有用
  •     namespace作为路径的一部分
  •     自定义的package必须extends="struts-default",否则struts2的强大的拦截器功能将不会使用到
  •     如果package 的 abstract="true"则该package将不能在其中定义action,该package只能被集成
  •     action 的class指定action是哪个类,method指定方法名称
  •     struts.xml文件struts在启动时只会加载一次,后面如果有改动,需重新部署启动服务器

action类:

  • action中被调用的方法返回的是String类型,不许继承任何类
  • action中的属性在页面可直接通过EL表达式访问,不许指定访问范围

浏览器访问Action的方法如下:

  • http://主机名(或IP):8080(端口号)/struts2(应用的名称)/test(package的namespace)/test(action 的name)
  • struts2的默认访问后缀是.action,如果不加.action也是可以的

struts2路径寻找规则:

假如路径是:http://localhost:8080/app/path1/path2/path3/action.action

  1. 首先,struts2会在namespace为/path1/path2/path3的package下寻找名称为action的Action,如果找到则返回,否则进入2
  2. 然后,struts2会在namespace为/path1/path2的package下寻找名称为action的Action,如果找到则返回,否则进入3
  3. 然后,struts2会在namespace为/path1的package下寻找名称为action的Action,如果找到则返回,否则进入4
  4. 然后,struts2会在namespace为/的package下寻找名称为action的Action,如果找到则返回,否则进入5
  5. 最后,struts2会在默认的命名空间下寻找名称为action的Action,如果找到则返回,否则返回404

 struts2中Action中的默认值

  1. 如果class没有指定,则默认值是ActionSupport类
  2. 如果method没有指定,则默认值是execute方法
  3. 如果result节点的name属性没有指定,则默认值是success

   struts2中result的类型:

其中比较常用的有:dispatcher、redirect、redirectAction、plainText

  • dispatcher:默认的方式,代表请求转发
  • redirect:重定向,注意不能重定向到WEB-INFO下面的页面
  • redirectAction:重定向到Action,同一个包时不必指定namespace,但是必须指定actionName,不在同一个包时namespace和actionName都要指定

      例如:         

<result type="redirectAction">
     <param name="actionName">dashboard</param>
     <param name="namespace">/secure</param>
<result>

<result name="error" type="redirectAction">error</result>
  • plainText: 文本显示,如果乱码需要指定编码,如上通过param标签传递编码参数和资源路径即可PlainTextResult

 

 全局视图:

  •     包全局视图:通过<global-results></global-results>直接在包中定义即可
  •     全局全局视图:包和包都可以访问的全局视图,可通过包的继承实现,定义一个包,包中通过<global-results></global-results>定义全局视图,然后其他的包继承该包即可实现

在视图中的资源文件后可以通过${属性名称}带上Action的属性的值,注意如果是URL要对属性值进行URL编码。

 

struts.xml中可以通过<param name=""></param>为Action注入数据:

<action name="" type="">
            <param name="name">张三</param>
</action>


struts2可以配置常量的地方:

  1. struts-default.xml(struts2-core-2.3.24.jar)
  2. struts-plugin.xml(struts2-convention-plugin-2.3.24.jar)
  3. struts.xml (src/)
  4. struts.properties (src/)
  5. web.xml

如果在上面的文件中都配置了同一个常量的值,那么后面的值会覆盖掉前面配置的值。

 

sturts2的常量:

      默认常量的位置:struts2-core-2.3.24.jar(org.apache.struts2/default.properties)

常见常量的含义: 

struts.i18n.encoding:这个常量会作用于setCharacterEncoding方法和freemarker,velocity(这两种为模板技术)的输出,POST方式提交的数据,可以交由这个常量去设置它的编码格式。

<constant name="struts.i18n.encoding" value="UTF-8"/>

struts.configuration.xml.reload:当struts的配置文件修改后,系统是否自动重新加载该文件,默认值为false,开发阶段最好打开,开发完后再关闭。

<constant name="struts.configuration.xml.reload" value="true" />

struts.serve.static.browserCache:设置浏览器是否缓存,默认值为true,开发阶段最好关闭。

<constant name="struts.serve.static.browserCache" value="false"/>

struts.devMode:打印出更详细的错误信息,用于排错,主要用于开发模式,做好了再关闭,在copy sturts-blank中的stuts.xml中,里面有这常量。

<constant name="struts.devMode" value="true" />

struts.ui.theme:标签所使用的额外的自定义样式,不太实用,最好设置成simple,且一般都不用到struts 2的标签库。

<constant name="struts.ui.theme" value="simple" />

struts.objectFactory:与spring继承时,指定由spring负责action对象的创建,在继承spring时,会用到这个常量.

<constant name="struts.objectFactory" value="spring"/>

struts.enable.DynamicMethodInvocation:该属性设置struts2是否支持动态方法调用,该属性的默认值是true,如果需要关闭动态方法调用,则可设置该属性为false,

<constant name="struts.enable.DynamicMethodInvocation" value="true" />

注意:DMI的调用方式Struts2的文档不建议使用,且下载的struts2-2-X.jar中,它的sturts-blank中sturts.xml有这常量,并设其值为false。

 

struts.multipart.maxSize:设置上传文件的总大小限制

<constant name="struts.multipart.maxSize" value="20971520" />

struts.action.extension:修改后缀名,默认是action,可以修改。若值有多个,可用逗号隔开,这对于常量的值都通用。

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

struts.custom.i18n.resources:用于配置国际化全局XML资源文件,须在指明该全局资源文件的基础名。

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

struts.ognl.allowStaticMethodAccess:如其名,用于设置OGNL是否允许静态方法访问,默认为false。

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

 struts2流程图(官网的一张)

struts2的简单流程:

客户端请求来临时,StrutsPrepareAndExecuteFilter进行处理,如果请求是以.action或者为空则转给Intecepter(准确的说是一系列拦截器,这些拦截器都是struts2的核心连接器),拦截器处理完成后交由Action进行处理,Action处理结束后返回result视图的名称,最后把视图返回给客户端。值得注意的是struts2的Action是线程安全的,因为struts2会对每一个请求实例化一个Action进行对请求的处理。

 

为struts2指定多个配置文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
    <include file="default.xml"></include>
    <include file="other.xml"></include>
</struts>


struts2的动态方法调用:

  • 感叹号的形式

假如Action中有两个方法,一个方法使add另一个方法使delete,Action的名称为xxxAction,应用名称为test,action的命名空间为test,则感叹的动态方法调用如下:

htttp://localhost:8080/test/test/xxxAction!add.action

struts2官方不建议使用这种形式的动态方法调用,可以通过下面的常量配置是否支持动态方法调用

<constant name="struts.enable.DynamicMethodInvocation" value="true" />
  • 通配符的形式

假如Action中有两个方法,一个方法使add另一个方法使delete,Action的名称为xxxAction,应用名称为test,struts.xml配置文件如下:

<package name="test" namespace="/test" extends="struts-default">
        <action name="test_*" class="xxxAction" method="{1}">
            <result name="success" >/WEB-INF/jsp/hello.jsp</result>
        </action>
</package>

则客户端的调用形式如下
       http://localhost:8080/struts2/test/test/test_add

注意:一个*好就代表一个通配符,{1}代表action name中的第一个*,如果有多个直接修改{}中的数值即可。通配符的位置可以出现在很多地方,不仅仅是上面的例子看到的那样。

 struts2 Action对请求参数的接收:

  • 基本类型的接收

             Action属性的名称和页面表单的字段的名称一致,且Action中属性必须存在set方法

  • 复合类型的接收

            复合类型在Action中必须存在set方法,页面使用复合类型属性.复合类型内部的属性传递参数

             如 Person有个name属性,那么 在页面访问时可以通过person.name

 

struts2类型转换器:

  •    局部类型转换器
  1. 定义类型转换器:该转换器集成com.opensymphony.xwork2.conversion.implDefaultTypeConverter并重写convertValue(Map<String, Object> context, Object value, Class toType)
  2. 注册类型转换器:在Action所在的包下创建actionName-conversion.properties(actionName:Action的简单类名,也就是不带包的类型)文件,文件的内容为Action中需要转换的属性=类型转换器的全名称
  •    全局类型转换器
  1. 定义类型转换器:该转换器集成com.opensymphony.xwork2.conversion.implDefaultTypeConverter并重写convertValue(Map<String, Object> context, Object value, Class toType)
  2. 注册类型转换器:在类路径下创建xwork-conversion.properties文件,文件的内容为需要转换的数据类型(全名称)=类型转换器的全名称

 

struts2向request、session、application范围存放数据:

ActionContext act = ActionContext.getContext();
act.getApplication().put(key, value)// application范围存放数据
act.getSession().put(key, value)// session范围内存放数据
act.put(key, value) // request范围内存放数据

 

struts2获取request、session、application等对象

ServletActionContext.getRequest()
ServletActionContext.getServletContext()

 

另外一种获取request、session、application等对象的方法使实现相应的接口,由容器自动注入这些对象,例如:ServletRequestAware,其他的接口与该接口类似

 

struts2文件上传

  1.  页面表单的method="post" enctype="multipart/form-data"
  2. Action中通过如下的字段接收客户端传递的文件资源
private File image; // 与file表单的name一致
private String imageFileName; // 文件名称
private String imageContentType; // 文件的类型

服务端可通过FileUtils 对文件进行保存。

 

多文件上传:

        只需将接收的参数设置问数组形式的就OK了。

private File image[]; // 与file表单的name一致
private String imageFileName[]; // 文件名称
private String imageContentType[]; // 文件的类型

 

struts2拦截器:

拦截器的定义:拦截器必须实现com.opensymphony.xwork2.interceptor.Interceptor接口,并实现intercept(ActionInvocation invocation)方法,

                    如果在intercept方法中不调用invocation.invoke()方法则Action中的方法将得不到执行的机会。

拦截器在Action中的使用:

struts.xml中拦截器的配置:

<package name="test" namespace="/test" extends="struts-default">
        <interceptors>
            <interceptor name="permisson" class="xxx.PermissionInterceptor">   </interceptor>
        </interceptors>      
</package>

Action中拦截器的使用:

<package name="test" namespace="/test" extends="struts-default">
        <interceptors>
            <interceptor name="permisson" class="xxx.PermissionInterceptor"></interceptor>
        </interceptors>
        <action name=" " class=" " method=" ">
            <interceptor-ref name="permisson"></interceptor-ref>
            <result name="success" ></result>
        </action>
</package>

注意:如果Action中指定了拦截器那么系统默认的拦截器将不会被使用,系统默认的拦截器在文件struts-default.xml中,如下:

<interceptor-stack name="defaultStack">
                <interceptor-ref name="exception"/>
                <interceptor-ref name="alias"/>
                <interceptor-ref name="servletConfig"/>
                <interceptor-ref name="i18n"/>
                <interceptor-ref name="prepare"/>
                <interceptor-ref name="chain"/>
                <interceptor-ref name="scopedModelDriven"/>
                <interceptor-ref name="modelDriven"/>
                <interceptor-ref name="fileUpload"/>
                <interceptor-ref name="checkbox"/>
                <interceptor-ref name="datetime"/>
                <interceptor-ref name="multiselect"/>
                <interceptor-ref name="staticParams"/>
                <interceptor-ref name="actionMappingParams"/>
                <interceptor-ref name="params"/>
                <interceptor-ref name="conversionError"/>
                <interceptor-ref name="validation">
                    <param name="excludeMethods">input,back,cancel,browse</param>
                </interceptor-ref>
                <interceptor-ref name="workflow">
                    <param name="excludeMethods">input,back,cancel,browse</param>
                </interceptor-ref>
                <interceptor-ref name="debugging"/>
                <interceptor-ref name="deprecation"/>
</interceptor-stack>

那么我们应该在package中定义一个拦截器栈,然后在给Action使用

<interceptors>
            <interceptor name="permisson" class="xxx.PermissionInterceptor"></interceptor>
            <interceptor-stack name="permissonStack">
                 <interceptor-ref name="defaultStack"></interceptor-ref>
                 <interceptor-ref name="permisson"></interceptor-ref>
            </interceptor-stack>
</interceptors>

注意系统默认的拦截器应该在我们自定义的拦截器前面,因为拦截器的调用时按照在文件中的配置顺序执行的。

然后在对我们的Action应用这个拦截器栈。

 

对package中所有的Action都应用同一个拦截器,如下配置即可对package下的所有Action都使用了拦截器permissonStack:

<default-interceptor-ref name="permissonStack"></default-interceptor-ref>

 

如果Action一次要使用多个拦截器,那么可以在Action通过多个<interceptor-ref name=""></interceptor-ref>指定拦截器。

值得注意的是,如果Action中指定了拦截器,那么默认的拦截器和package内默认的拦截器将都不会被使用到。

 

struts2的输入校验

  1. 编码校验
  2. xml配置文件校验
  •  编码校验
    • 所有方法校验
    • 指定方法校验

所有方法校验,类必须继承ActionSupport类,然后重写validate()方法,在该方法中对数据进行验证,如果存在问题则调用addFieldError(String fieldName, String errorMessage)方法,如果校验出现不通过的情况,那么就会返回input视图。

 

针对Action中的某个方法进行校验,只需要在Action中实现validateXxx方法,Xxx为方法的签名,其他的和所有方法校验一致。

 当类型转换异常或者校验失败时,fieldErrors不为空,则会进入input视图。

 

基于XML文件的输入校验:

  1. Action也必须继承ActionSupport
  2. 编写校验文件

基于XML所有方法校验:

编写XML文件,文件的命名格式为ActionClassName-validation-xml,ActionClassName为Action的简单类名。该文件应该与Action在同一个包中。

校验文件格式如下:

<!DOCTYPE validators PUBLIC
        "-//Apache Struts//XWork Validator 1.0.3//EN"
        "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">

<validators>
    <field name="username">
        <field-validator type="requiredstring">
            <message key="requiredstring"/>
        </field-validator>
    </field>
</validators>

filed节点的name为Action中属性的名称,field-validator的type属性指定了校验器,message为校验不通过的提示信息(注意Action应该配置input视图)。

所有的校验器我们可以在work-core-2.3.24.jar jar包下 com/opensymphony/xwork2/validator/validators/default.xml找到,如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
        "-//Apache Struts//XWork Validator Definition 1.0//EN"
        "http://struts.apache.org/dtds/xwork-validator-definition-1.0.dtd">

<!-- START SNIPPET: validators-default -->
<validators>
    <validator name="required" class="com.opensymphony.xwork2.validator.validators.RequiredFieldValidator"/>
    <validator name="requiredstring" class="com.opensymphony.xwork2.validator.validators.RequiredStringValidator"/>
    <validator name="int" class="com.opensymphony.xwork2.validator.validators.IntRangeFieldValidator"/>
    <validator name="long" class="com.opensymphony.xwork2.validator.validators.LongRangeFieldValidator"/>
    <validator name="short" class="com.opensymphony.xwork2.validator.validators.ShortRangeFieldValidator"/>
    <validator name="double" class="com.opensymphony.xwork2.validator.validators.DoubleRangeFieldValidator"/>
    <validator name="date" class="com.opensymphony.xwork2.validator.validators.DateRangeFieldValidator"/>
    <validator name="expression" class="com.opensymphony.xwork2.validator.validators.ExpressionValidator"/>
    <validator name="fieldexpression" class="com.opensymphony.xwork2.validator.validators.FieldExpressionValidator"/>
    <validator name="email" class="com.opensymphony.xwork2.validator.validators.EmailValidator"/>
    <validator name="url" class="com.opensymphony.xwork2.validator.validators.URLValidator"/>
    <validator name="visitor" class="com.opensymphony.xwork2.validator.validators.VisitorFieldValidator"/>
    <validator name="conversion" class="com.opensymphony.xwork2.validator.validators.ConversionErrorFieldValidator"/>
    <validator name="stringlength" class="com.opensymphony.xwork2.validator.validators.StringLengthFieldValidator"/>
    <validator name="regex" class="com.opensymphony.xwork2.validator.validators.RegexFieldValidator"/>
    <validator name="conditionalvisitor" class="com.opensymphony.xwork2.validator.validators.ConditionalVisitorFieldValidator"/>
</validators>
<!--  END SNIPPET: validators-default -->

假如我们的Action为UserAction,那么校验文件的命名应该为:UserAction-validation.xml。

 

基于XML对Action中的指定方法进行校验,大体上和对所有方法校验一样,只是校验文件的命名有所变化。文件命名的格式是:ActionClassName-actionName-validation.xml,其中actionName为struts.xml中Action的配置名称。例如:

假如我们的Action为UserAction,在UserAction中有两个方法,分别为add、delete,UserAction的配置如下:

<package name="user" namespace="/user" extends="struts-default">
        <action name="user_*" class="com.xxx.UserAction" method="{1}">
            <result name="input">/WEB-INFO/page/input.jsp</result>
        </action>
</package>

那么如果我们需要对add方法校验,那么校验文件的命名应该为UserAction-user_add-validation.xml,该文件与Action在同一个包下。

 

如果一个Action既有所有方法校验配置文件也有方法校验配置文件,那么struts2会搜索所有的检验文件,对于方法校验以方法校验文件为准。

 

struts2国际化:

全局范围的国际化、包范围的国际化、action范围的国际化。

 

国际化资源文件的命名规则:

baseName_language_country.properties

baseName_language.properties

baseName.properties

其中baseName可为任意值

比如汉语国际化资源文件命名:resources_zh_CN.properties,美国英语资源文件为:resources_en_US.properties

 

全局资源文件应该放在src目录下。

 

struts.xml中可通过常量引入全局资源文件:

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

jsp页面访问国际化资源:

<s:text name="key" />

key为国际化资源文件中的key。

Action中访问国际化资源文件需要继承ActionSupport,通过getText()方法获取。

 

带占位符的国际化资源的访问:

name={0}你好,{1}
<s:text name="key" >
    <s:param> </s:param>
    <s:param> </s:param>
</s:text>

 

包范围的国际化资源的命名格式package_language_country.properties,package为固定写法。包范围的国际化资源可以被该包和子包进行访问,访问格式和访问全局国际化资源文件一样。如果在包范围内找不到,则会去全局范围内找。

 

Action范围的国际化资源文件的命名格式ActionClassName_language_country.properties,ActionClassName为Action的简单类名称。

 

OGNL表达式:Object Graphic Navigation Language(对象图导航语言)的缩写,struts2框架默认使用OGNL做为表达式语言。

OGNL有一个上下文的概念,在struts2中上下文的实现时ActionContext。结构图如下:

当struts2接收到一个请求时,会迅速的创建ActionContext、ValueStack、action,然后把action存放进ValueStack中,所以action中的实例变量可以被OGNL访问。

 

访问上下文(Context)中的对象需要使用#标注命名空间,如#application、#session

 

另外OGNL会设定一个根对象(root对象),在struts2中根对象就是ValueStack(值栈),如果需要访问根对象中的对象属性,则可以不加#命名空间,直接访问该对象的属性即可。

 

在struts2中,根对象ValueStack的实现类为OgnlValueStack,该对象可以存放一组对象,在OgnlValueStack类里有一个List类型的root变量,就是使用它存放一组对象。

 

在root变量中处于第一位的对象叫栈顶对象,通常我们在ONGL表达式里直接写上属性名即可访问root变量里对象的属性。搜索顺序是从栈顶开始寻找,如果栈顶对象不存在该属性,就会从第二个对象寻找,如果没有找到,则从第三个对象寻找,知道找到为止。

 

值得注意的是,OGNL表达式需要配合struts2的标签才可以使用。

 

由于ValueStack是struts2中OGNL的根对象,那么可以直接使用EL表达式直接访问值栈中的对象的属性。

 

如果是其他的Context中的对象,由于他们不是根对象,所以访问时需要添加#前缀。

application对象:用于访问ServletContext,例如#application.userName或者#application["userName"]相当于调用ServletContext的getAttribute("userName");

 

session对象:用于访问HttpSession对象,例如:#session.userName或者#session["userName"]相当于调用seesion.getAttibute("userName")

 

request对象:用来访问HttpServletRequest属性(attribute)的Map,例如#request.userName或者#request["userName"],相当于调用requset.getAttribute("userName")

 

parameters对象:用于访问HTTP的请求参数,例如#parameters.userName或者#parameters["userName"]相当于调用request.getParameter("userName")

 

attr对象:用于按page->request->session->application顺序访问其属性

 

OGNL表达式创建List/Map集合对象

 

使用如下代码创建一个List集合对象:

<s:set name="list" value="{'a', 'b', 'c'}"/>

遍历List集合:

<s:iterator value="#list"> 
    <s:property/><br/>
</s:iterator>

Set标签用于将某个值存放在指定的范围内

scope:指定变量被存放的范围,该属性可接受application、seesion、request、page、action,如果没有设置该属性,则默认放置在OGNL Context中。

value:赋给变量的值,如果没有设置该属性,则将ValueStatck栈顶的值赋给变量

 

生成Map集合:

<s:set name="map" value="#{'key1':'value1', 'key2':'value2'}"/>

遍历Map集合

<s:iterator value="#map">
    <s:property value="key"/>
    <s:property value="value"/>
</s:iterator >

iterator标签的特点:该标签会把当前遍历的元素放置在值栈的栈顶。
property标签的特定,如果value没有指定,则表示输出值栈栈顶的元素。


OGNL表达式可以判断对象是否存在于某个集合中:
in:表示对象在集合中
not in: 表示对象不在集合中

<s:if test="'a' in {'a','b'}"></s:if>
<s:else>
    不在
</s:else>


<s:if test="'a' not in {'a','b'}"></s:if>
<s:else>
    不在
</s:else>

OGNL表达式的投影功能

常用的有以下几个:

?:获取所有符合逻辑的元素

^:获取符合逻辑的第一个元素

$:获取符合逻辑的最后一个元素

使用方式:

<s:iterator value="books.{?#this.price>35}">
    <s:property value="title"/>
    <s:property value="price"/>
</s:iterator>

上面代码直接在集合后面紧跟  .{}  运算符表明用于取出该集合的子集,{}内的表达式用于获取符合条件的元素,this指的是为了从大集合中筛选元素到小集合中,需要对大集合进行迭代,this代表当前迭代的元素。

 

OGNL栈顶的元素可以直接使用EL表达式访问。

 

posted @ 2015-08-22 15:49  天之涯0204  阅读(192)  评论(0编辑  收藏  举报