天天看点

Struts2知识整理

struts2是基于mvc开发模型的框架,属于表现层框架

核心为拦截器

基于MVC,结构清晰

丰富的标签库,提高了开发效率

强大的拦截器

全局异常和全局结果处理

易于扩展的插件化机制

Struts2也有IOC和DI的特性

整体执行图

Struts2知识整理

下面是一次请求Action的流程

创建actioncontext, 创建valuestack, 并且把整个ActionContext对象放入到threadlocal中,这样就能保证valueStack的数据的安全性

创建Actionproxy 创建Action

按照顺序执行所有的拦截器

执行Action

执行结果集

按照倒叙的方式执行符合规则的拦截器(return invoke)

清空数据

web.xml

struts2.xml

struts2可以包含多个配置文件(提高了配置文件的安全性和独立性),<code>&lt;include file=""&gt;</code>|

default.properties:struts2-core**.jar org.apache.struts包中

struts-default.xml:struts2-core**.jar中

struts-plugin.xml:在插件的jar包中

struts.xml:在应用的构建路径顶端。自己定义的Struts配置文件(推荐)

struts.properties:在应用的构建路径顶端。程序员可以编写

web.xml:配置过滤器时,指定参数。程序员可以编写

特别注意:顺序是固定的。后面的配置会覆盖前面的同名配置信息。

访问一次Action就会重新创建一个Action对象(多例)

action

name: 动作名称,用于用户请求

class: 映射类的全名,如果不指定默认值为:ActionSupport 默认类可以修改,默认类在struts-default.xml中进行了声明,可以在配置文件中用来指定自定义默认类

method: 指定映射方法, 默认值: execute

action内的通配符

通配符配置ACTION

存在多个匹配,匹配的执行顺序:绝对匹配-&gt;按照通配符匹配的顺序

地址:add_Customer

name="*_" {1}代表第一个所代表的的字符 {2}代表的第二个字符

使用方法:如果请求的是 Customer_add

class="com.item.action.{1}Action" method="{2}" // com.item.action.CustomerAction" method="add"

result /customer/{1}{2}.jsp // addCustomer.jsp

动态调用

http://loaclhost:8080/XXX/demo!m1(不安全,不建议使用)

使用前需要开启动态调用,在struts2.xml中配置:<code>struts.enable.DynamicMethod.Invocation=true</code>

package(类似于java类的包)

name:唯一

extends:struts-default 继承默认包,包内设置了默认的拦截器,如果不继承该包,那么Struts2中的核心功能将无法使用。

namespace: 指定命名空间,一般以"/"开头。该包中的动作访问路径:namesapce+动作名称。如果namespace="",这是默认名称空间,和不写该属性是一样的。

abstract:没有action子元素的包可以声明为抽象包.

编写动作类的三种方式:

单纯POJI

实现Action接口提供了几个格式化的返回参数

String SUCCESS:success。一切正常。

String NONE:none。动作方法执行后,不转向任何的结果视图。或者在动作方法中返回null。

String ERROR:error。动作方法执行时遇到异常,转向错误提示页面。

String INPUT:input。验证、转换失败,转向输入页面。

String LOGIN:login。检测用户是否登录,没有登录转向此视图。

实现 ActionSupport(推荐)这个类实现了Action接口,并且提供了一些基本的功能,比如:验证 国际化提示等

action访问ServletAPI

方式一:ServletActionContext静态方法(推荐)

ServletActionContext.getRequest(); //struts2 改变了request中的某些功能 ServletActionContext.getResponse(); //apache ServletActionContext.getServletContext(); //apache

方式二:实现接口 ServletRequestAware,ServletResponseAware ,ServletContextAware

执行动作方法前,框架会把HttpServletRequest()对象注入进来

是由一个拦截器负责注入的,servletConfig

type 到达目标形式 默认:转发,下面是几个重要的

chain: 转发到另一个动作

如果对应的action所在的包不在默认空间内,需要用到来设置空间和action名字

&lt;param name="Namespace"&gt;/n2&lt;/param&gt; &lt;param name="ActionName"&gt;math&lt;/param&gt;

dispatcher: 用户转发到页面(请求转发 jsp)

redirect: 请求重定向到jsp

redirectAction: 请求重定向到action

stream: 用于文件上传和下载

freemarker: 转发到另一个freemarker模板(页面静态化)

httpheader: 输出http协议的消息头

