Structs2

一.Structs2helloworld

1.加入Struts2所依赖jarstruts-2.2.1.1\apps\struts2-blank\WEB-INF\lib\*.jar

2.web.xml配置我们的核心控制器StrutsPrepareAndExecuteFilter

3.新建一个Action,这个类很普通不用继承任何类

4.在classpath新建struts.xml文件

5.action通用方式

http://localhost/appName/<PackageNamespace>/<ActionName>.<Extension>

<PackageNamespace> 代表你在struts.xml中配置package的namespace!

action配置中name! <Extension>默认可不写或者是.action

二.常量配置

1.在根元素<struts>下可以使用constant子元素配置常量。

2.strut2的核心jar包内的org.apache.struts2包下的default.properties文件中可以看到   各个常量的注释说明,典型几个常量:

<constant name="struts.action.extension" value="do,go"/>配置访问Action的后缀,可以配置多个后缀名。 提示:default.properties文件中为该常量配置了一个空字符串。

<constant name="struts.devMode" value="true"/>可以让struts在控制台中打印出更多的信息和重新加载配置文件。

<constant name="struts.enable.DynamicMethodInvocation" value="false"/>可以配置不支持动态方法调用。

<constant name="struts.configuration.xml.reload" value="true"/>可以让struts重新加载配置文件,但不会导致web应用重新启动。

3.常量可以在下面多个文件中进行定义,struts2加载常量的搜索顺序如下,后面的设置   可以覆盖前面的设置:

default.properties文件

struts-default.xml

struts-plugin.xml

Struts.xml(建议放到该文件中)

struts.properties(为了与webwork向后兼容而提供)

web.xml

三.包与Action的定位

如果不存在相应的包,则查找上一层的包名,注意,只要一旦追溯到了一个最匹配的上层包名,不管这个包中是否存在要访问的Action,都不会再追溯更上层的包名了。如果struts2定位到的包名中不存在当前要访问的Action struts2接着会在默认名称空间寻找该Action,只有在默认名称空间的包名中没找到该action时,才报错action找不到的错误。

