Structs2
一.Structs2的helloworld
1.加入Struts2所依赖jar包struts-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(默认值),redirect,redirectAction,plainText。
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.如果没有指定result的name属性,默认为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属性可以不设置,默认为execute;class属性可以不设置,默 认为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的访问链接。(详见6月30的视频3中00: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元素的class和method属性以及result元素中可以引用*通配符 在访问期间实际匹配的内容。
2.如果*匹配的内容为空,则调用execute方法;对于采用下划线连接*的方式,如果访 问路径中没有为*部分指定内容,那么在访问路径中还可以省略下划线。
3.使用*通配符可能导致有多个action元素与一个访问路径匹配,这时候以排在配置文 件中最后的配置项为准,所以更具体的模式应在更不具体的模式之后进行配置。
十一.接收请求参数
1.采用基本类型接受请求参数(get/post)
在action类中定义与请求参数同名的属性,structs2便能自动接受请求参数并赋予 给同名属性。如:
请求路径:http://localhost/test/view.action?id=78
public class ProductAction{
public Integer id;
setter和getter.......
}
structs2通过反射技术调用与请求参数同名的属性的setter方法来获取请求参数值。
2.采用复合类型接收请求参数
请求路径:http://localhost/test/view.action?product.id=78
public class ProductAction{
private Product product;
setter和getter.....
}
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类直接获取。建议使用
方法二:实现ServletRequestAware、ServletResponseAware、ServletContextAware 接口,由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会将请求 转发到名为input的result,在input视图中可以通过<s:fielderror/>显示失败信息。
<1>提供validate方法
<2>提供input视图,一般该视图为提交信息的页面。
<3>在编辑页面导入s标签,使用<s:fielderror/>显示失败信息。
3.手工编写代码对action中指定方法进行校验
通过validateXxx()方法实现,它之后校验action中方法名为xxx的方法。
4.输入校验流程
<1>类型转换器对请求参数执行类型转换,并把转换后的值赋给action中的属性。
<2>如果在执行类型转换的过程中出现异常,系统会将异常信息保存到 ActionContext,conversionError拦截器将异常信息封装到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.xml(action的名称是由url路径决定的)。
在处理请求方法上使用@SkipValiation注解,配置文件校验方式也将无效。
7.基于xml校验的一些特点
当为某个action提供了所有方法和指定方法校验两种规则时,系统会先寻找所有方法的校验文件,然后继续寻找指定方法的校验,当寻找完所有的相关校验文件后,会将所有的校验规则进行汇总,然后全部应用于action的校验。如果两个校验文件中指定的校验规则发生冲突,则只使用后面文件中的校验规则。
当action继承了另一个action,父类的action校验文件会先被搜索到。
十七.国际化
1.properties文件查询规则:如app_jp_ja.properties。
当前服务器只有en,zh和默认的支持。
先找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.访问对象及其属性
由于ValueStack是structs2中的OGNL的根对象,如果用户需要访问值栈中的对象,在jsp页面还可以通过EL表达式访问ValueStack中对象的属性:
${foo} //获得值栈中某个对象的foo属性。
因为structs2对HttpServletRequest做了进一步封装,所以我们能够直接使用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集合对象,其中的各个元素之间用逗号分隔,元素的key和value 之间采用冒号分隔。另外,还可以指定Map实例对象的类型。
<s:set value=“#{‘lhm’:96,’zxx’:93,’xpc’:97}”
<s:set value=“#@java.util.LinkedHashMap@{‘lhm’:96,’zxx’:93,’xpc’:97}”
scope:指定变量被放置的位置,该属性可以接受application、session、request、page 或action。如果没有设置该属性,则默认放置在OGNL Context中。
value;赋给变量的值,如果没有设置该属性,则将ValueStack栈顶的值赋给变量。
in和not 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.xml的action中使用token拦截器(注意引入系统默认的拦截器)。
使用<result name="invalid.token">/指定页面</result>,可以在重复提交后返回到指定页面。
二十一.访问静态资源
1.当项目加载structs2的jar包后,可以通过浏览器直接访问它的静态资源。其思想是通 过输入输出流读取文件。
如: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包的名称中不能有“-”等特殊字符,否则会报异常。

浙公网安备 33010602011771号