plainText:原样输出源代码

在struts2.xml中声明结果定义类型

首先编写类,实现com.opensymphony.xwork2.Result接口或者继承StrutsResultSupport(一般为继承),然后里面设置需要输出的内容(输出方式和Servlet内相同)输出验证码

表单的的name要与参数名字相同才可以赋值

动态参数赋值

模型类最好实现Serilalizable接口

参数赋值的顺序: 模型对象中找,如果没有对应对象的Set方法,下一步就会从对应的action中寻找.

1.用Action动作类对象作为模型对象,即Javabean内写上action函数jsp页面name和属性名字相同,然后直接访问就可以自动赋值

2.动作类和模型分开在动作类里面声明模型类,并且设置get,set方法,动作类对象名字为person, 则jsp页面的name要加上前缀,即:person.name才可赋值

3.动作类和模型分开(ModelDriven)

动作类继承ModelDeriven

原因:与Struts2的值栈有关

该功能是由一个叫做modelDriven的拦截器完成的。

静态参数注入<code>&lt;param name="name"&gt;游客&lt;/param&gt;</code>

动态参数和静态参数注入功能实现

是由两个拦截器来完成。

静态参数注入:staticParams

动态参数注入:params

批量添加表单

参数的类型转换

struts2内置了转换器,多数情况下不需要自己来编写

struts2的发展过程 OGNL-WebWork-struts2 , 所以一些在ONGL或者WebWork时期定义不明确的方法和参数struts2会有一定程度的改正.

自定义转换器:

编写转换器

继承<code>StrutsTypeConverter</code>,重写<code>convertFromString()</code> 和 <code>convertToString()</code> 这两个方法

转换器示例代码

配置转换器

局部转换器

前缀名字一定要和类名相同

对应模型类或者对应动作类下面创建 ClassName-conversion.properties文件, 内容: <code>birthday=com.item.MyDateConverter(转换器类)</code>

Struts2知识整理

全局转换器

位置在src下面,名字为<code>xwork-conversion.properties</code>,所有动作都可以用

<code>java.util.Date=com.itheima.convertors.MyDateConverter</code> 内容为需要转换的类型和对应的类

类型转换失败提示

转换失败,会自动转到一个name=input的逻辑视图(需要在result内定义),一般指向输入的那个页面,目的回显(建议使用struts2的表单标签)

错误消息提示中文版本(动作类要继承ActionSupport类)

<code>类名.properties</code> , 内容为<code>invalid.fieldvalue.birthday=输入错误</code>

Struts2知识整理

验证功能是由validation拦截器来负责处理的。回显错误信息是由workflow拦截器来负责处理的。

下面两种方式都需要在struts.xml配置文件中添加<code>&lt;result name="input"&gt;/regist.jsp&lt;/result&gt;</code>结果视图

编程式验证

针对动作类中所有的方法进行验证

动作类需要实现ActionSupport覆盖掉validate()方法

在validate方法内部编写规则,不正确的情况用addFieldError添加错误信息

动作类就是模型类: <code>addFieldError("name", "请输入用户名");</code>

动作类跟模型类分开: <code>addFieldError("m.name", "请输入用户名");</code>

针对指定方法进行验证

在需要验证的方法上面添加注解<code>@SkipValidation</code>

将validate()方法改写成为<code>public void validateDemo1</code> 后面是指定方法的名字.

声明式验证

在xml文件中配置验证信息,不需要硬编码

在动作类所在的包中建立:动作类名-validation.xml配置文件。

xml文件

在模型类和动作类的两种方式, 只需要改一下<code>&lt;field name="m.name"&gt;</code> 中的name要和表单名(jsp/name)一致

针对动作做类的方法进行验证在动作类所在的包中建立:动作类名-动作名(是请求的struts.xml配置文件中的)-validation.xml配置文件。 action配置文件中可以用method属性来指定执行那个方法

常用内置验证器

提供的声明式验证器在xwork-core-**.jar包的com\opensymphony\xwork2\validator\validators\default.xml配置文件中(查询具体类用CRTL+T)。

内置验证器示例

自定义声明式验证器

编写一个类,继承FieldValidatorSupport

定义验证器,之后就可以和使用内置验证器一样使用src目录下,新建validators.xml

编写自定义验证器

是struts2中的核心功能,是一种AOP变成思想的具体应用.

常用的拦截器

modelDriven:模型驱动