注意(“/算是一个包,只是这个包比较特殊!

四.result标签及其配置

1.structs2中的result类似于structs1中的<forward>标签。但structs2提供了多种结果类 型,如dispatcher(默认值)redirectredirectActionplainText

2.redirectAction举例

如果重定向的action在同一个包下:

<result type="redirectAction">HelloAction</result>

如果重定向的action在别的包下:

<result type="redirectAction">

<param name="actionName">helloAction</param>

<param name="namespace">/test</param>

</result>

3.plainText显示原始文件内容,如需要原样显示jsp文件源代码时:

<result name="source" type="plainText">

<param name="location">/xxx.jsp</param> //name默认值为location,可省略

<param name="charSet">UTF-8</param>  //指定读取文件的编码

</result>

4.如果没有指定resultname属性,默认为success

五.为action的属性注入值

1.在action类中需要提供setter方法;

2.在配置文件中的<action>中使用<param>注入action属性值。如,向HelloworldAction 中的sName属性注入“sValue”值。

<action name="helloworld" class="cn.itcast.hello.HelloworldAction">

<param name="sName">sValue</param>

</action>

六.Struts.xml中的默认值与更多配置细节

1.在根元素<struts>下可以使用include子元素引入其他的配置文件,这样可以将各个模 块分散在不同的配置文件中进行配置。

2.package元素下可以定义全局视图,如果两个package要共享相同的全局视图,那么为 它们定义一个相同的父包。

3.<action>元素的method属性可以不设置,默认为executeclass属性可以不设置,默 认为ActionSupport。 

4.<result>元素的type属性和name属性都可以不设置,默认值分别为dispatcher success。当<result>元素中只有默认的<param>子元素要设置时,可以将该<param> 子元素中的内容直接写在<result>标签中。

5.在<package>元素下配置<default-action-ref>子元素,用于说明在该包下不存在的action 路径映射,都可以统交给一个默认的<action>元素去处理。

6.在<package>元素下配置<default-class-ref>子元素,用于说明默认的Action类是可以进 行配置修改的。

7.使用Config Browser Plugin浏览已经装载的配置信息和列表针对各个包名称空间下的 所有Action的访问链接。(详见630的视频300:31:00段视频)

七.Structs2的处理流程

当用户发出请求后,web.xml中的StrutsPrepareAndExecuteFilter核心控制器进行拦截过滤。一般情况下,它负责拦截所有的用户请求。默认情况下,如果用户的请求路径不带后缀或者以“.action”结尾,这是请求将被转入structs2框架处理,否则structs2忽略请求。当请求转入structs2框架时会先经过一系列的拦截器,然后再到action

structs1不同,structs2对用户的每一次请求都会创建一个action,所有structs2中的action是线程安全的。

八.使用include为应用指定多个structs配置文件

在实际应用开发中,一般是以模块进行structs配置文件的划分。

九.动态方法调用

1.如果Action中存在多个方法时,在struts.xml文件中可以只配置一个<action>元素,访 问路径可以在紧跟action名称的后面增加一个感叹号(!)后接着指定要访问的方 法名,这就是动态方法调用,语法格式如下:

http://ip:port/AppPath/<PackageNamespace>/<ActionName>!<MethodName>.<extension>

举例:

http://localhost:8080/struts2demo/user/admin/view1Action!sayHello1.action

2.可以通过常量struts.enable.DynamicMethodInvocation关闭动态方法调用。

3.尽量不要使用动态方法调用,可以采用*通配符的方式进行替代。

十.*通配符

1.在action元素的name属性中可以使用*通配符,它可以匹配除了“/”以外的多个连 续字符,在action元素的classmethod属性以及result元素中可以引用*通配符 在访问期间实际匹配的内容。

2.如果*匹配的内容为空,则调用execute方法;对于采用下划线连接*的方式,如果访 问路径中没有为*部分指定内容,那么在访问路径中可以省略下划线。

3.使用*通配符可能导致有多个action元素与一个访问路径匹配,这时候以排在配置文 件中最后的配置项为准,所以更具体的模式应在更不具体的模式之后进行配置。

十一.接收请求参数

1.采用基本类型接受请求参数(get/post

action类中定义与请求参数同名的属性,structs2便能自动接受请求参数并赋予 给同名属性。如:

请求路径:http://localhost/test/view.action?id=78

public class ProductAction{

public Integer id;

settergetter.......

}

structs2通过反射技术调用与请求参数同名的属性的setter方法来获取请求参数值。

2.采用复合类型接收请求参数

请求路径:http://localhost/test/view.action?product.id=78

public class ProductAction{

private Product product;

settergetter.....

}

Structs2首先通过反射技术调用Product的默认构造器创建product对象,然后通过 反射技术调用product中的请求参数同名的属性的setter方法来获取请求参数值。

3.其他

<1>Struts框架在把请求交给action的业务方法去处理之前,可以将请求参数来填 充到Action的相应属性中,所以,对于请求消息中的每个参数(包括网页表 单中的每个字段),Action中 通常都有一个对应的属性来接受相应的参数值。

<2>action的业务方法中可以访问Servlet API,通过request.getParameter获得 参数,框架使用中不建议这种方法。

<3>structs2.1.6的版本中,会出现中文乱码问题,可以自己写一个filter,在structs2 之前进行过滤。

十二.自定义类型装换器

1.Structs2有两种类型装换器

局部类型转换器:即只对某个action作用。

全局类型转换器:即对所有action中的指定类型作用。

注意:使用全局类型转换器是在确保整个应用该类型都使用该类型转换器。如果一  个应用的该类型有多个类型转换器,则使用局部类型转换器。

2.自定义类型装换器使用

<1>新建一个类,实现TypeConverter接口,或者继承DefaultTypeConverter StrutsTypeConverter两个类中的一个,此处使用DefaultTypeConverter进行说 明,其他两种方式基本类似。

<2>重写convertValue(Map<String,Object> context,Object value,Class toType)方法

<3>进行局部类型转换器注册

action类所在的包下放置ActionClassName-conversion.properties文件;

properties文件中的内容为:action中的转换类型属性名称=类型转换器的全 类名。

<4>进行全局类型转换器注册

WEB-INF/classes下放置xwork-conversion.properties

properties文件中的内容为:待转换的类型全名称=类型转换器的全类名。

十三.添加或者访问request/session/application属性

1.ActionContext context = ActionContext.getContext();

如果只是像作用域添加或者访问属性,则使用ActionContext方式。

2.获取HttpServletRequest/HttpSession/ServletContext/HttpServletResponse对象

方法一:通过ServletActionContext类直接获取。建议使用

方法二:实现ServletRequestAwareServletResponseAwareServletContextAware 接口,由structs2框架运行时注入。

十四.文件上传

1.要想让浏览器把文件内容传给服务器,必须将form表单的enctype属性设置为 "multipart/form-data",提交方式必须是post

2.文件过大,请求将会被拒绝。在structs.xml中可以更改它的最大文件上传限制。

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

3.文件上传action类中的命名一定要符合structs2的规范。

上传文件的名称必须是:上传文件+FileName;

上传文件的类型必须是:上传文件+ContentType

如:上传文件名称为:uploadFiles,则上传文件的名称命名是uploadFilesFileName上传文件的类型命名为uploadFilesContentType,切勿写成uploadFileFileNames

十五.拦截器(interceptor)

1.自定义拦截器

<1>定义一个类实现interceptor接口

<2>structs.xml中注册拦截器

<3>action应用拦截器

2.其他

<1>一旦为某个action显式指定了某个拦截器,则所属包中定义的默认拦截器将不 作用。

<2>如果想保留structs2的拦截器,又想使用我们自定义的拦截器,可以定义一个 拦截器栈。

<3><default-interceptor-ref name="defaultStack"/>把拦截器定义为默认的拦截器。每 个包只能定义一个默认的拦截器。

十六.输入校验

可以对action中的指定方法和所有方法进行校验。

1.提供了两种实现方式

采用手工编写代码实现

基于xml配置方式实现

2.手工编写代码对action中所有方法进行校验

通过重新validate()方法实现,当某个数据校验失败时,应该调用addFieldError() 法往系统的fieldErrors添加校验失败信息。为了使用addFieldError()方法,action 可以继承ActionSupport,如果系统的fieldErrors包含失败信息,structs2会将请求 转发到名为inputresult,在input视图中可以通过<s:fielderror/>显示失败信息。

<1>提供validate方法

<2>提供input视图,一般该视图为提交信息的页面。

<3>在编辑页面导入s标签,使用<s:fielderror/>显示失败信息。

3.手工编写代码对action中指定方法进行校验

通过validateXxx()方法实现,它之后校验action中方法名为xxx的方法。

4.输入校验流程

<1>类型转换器对请求参数执行类型转换,并把转换后的值赋给action中的属性。

<2>如果在执行类型转换的过程中出现异常,系统会将异常信息保存到 ActionContextconversionError拦截器将异常信息封装到fieldError里。不管类型 转换是否出现异常,都会进入第3步。

<3>系统通过反射技术先调用action中的validateXxx()方法,Xxx为方法名。

<4>再调用action中的validate()方法。

<5>经过上面四个步骤,如果系统中的fieldErrors存在错误信息(即存放错误信息的 集合的size大于0),系统自动将请求转发至名称为input的视图。如果系统中的 fieldErrors没有任何错误信息,系统将执行action中的处理方法。

注意:如果确认validate方法中没有问题,但是跳到input视图时,需要判断类   型是否转换失败。

5.基于xml方式对action中所有方法进行校验

使用xml配置方式实现输入校验,action需要继承ActionSupport,并且提供校验文件,校验文件和action类纺织同一个包下。文件的取名格式为:ActionClassName-validation.xml

采用配置文件校验方式校验后,Action中的validatable有关的校验方法会执行,且配置文件校验方式在validate校验方法之前执行。

系统定义的校验器在xwork-2.x.jar...validators包下的default.xml中找到。

6.基于xml方式对action中指定方法进行校验

xml文件的取名格式为:ActionClassName-actionName-validation.xml 。如:

UserAction-user_add-validation.xmlaction的名称是由url路径决定的)。

在处理请求方法上使用@SkipValiation注解,配置文件校验方式将无效。

7.基于xml校验的一些特点

当为某个action提供了所有方法和指定方法校验两种规则时,系统会先寻找所有方法的校验文件,然后继续寻找指定方法的校验,当寻找完所有的相关校验文件后,会将所有的校验规则进行汇总,然后全部应用于action的校验。如果两个校验文件中指定的校验规则发生冲突,则只使用后面文件中的校验规则。

action继承了另一个action,父类的action校验文件会先被搜索到。

十七.国际化

1.properties文件查询规则:如app_jp_ja.properties

当前服务器只有enzh和默认的支持。

先找app_jp_ja.properties,然后找app_jp.properties,然后找服务器本地的zh

2.配置全局资源与输出国际化信息

structs.xml中通过structs.custom.i18n.resources常量把资源文件定义为全局资源文件,如:

<constant name="structs.custom.i18n.resources" value="test"/>

其中test为资源文件的基本名。

然后我们就可以在页面或在action中访问国际化信息:

<1>jsp页面中使用<s:text name=""/>标签输出国际化信息,name为文件中的key

<2>action类中,可以继承ActionSupport,使用getText()方法得到国际化信息, 该方法的第一个参数用于指定资源文件中的key

<3>在表单标签中,通过key属性指定资源文件中的key,如:

<s:textfield name="realname" key="user"/>

3.配置包范围资源文件

在一个大型医用中,为了防止资源文件过于庞大臃肿,我们可以针对不同模块,使用包范围来组织国际化文件。方法如下:

java的包下放置package_language_country.properties资源文件,package为固定写法,处于该包及子包下的action都可以访问该资源。当查找指定的key的消息时,系统会先从package资源文件查找,当找不到对应的key时才会从常量structs.custom.i18n.resources指定的资源文件中寻找。

4.为某个action单独指定资源文件,方法如下:

action类所在的路径,放置ActionClassName_language_country.properties文件。

当查找指定key的消息时,系统会先从ActionClassName_language_country.properties资源文件查找,如果没有找到对应的key,然后沿着当前包往上查找基本名为package的资源文件,一直找到最顶层包。如果没有找到对应的key,最后会从常量structs.custom.i18n.resources指定的资源文件中寻找。

5.jsp中直接访问某个资源文件

使用<s:i18n>标签可以在类路径下直接从某个资源文件中获取国际化数据,无需任何配置。如:

<s:i18n name="test">

<s:test name="welcome"/>

</s:i18n>

test为类路径下资源文件的基本名。

如果要访问的资源文件在类路径的某个包下,可以这样访问:

<s:i18n name="cn/heimar/action/package">

<s:test name="welcome"/>

</s:i18n>

上面访问cn.heimar.action包下基本名为package的资源文件。

6.输出带有占位符的国际化信息

资源文件内容如下:

welcome={0},欢迎来到{1}

jsp页面输出带占位符的国际化信息

<s:test name="welcome">

<s:param><s:property value="realname"/></s:param>

<s:param>中国</s:param>

</s:test>

action类中获取带占位符的国际化信息,可以使用getTest(String key,String[] args)或者getTest(String TextName,List args)方法。

十八.OGNL表达式

1.概述

Object Graphic Navigation Language对象图导航语言。structs2框架使用OGNL作为默认的表达式语言。

相对于EL表达式,它提供了:

<1>支持对象方法的调用,如:xxx.sayHello();

<2>支持类静态方法调用和值的访问,表达式格式为:@[类全名]@[方法名|值名] 如:@java.lang.String@format('foo %s','bar')@cn.heimar.Constant@APP_NAME;

<3>操作集合对象。

OGNL有一个上下文(Context)概念,其实就是一个Map结构,它实现了java.utils.Map接口。在structs2中上下文(Context)的实现为ActionContext

2.OGNL的使用

访问上下文(Context)中的对象需要使用#符合标注命名空间。如:#session

OGNL会设定一个跟对象(root对象),structs2中根对象就是ValueStack(值栈)。如果要访问根对象中对象的属性,则可以省略#命名空间,直接访问该对象的属性即可。

structs2中,跟对象ValueStack的实现类为OgnlValueStack,该对象不是我们想象的只存放单个值,二十存放一组对象。在OgnlValueStack类里有一个List类型的root变量,就是使用它存放一组对象。

|--request

|--application

context---|--OgnlValueStack (root变量[action,OgnlUtil,...])

|--session

|--attr

|--parameters

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

注意:structs2中,OGNL表达式需要配合structs标签才可以使用。如:<s:property value="name"/>

3.访问对象及其属性

由于ValueStackstructs2中的OGNL的根对象,如果用户需要访问值栈中的对象,在jsp页面可以通过EL表达式访问ValueStack中对象的属性:

${foo}  //获得值栈中某个对象的foo属性。

因为structs2HttpServletRequest做了进一步封装,所以我们能够直接使用EL表达式访问ValueStack中对象的属性。

如果访问其他Context中的对象,需要添加#前缀。

<1>application对象。用于访问ServletContext。如:#application.userName #application['userName'],相当于调用ServletContext.getAttrubute("userName");

<2>session对象。用来访问HttpSession

<3>request对象。用来访问HttpServletRequest

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

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

4.集合对象与操作

{}用于创建List集合对象,其中的各个元素之间用逗号分隔。

<s:set value={1,3,5,7}” var=list/>

采用类似Java的语法创建数组

<s:set value=new int[]{1,3,5,7}” var=array/>

<s:set value=new int[4]” var=array/>

#{}用于创建Map集合对象,其中的各个元素之间用逗号分隔,元素的keyvalue 之间采用冒号分隔。另外,可以指定Map实例对象的类型。

<s:set value=#{lhm:96,zxx:93,xpc:97}

<s:set value=#@java.util.LinkedHashMap@{lhm:96,zxx:93,xpc:97}

scope:指定变量被放置的位置,该属性可以接受applicationsessionrequestpageaction。如果没有设置该属性,则默认放置在OGNL Context中。

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

innot in:判断对象是否存在于集合中。

5.OGNL表达式的投影和过滤

OGNL允许使用某个规则获得集合对象的子集,常用以下三个相关操作符:

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

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

$:获得符合逻辑的第一个元素。

使用方法:

直接在集合后紧跟“.{}”运算符表明用于取出该集合的子集。

十九.Structs2常用标签

Structs2的标签会帮我们生成许多html标签,使得我们不能很好的控制html页面。解决方式是:在structs.xml中使用常量

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

二十.防止重复提交

1.原理:

使用<s:token>标签放置重复提交,<s:token>标签在session中生成Token号码和在网页中生成一个带有该号码的隐藏字段。

2.使用

<1>form表单中加入<s:token/>

<2>structs.xmlaction中使用token拦截器(注意引入系统默认的拦截器)

使用<result name="invalid.token">/指定页面</result>,可以在重复提交后返回到指定页面。

二十一.访问静态资源

1.当项目加载structs2jar包后,可以通过浏览器直接访问它的静态资源。其思想是通 过输入输出流读取文件。

如:http://localhost/struts/domTT.js

2.我们可以访问自己的class文件

web.xml中的配置structs2<filter>中添加参数:

<init-param>

<param-name>packages</param-name>

<param-name>要设置访问的静态资源包名</param-name>

</init-param>

访问方式:http://localhost/static/类名.class

 

 

 

知识点滴:

如果你的操作系统是windows7,则add library时,jar包的名称中不能有“-”等特殊字符,否则会报异常。

posted @ 2013-07-23 12:40  行者无疆A  阅读(265)  评论(0)    收藏  举报