servletConfig:获取ServletAPI

staticParams:静态参数注入

params:动态参数注入

validation:输入验证,声明式验证。

结果应该是:

拦截前-动作类-jsp-拦截后

即先执行拦截器,然后在执行方法,执行方法返回的逻辑视图,最后再次执行拦截器

使用自定义拦截器

拦截器参数可以用set方法或者在xml中用param来设置, 如果在class中用Set来设置,需要覆盖父类的init()方法.

编写一个类,继承AbstractInterceptor(所有方法都会拦截)示例

配置拦截器在pageage里面用<code>&lt;interceptors&gt;&lt;interceptor name="" class=""/&gt;&lt;/interceptors&gt;</code>来声明拦截器

使用拦截器(如果只是在单纯的指定自定义拦截器,则默认拦截器不起作用)

在action里面使用<code>&lt;interceptor-ref name=""&gt;&lt;/interceptor-ref&gt;</code>来使用拦截器(使用了自定义拦截器,则默认拦截器失效)

代码

指定方法拦截

继承MethodFilterInterceptor方法代码

使用

通过<code>&lt;param name="excludeMethods"&gt;query&lt;/param&gt;</code>的形式传递不需要过滤的方法(includeMethods需要包含的方法),参数为需要拦截的方法.

拦截组合

定义组,覆盖默认拦截器, 将拦截器声明为全局的拦截器

简单的登录验证

所有方法

指定方法

xml

表单域前提: post, enctype="multipart/form-data"

struts2中,是fileupload拦截器完成的

单文件上传

Struts2知识整理

存储文件可以用<code>FileUtils.copyFile(file1, target);</code> 方法, file1: file文件域对象 target: 目标文件(创建的文件)

上传文件

多文件上传

参数和单文件相同,不过要改成数组或者List方式来存储

存储文件时需要遍历File数组

文件错误信息提示

修改上传文件默认错误信息

在src文件夹下创建<code>fileupload.properties</code> 文件

配置参数 <code>struts.messages.upload.error.SizeLimitExceededException</code> 和 <code>struts.messages.error.file.extension.not.allowed</code> 等,可以用{1}来设置系统返回值

示例

动作类中需要定义InputStream对象,(名称不能为in)和String Filename

<code>&lt;result type="Stream"&gt;</code> Xml配置文件结果视图类型为Stream

需要设置参数

inputStream 设置输出流,名字为Action中定义的名字

attachment;filename=${@java.net.URLEncoder@encode(fileName,'UTF-8')} ,设置响应头

导入标签 <code>&lt;%@ taglib uri="/struts-tags" prefix="s"%&gt;</code>

OGNL不仅仅可以在jsp中使用,在其他地方也可以(例如xml配置文件)

context上下文

ActionContext私有化会使得jsp页面获取不到Context/valuestack中的值

ActionContext和ValueStack声明周期都是一次http请求

传输的数据存储在context,数据中心

在jsp页面使用标签可以显示context中的信息

context是一个Map,每个域对象对应一个值, 这个值可以是Map也可以是其他的 即Map

Struts2知识整理

动作类的生命周期,每次访问都会创建新的动作类实例,ActionContext和ValueStack, 会一直保持在你的线程中,所以线程安全.

ActionContext API 常用API

ValueStack

ValueStack属于Context里面的一个属性,结构为栈

也可以通过ValueStack获得Context,ActionContext中的Context和ValueStack里面的相同

如果ValueStack中有多个名字相同的值<code>&lt;s:property value="[1].month"&gt;</code>

获取对象数据的不同:

获取Context中的数据需要用#开头

获取ValueStack中的数据直接写属性名字就可以,会从栈顶一直往下找.

基本方法

vs.set("b1", "vb1"); //检测栈顶是不是一个Map,如果不是,创建一个Map,Map中的数据就是p1=pp1,再把这个Map压入栈顶,如果有,则会把数据直接放入

vs.setValue("name", "三平");//设置ValueStack中存在属性的值,属性必须存在

vs.setValue("#name", "三平"); //向Context中设置key为name, value为三平的Map, key可以不存在

vs.findValue(name);//取valuestack中的值不用#,context中的用#,从根中依次寻找对象的属性,没有找到会去Context内找(寻找整个Context),加强EL表达式运用的方法.

对EL表达式的增强EL不仅仅会搜索以前的几个域中的对象,还会通过find.Value()方法去Context中搜索

特殊符号的运用

在ognl表达式内如果需要输出字符串,则字符串需要添加单引号

%{} 将字符串当成ognl表达式

${} 在国际化资源文件中引用OGNL表达式,在Struts2配置文件中引用ognl表达式(上次文件示例)数组和数列:${@java.net.URLEncoder@encode(fileName,'UTF-8')}

Struts2知识整理

压栈/弹栈

OGNL 创建List和Map

Struts2知识整理

内置标签需要导入标签<code>&lt;%@ taglib prefix="s" uri="/struts-tags" %&gt;</code>

<code>&lt;s:property value="'name'"/&gt;</code> //将value输出,使用ognl表达式都需要在struts2的标签内才可以

<code>&lt;s:set value="'value'" var="v1" scope="session"&gt;&lt;/s:set&gt;</code> 存放数据,如果没有指定scope, 默认放到contextMap和request中

<code>&lt;s:property value="'&lt;hr/&gt;'" escapeHtml="true"/&gt;&lt;br/&gt;</code> 是否转译

<code>&lt;s:push value="'value3'"&gt;&lt;/s:push&gt;</code> 将对象压入valuestack栈中,标签结束后弹栈,则操作必须在结束标签之前进行

<code>&lt;s:bean name="java.util.Date" var="now"&gt;&lt;/s:bean&gt;</code> 给一个对象去一个名字,并且放到contextMap中

<code>&lt;s:action name="HelloWorldAction" executeResult="true"/&gt;</code> action指向一个动作,将动作结果包含进来,类似于EL标签的include

<code>&lt;s:iterator value="#request" var="s"&gt;</code> forEach,将当前遍历的元素存储到contextMap中,key就是var指定的值 m=Map.Entry,如果没有指定var,会将当前元素放到valuestack中

<code>&lt;s:radio list="{'man','faman'}" name="username"&gt;&lt;/s:radio&gt;</code> 如果contextMap中有key和下面连个标签的name相同,则会自动遍历内容,选中对应的选项

<code>&lt;s:if test="#grade=='A'"&gt; &lt;/if&gt; &lt;s:elseif test="#grade=='B'"&gt;&lt;/s:elseif&gt;</code> if-else标签

<code>&lt;s:url action="demo2" var="u1"&gt; &lt;a href="${u1 }"&gt;点我&lt;/a&gt;</code> url标签和a标签传递参数是用<code>&lt;s:param name="username" value="'你也好'"&gt;</code> 来传递

<code>&lt;s:a action="demo1"&gt;&lt;/s:a&gt;</code>

具体代码

标签简单实现防止表单重复提交

在jsp页面使用

在xml里面配置 有两种方法 (token, tokenSession)

<code>&lt;interceptor-ref name="token"&gt;&lt;/interceptor-ref&gt;</code> //需要结果视图,如果重复提交会转向结果视图

<code>&lt;interceptor-ref name="tokenSession"&gt;&lt;/interceptor-ref&gt;</code> //不需要结果视图,点多次提交会等待

java

jsp

struts2加载配置文件的顺序:

struts-default.xml 核心的配置文件

struts-plugin.xml 插件的配置文件

struts.xml 程序员开发的时候需要写的配置文件

objectFactory类 : 生产struts2关键组件, 如拦截器,结果集,action, 可以通过继承这个类来改写方法

插件机制的原理

我们可以通过继承 objectFactory类来编写自己需要的方法,然后通过改变配置文件中的参数,将objectFactory改变为我们自己编写的类.

在工程的Lib下有很多个struts2-plugin-xx.jar包,在这个包下有一个struts-plugin.xml文件,在这个文件中可以配置很多内容,只需要吧这个jar包放到lib下面,当tomact启动的时候被加载了, 如果不需要,只需要把这些jar包移除掉就可以了 这就是插件机制

struts2底层用objectFactory.buildAction方法来创建action的,所以我们可以继承objectFactory类改写方法,而在配置文件中可以指定objectFactory是哪一个具体的类,所以我们只需要把jar包放进去和配置好Xml文件就可以了

如果需要在生成Action之前做一些操作,那我们就可以考虑选择重写objectfactory方法.

objectfactory说明

该对象称为对象工厂:生成对象的工厂,struts2的很关键的组件都可以是一个对象

在default.properties文件中有一个常量struts.objectFactory,该值就是对象工厂

objectfactory的示意图

Struts2知识整理