一、Struts2概述
1.概述
* struts1在2001年发布,是全世界第一个发布的mvc框架
* struts2并不是struts1的升级版,而是由WebWork基础上发展起来的,吸收了Struts1和WebWork两者的优势.
* mvc模式中,struts负责view和control层,而model层中的业务层则由Spring负责,model中的持久层由hibernate负责
这就是典型的ssh三大框架.
2 .struts2完整工作流程
* tomcat服务器启动加载web.xml文件
* web.xml文件中配置了struts2框架提供的过滤器.
* 当有请求时,会被过滤器拦截(拦截指定拦截的对象),解析路径然后在struts.xml文件中寻找指定namespace与指定action,如果没有action会执行默认的(如果配置的话)
* struts.xml文件需要程序员配置,放在classes目录下(即工程src下).
3.struts2开发环境快速搭建
(1)创建javaweb工程.
(2)找到开发Struts2应用需要使用到的jar文件(在struts2包中有小示例,里边有开发struts2应用需要的最少jar包)
* struts2-core-2.3.1.1.jar:struts2框架的核心类库.
* xwork-core-2.3.1.1.jar:command模式框架,webwork和struts2都基于xwork
* ognl-3.0.3.jar:对象图导航语言(Object Graph Navigation Language),struts2框架通过其读写对象的属性.
* freemarker-2.3.18.jar: struts2的UI标签的模版使用FreeMarker编写.
* commons-logging-1.1.x.jar:ASF出品的日志包,struts2框架使用这个日志包来支持Log4J和JDK1.4+的日志记录
* commons-fileupload-1.2.2.jar:文件上传组件,2.1.6版本后需要加入此文件.
* commons-lang-2.5.jar:对java.lang包的增强.
* asm-3.3.jar:提供了字节码的读写的功能,包含了核心的功能,而其他jar包都是基于这个核心的扩展.
* asm-commons-3.3.jar:提供了基于对象的表现形式.
* asm-tree-3.3.jar:提供了基于对象的表现形式.
* javassist-3.11.0.GA.jar:代码生成工具,struts2用它在运行时扩展java类.
* 例如struts2的struts-2.3.3-all.zip解压后,有一些文件和四个文件夹(apps,docs,lib,src).
apps文件夹:存放struts2提供的例子,方便呢我们学习.
docs文件夹:struts2的所有的文档.
lib文件夹:这里放着struts2所有的jar包.
src文件夹:struts2的源代码,他是开源的.
(3)创建jsp文件
* 假设有一请求连接:<a href="${pageContext.request.contextPath}/primer/HelloWorldAction.action">helloWorld</a>
(4)创建action文件
* 这里要自定义Action,可以实现Action接口覆盖其中的execute()方法,也可以直接继承ActionSupport类,一般情况下直接继承ActionSupport类,因为
ActionSupport类中实现了其他的方法,可以直接使用数据校验等Struts2集成的方法.
而Action接口中只定义了一个execute()方法,以及几个常用的结果名称(success,none,error,input,login).
实现action接口示例:
import coom.opensymphony.xwork2.Action;
public class HelloWorldAction implements Action {
public String execute() throws Exception {
System.out.println("helloWorld");
return "success";
}
}
(5)编写Struts2的配置文件
* struts2默认的配置文件是struts.xml,该文件需要放在WEB-INF/classes下,即当千工程的src下.
(6)在web.xml中加入Struts2 MVC框架启动配置
5.细节、配置
(1)拦截器和过滤器的区别
相同点:都起拦截作用
不同点: * 过滤器是java EE 中的规范,任何javaWeb程序都可以使用.
* 拦截器是Struts2框架独有的,离开了Struts2框架,拦截器将不能使用,拦截器是依赖于struts2框架的.
* 过滤器负责拦截请求路径,解析xml文件
* 其他拦截功能交给拦截器处理.
(2)Action名称的搜索顺序
获得请求路径的uri:http://server/struts2/path1/path2/path3/test.action
* 首先寻找namespace为/path1/path2/path3的package,存在则找action,不存在则下一步
* 则再找namespace为/path1/path2的package
* 再找namespace为/path1的package
* 上边都找不到,则找默认的namespace,默认的为"/".此时如果再找不到,页面会提示找不到action
(3)Action配置中的各项默认值
* 如果没有为action指定class,默认是com.opensymphony.xwork2.ActionSupport执行ActionSupport中的execute方法
* 如果没有为action指定method,默认执行action中的execute()方法.此方法中只有一句话:return "success";
* 如果没有指定result的那么属性,默认值为success.
* 如果请求的路径查不到action的情况下,程序运行会抛出异常,可以通过配置默认的action:<default-action-ref name="helloWorldAction"></default-action-ref>
(4)struts2处理的请求后缀
* StrutsPrepareAndExecuteFilter是struts2框架的核心控制器,它负责拦截<url-pattern>/*<url-pattern>
指定的所有用户请求,当用户请求到达时,该filter会过滤用户的请求.
默认情况下,只拦截请求路径不带后缀或者后缀以.action结尾的路径,否则struts2框架将略过该请求的处理.
此默认的后缀是根据配置文件struts2-core..这个核心包下的org.apache.struts2/default.properties文件
定义的常量决定的:struts.action.extension=action,,
* 后缀的自定义配置:两种方式
第一种:在struts.xml中配置(建议方式)
配置struts2只处理以.do或者.go结尾的后缀请求路径:在struts.xml中配置如下:
<struts>
<constant name="struts.action.extension" value="do,go"/>
</struts>
第二种:struts.properties中配置(创建此文件并放在src下,即classes下)
配置如下:struts.action.extension=do,go
* 常量加载顺序(注意是常量,不仅仅只是配置后缀的常量)
由于常量可以在多个配置文件中进行定义,因此需要了解struts2加载常量的搜索顺序.
①struts-default.xml
②struts-plugin.xml
③struts.xml(自己创建)
④struts.properties(自己创建)
⑤web.xml
如果在多个文件中配置了同一个常量,则后一个文件中配置的常量值会覆盖前面文件中配置的常量值.
(5)常用的常量介绍
* 指定默认编码集,作用于HttpServletRequest的setCharacterEncoding方法 和freemarker 、velocity的输出
<constant name="struts.i18n.encoding" value="utf-8"/>
* 配置请求后缀
<constant name="struts.action.extension" value="do"/>
* 设置浏览器是否缓存静态内容,默认值为true(生产环境下使用),开发阶段最好关闭
<constant name="struts.serve.static.browserCache" value="false"/>
* 配置当国际化文件修改时,重新加载该国际化资源文件,默认是false(不重新加载)
<constant name="struts.i18n.reload" value="true"/>
* 当struts的配置文件修改后,系统是否自动重新加载该文件,默认为false
<constant name="struts.configuration.xml.reload" value="true"/>
* 开发模式下使用,这样可以打印出更详细的错误信息,默认为false
<constant name="struts.devMode" value="true"/>
* 默认的视图主题
<constant name="struts.ui.theme" value="simple"/>
* 与spring集成时,指定由spring负责action对象的创建
<constant name="struts.objectFactory" value="spring"/>
* 设置struts2是否支持动态方法调用,默认为true.
<constant name="struts.enable.DynamicMethodInvocation" value="false"/>
* 上传文件的大小限制
<constant name="struts.multipart.maxSize" value="10701096"/>
(6)inclue指定多个struts配置文件
* 随着应用规模的增加,系统中Action的数量也会大量增加,导致struts.xml配置文件变的非常臃肿.
为了避免struts.xml文件过于庞大、臃肿,并提高可读性,可以将一个struts.xml配置文件分解成多个配置文件,
然后在struts.xml中用include包含其他配置文件.
示例:<struts>
<include file="struts-user.xml"/>
<include file="struts-order.xml"/>
</struts>
(7)struts2结果类型
* 每个action方法都将返回一个String类型的值,struts将根据这个值来决定响应什么结果.
每个action声明都必须包含有数量足够多的result元素,每个result元素分别对应着action方法的一个返回值.
* result元素可以有下面两个属性:
name:结果的名字,必须与action方法的返回值相匹配,默认值为success.
type:响应结果的类型,默认值为dispatcher
* 具体结果类型的声明在struts2-core...核心包下的struts-default.xml配置文件中的<result-types>节点下.
(8)结果类型:dispatcher(转发)
* 该结果类型有一个location参数,它是一个默认参数,写不写效果一样.
* dispatcher结果类型将把控制权转发给应用程序里的某个资源.
但它不能把控制权转发给一个外部资源,若需要把控制权重定向到一个外部资源,应该使用redirect结果类型.
* dispatcher的两种写法:
方法一:<result name="success" type="dispatcher">/result/success.jsp</result>
方法二:<result name="success" type="dispatcher">
<param name="location">/result/success.jsp</param>
</result>
(9)结果类型:redirect
* redirect结果类型接受下面这些参数:
location:用来给出重定向的目的地.
parse:用来表明是否把location参数的值视为一个OGNL表达式来解释,默认值是true.
* 同上,也有两种方式,二者等同
<result name="successredirect" type="redirect">/result/success.jsp</result>
<result name="successredirect" type="redirect">
<param name="location">/result/success.jsp</param>
</result>
(10)结果类型:redirectAction
* redirectAction结果类型把响应重定向到另一个Action
* redirectAction结果类型接受下面这些参数:
actionName:指定"目的地"动作的名字,他是默认属性.
namespace:用来指定"目的地"动作的命名空间,如果没有配置该参数,Struts会把当前Action所在的命名空间作为"目的地"的命名空间.
示例:<result name="redirectActionSuccess" type="redirectAction">
<param name="actionName">HelloWorldAction</param>
<param name="namespace">/primer</param>
</result>
(11)通配符
* 在action中增加新的方法:
自定义的方法须与execute方法的方法名不同,其他都一样,只有这样struts2才识别.
* 一个web应用可能有成千上百个action声明,可以利用struts提供的通配符映射机制把多个彼此相思的映射关系简化为一个映射关系.
* 通配符映射规则:
①若找到多个匹配,没有通配符的那个将胜出.
②若指定的动作不存在,struts将会尝试把这个uri与任何一个包含着通配符*的动作名进行匹配.
③若struts找到的带有通配符的匹配不止一个,最后一个匹配将胜出.
④被通配符匹配到的uri字符串的子串可以用{1},{2}来引用,{1}匹配第一个子串,{2}匹配第二个子串.而{0}匹配整个uri
⑤可以匹配零个或多个字符,但不包括/字符,如果想把/字符包括在内,需要使用**,如果需要对某个字符进行转义,需要使用\.
* 示例:
(12)动态方法调用
* 动态方法调用即通过rul动态调用Action中的方法.
如果Action中存在多个方法时,我们可以使用!+方法名调用指定方法.
* 默认情况下,Struts的动态方法调用处于激活状态,若想禁用该功能,则可以在struts.xml文件中添加如下constant元素:
<constant name="struts.enable.DynamicMethodInvocation" value="false"/>
* 动态方法调用示例:
jsp页面中 <a href="${pageContext.request.contextPath}/pattern/BookAction!add.action">图书添加</a>
则会调用相应Action中的add方法.
* 通配符也可以达到一样效果.
(13)全局结果与局部结果区别
全局结果:对该包下所有action配置起作用.
局部结果:只对当前的action起作用.
struts2中应用范围内action的实例,每个 请求都会创建一个action实例.
二、struts2应用
1.类型转换
(1) 从一个HTML表单到一个Action对象,类型转换是从字符串到非字符串.
(2) struts2中,把请求参数映射到action属性的工作由Parameters拦截器负责,它是默认的defaultStack拦截器中的一员.
Parameters拦截器可以自动完成字符串和基本数据类型之间转换.但它并不能转换所有的类型.例如Date类型.因此我们需要自定义类型转换器.
(3)配置自定义的类型转换器
要使用自定义的类型转换器之前,必须先配置,这种配置既可以基于字段(局部),也可以基于类(全局).
基于类(全局)的配置:在 WEB-INF/classes/ 目录下创建 xwork-conversion.properties 文件
内容为:待转换的类型=类型转换器的全类名
java.util.Date= com.liu.converter.DateConverter
基于字段配置(局部):可以为某个动作的各个属性分别制定一个自定义的转换器.
第一种:普通实体bean的类型转换器
* 创建一个属性文件:ActionClassName-conversion.properties.该文件须和相对应的动作类(Action)放在同一目录下.
ActionClassName是Action的类名,后面的-conversion.properties是固定写法.
* 文件内容:属性名称=自定义类型转换器的全类名
createTime=com.liu.converter.DateConverter
* 示例:Action动作类内容:
(4)类型转换-处理异常
* 首先转换器中要抛出异常.
* 在error.jsp中引入<%@ taglib uri="/struts-tags" prefix="s" %>
并使用<s:fielderror fieldName=""/>打印所有转化的异常错误信息(默认是英文信息)
例如:<s:fielderror fieldName="createTime"/>
name:指定Action属性的名称
* 由于在xwork-core..核心包下com\opensymphony\xwork2中的xwork-messages.properties文件定义的错误信息是英文的.
* 修改错误信息为中文:两步
第一步:在对应Action同级目录下新建xxxx.properties(名称自定义)
写入内容:xwork.default.invalid.fieldvalue=无效的字段值 "{0}"
内容可参考xwork-messages.properties,把英文翻译即可.
第二步:在struts.xml文件中加入常量,以加载该资源文件
<constant name="struts.custom.i18n.resources" value="com.liu.action.xxxx"></constant>
加载国际化资源文件,如果有多个文件,可用逗号隔开,资源文件后缀名不写.
此配置是针对多有字段给出提示.
* 针对特定字段给出提示
在xxxx.properties中增加如下内容:格式:invalid.fieldvalue.xx=提示信息
例如:invalid.fieldvalue.createTime=出生时间转化异常
2.文件上传
(1)jsp页面里使用file标签,如果上传多个文件,就必须使用多个file标签,但名字必须相同.
form中的enctype属性须设置为multipart/form-data,并把method设置为post
(2)Action中要添加3个和文件上传相关的属性:
//uploadImage是jsp页面中file标签的名字 <input type="file" name="uploadImage">
private File uploadImage;
private String uploadImageContentType;
private String uploadImageFileName;
//set和get方法省略
如果上传多个文件,可以使用数组或list
(3)单文件上传代码:
第一:jsp页面中代码
<form action="${pageContext.request.contextPath}/upload/uploadAction_saveFile.action" method="post" enctype="multipart/form-data" >
<input type="file" name="uploadImage">
<input type="submit" value="上传">
</form>
第二:Action类中代码
第一:jsp页面中代码
//需要引入<%@ taglib uri="/struts-tags" prefix="s" %>
<s:form action="/login/uploadAction.action" method="post" enctype="multipart/form-data">
<s:file name="uploadImage"></s:file>
<s:file name="uploadImage"></s:file>
<s:submit type="button" value="upload"></s:submit>
</s:form>
第二:Action中代码
(5)设置上传文件的总开关
在struts.xml文件加载该资源文件,默认值是2M
<constant name="struts.multipart.maxSize" value="86170804"/>
可以在struts2-core...核心包下的org\apache\struts2\default.properties中查看.
(6)File Upload拦截器
* FileUpload拦截器负责处理文件的上传操作,它是默认的defaultStack拦截器中的一员.
* FileUpload拦截器有3个属性可以设置
* maximumSize:上传文件的最大长度(以字节为单位)默认值为2MB
* allowedTypes:允许上传文件的类型,各类型之间以逗号分隔.
* allowedExtensions:允许上传文件扩展名,各扩展名之间以逗号分隔.
* 可以在struts.xml文件中覆盖这3个属性
<interceptor-ref name="defaultStack">
<param name="fileUpload.maximumSize">2048576</param>
<param name="fileUpload.allowedExtensions">.doc,.txt,.jpg</param>
<param name="fileUpload.allowedTypes">text/plain,application/vnd.ms-powerpoint</param>
</interceptor-ref>
* 如果用户上传的文件大小或内容类型等不符合设置的参数限定,则会显示出错消息,与文件上传有关的出错消息在
struts-messages.properties文件里预定义(org.apache.struts2包下)
* 显示错误信息,可以在<result name="input">/upload/error.jsp</result>中的error.jsp页面中
使用<s:fielderror/>显示错误信息.
* struts-messages.properties文件
struts.messages.error.uploading=Error uploading: {0}
struts.messages.error.file.too.large=File too large: {0} "{1}" "{2}" {3}
struts.messages.error.content.type.not.allowed=Content-Type not allowed: {0} "{1}" "{2}" {3}
struts.messages.error.file.extension.not.allowed=File extension not allowed: {0} "{1}" "{2}" {3}
{0}:<input type=“file” name=“uploadImage”>中name属性的值
{1}:上传文件的真实名称
{2}:上传文件保存到临时目录的名称
{3}:上传文件的类型(struts.messages.error.file.too.large是上传文件的大小)
(7)修改错误信息为中文
第一:在上传文件的动作类Action同目录下创建资源文件 fileuploadmessage.properties
内容如下:
struts.messages.error.uploading=上传错误: {0}
struts.messages.error.file.too.large=上传文件太大: {0} "{1}" "{2}" {3}
struts.messages.error.content.type.not.allowed=上传文件的类型不允许: {0} "{1}" "{2}" {3}
struts.messages.error.file.extension.not.allowed=上传文件的后缀名不允许: {0} "{1}" "{2}" {3
第二:在struts.xml文件中加载该资源文件
<constant name="struts.custom.i18n.resources" value="com.liu.upload.fileuploadmessage"/>
3.自定义拦截器
(1)概述
* Struts2拦截器在访问某个action方法之前或之后实施拦截,struts2拦截器是可插拔的,拦截器是AOP的一种实现.
* 拦截器栈(Interceptor Stack)将拦截器按一定的顺序联结成一条链,在访问被拦截的方法时,struts2拦截器链
中的拦截器就会按其之前定义的顺序被依次调用.
* 每个拦截器都是实现了com.opensymphony.xwork2.interceptor.Interceptor接口的java类.
有三个方法需要被实现:init、intercept、destroy.
(2)自定义拦截器
第一:实现com.opensymphony.xwork2.interceptor.Interceptor接口,实现三个方法
例如:
第二:在struts.xml文件中配置自定义拦截器
* 先在包中定义拦截器,然后定义拦截器栈,在自定义栈中引入默认栈,并把自定义拦截器放置到默认栈后面.
然后在要拦截的action中引入自己的拦截栈
示例: <package name="login" namespace="/login" extends="struts-default">
<interceptors>
<interceptor name="intercepter" class="com.liu.action.MyIntercepter"/>
<interceptor-stack name="MyStack">
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="intercepter"></interceptor-ref>
</interceptor-stack>
</interceptors>
<!--下面这句是覆盖底层的拦截器栈,对包中所有action都有效-->
<default-interceptor-ref name="MyStack"></default-interceptor-ref>
<action name="loginAction" class="com.liu.action.LoginAction" method="login">
<result>/login/success.jsp</result>
<result name="error">/login/error.jsp</result>
<!--在要拦截的action中引用-->
<interceptor-ref name="MyStack"></interceptor-ref>
</action>
</package>
4.手工验证(基本验证)
(1)在Action中
* 需要继承ActionSupport
* 重写Validateable接口中的validate()方法,在该方法中完成验证.
validate()方法会在其他业务方法之前执行,它会对action中的所有方法都进行校验
在方法中验证错误时,添加错误提示,this.addFieldError("sss","错误信息");
要校验指定的方法通过重写validateXxx()方法实现, validateXxx()只会校验action中
方法名为Xxx的方法。其中Xxx的第一个字母要大写。
Action示例:
(2)在struts.xml文件中
* 需要在对应的action中配置<result name="input">/validate/login.jsp</result>
这里一般再转向登录页面,即在登录页面提示:"用户名或密码错误"等这类提示.
(3)在input转向的jsp页面
* 在需要显示验证错误提示的jsp页面添加:<s:fielderror/>,此标签即可将错误提示信息输出到页面中.
5.基于xml配置进行验证(验证框架)
(1)Action要继承ActonSupport或者实现Validateable接口
(2)struts.xml中对应的action中要配置name为input的result
例如:<result name="input">/login/login.jsp</result>
(3) 在与Action动作类同一目录下创建ActionClassName-validation.xml,这样一个文件,ActionClassName是action的简单类名.
例如:LoginAction-validation.xml
首先要添加约束:其规范在xwork-core..核心包下的xwork-validator-1.0.3.dtd文件中.
然后进行配置:
<validators>:根元素
<field>:指定action中要校验的属性,name属性指定将被验证的表单字段的名字.
<field-validator>:指定校验器,type指定验证规则
(系统内建的验证规则可以在xwork-core..核心包下的com.opensymphony.xwork2.validator.validators下的default.xml中找到).
<param>:子元素可以向验证程序传递参数.
<message>:子元素为校验失败后的提示信息.
示例:
要求:动作类名为:com.liu.action.LoginAction
用户名不能为null,""
密码不能为null,""并且密码的长度6-12之间
则:定义LoginAction-validation.xml
内容:
(4)注意:
* 如果校验文件取名为ActionClassName-validation.xml这种格式时,会对action中的所有处理方法进行输入验证.
如果要对指定action方法实现输入校验,则文件名应为这种格式:ActionClassName-ActionName-validation.xml
ActionName为struts.xml中对应的action名称.
* jsp页面使用ognl标签时,会提示错误信息,当使用html标签时需要引入<s:fielderror/>
6.struts2标签自动回显
(1)方法一
//获取栈
ValueStack valueStack = ServletActionContext.getContext().getValueStack();
//删除栈顶的user对象
valueStack.pop();
//增加新的对象到栈顶newUser
valueStack.push(newUser);
7.令牌机制,处理表单重复提交
(1)jsp页面中增加一个隐藏域
<s:token></s:token>
(2)在struts.xml配置文件
在对应package包中增加
<!-- 在默认栈中增加token拦截器 -->
<interceptors>
<interceptor-stack name="tokenStack">
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="token">
<!-- 配置token拦截器拦截哪些方法 -->
<param name="includeMethods">save</param>
</interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- 配置struts2运行时执行的拦截器栈 -->
<default-interceptor-ref name="tokenStack"></default-interceptor-ref>
(3)在struts.xml中对应的action中增加
<!-- 当表单重复提交时,转向invalid.token所指向的页面 -->
<result name="invalid.token">/model/error.jsp</result>
以上配置加入了"invalid.token"结果,在会话的token与请求的token不一致时,将会直接返回"invalid.token"结果
(4)在error.jsp页面中加入<s:actionerror/>以打印错误信息.默认错误信息为英文
(5)修改error.jsp页面打印错误信息为中文
* 在与action同级目录下新建token.properties资源文件
* 在文件中增加如下内容:
struts.messages.invalid.token=您已经重复提交表单,请刷新后重试
该信息在struts2-core..核心包下的org.apache.struts2中的struts-messages.properties文件中找到.
* 在struts.xml文件中加载该资源文件
<constant name="struts.custom.i18n.resources" value="com.liu.model.token"></constant>
1.概述
* struts1在2001年发布,是全世界第一个发布的mvc框架
* struts2并不是struts1的升级版,而是由WebWork基础上发展起来的,吸收了Struts1和WebWork两者的优势.
* mvc模式中,struts负责view和control层,而model层中的业务层则由Spring负责,model中的持久层由hibernate负责
这就是典型的ssh三大框架.
2 .struts2完整工作流程
* tomcat服务器启动加载web.xml文件
* web.xml文件中配置了struts2框架提供的过滤器.
* 当有请求时,会被过滤器拦截(拦截指定拦截的对象),解析路径然后在struts.xml文件中寻找指定namespace与指定action,如果没有action会执行默认的(如果配置的话)
* struts.xml文件需要程序员配置,放在classes目录下(即工程src下).
3.struts2开发环境快速搭建
(1)创建javaweb工程.
(2)找到开发Struts2应用需要使用到的jar文件(在struts2包中有小示例,里边有开发struts2应用需要的最少jar包)
* struts2-core-2.3.1.1.jar:struts2框架的核心类库.
* xwork-core-2.3.1.1.jar:command模式框架,webwork和struts2都基于xwork
* ognl-3.0.3.jar:对象图导航语言(Object Graph Navigation Language),struts2框架通过其读写对象的属性.
* freemarker-2.3.18.jar: struts2的UI标签的模版使用FreeMarker编写.
* commons-logging-1.1.x.jar:ASF出品的日志包,struts2框架使用这个日志包来支持Log4J和JDK1.4+的日志记录
* commons-fileupload-1.2.2.jar:文件上传组件,2.1.6版本后需要加入此文件.
* commons-lang-2.5.jar:对java.lang包的增强.
* asm-3.3.jar:提供了字节码的读写的功能,包含了核心的功能,而其他jar包都是基于这个核心的扩展.
* asm-commons-3.3.jar:提供了基于对象的表现形式.
* asm-tree-3.3.jar:提供了基于对象的表现形式.
* javassist-3.11.0.GA.jar:代码生成工具,struts2用它在运行时扩展java类.
* 例如struts2的struts-2.3.3-all.zip解压后,有一些文件和四个文件夹(apps,docs,lib,src).
apps文件夹:存放struts2提供的例子,方便呢我们学习.
docs文件夹:struts2的所有的文档.
lib文件夹:这里放着struts2所有的jar包.
src文件夹:struts2的源代码,他是开源的.
(3)创建jsp文件
* 假设有一请求连接:<a href="${pageContext.request.contextPath}/primer/HelloWorldAction.action">helloWorld</a>
(4)创建action文件
* 这里要自定义Action,可以实现Action接口覆盖其中的execute()方法,也可以直接继承ActionSupport类,一般情况下直接继承ActionSupport类,因为
ActionSupport类中实现了其他的方法,可以直接使用数据校验等Struts2集成的方法.
而Action接口中只定义了一个execute()方法,以及几个常用的结果名称(success,none,error,input,login).
实现action接口示例:
import coom.opensymphony.xwork2.Action;
public class HelloWorldAction implements Action {
public String execute() throws Exception {
System.out.println("helloWorld");
return "success";
}
}
(5)编写Struts2的配置文件
* struts2默认的配置文件是struts.xml,该文件需要放在WEB-INF/classes下,即当千工程的src下.
配置模版:
<?xml version="1.0" encoding="UTF-8"?>
<!-- 下面的dtd约束可以在例子中找到,或在struts2-core这个核心包下找到 -->
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<package name="primer" namespace="/primer" extends="struts-default">
<action name="helloWorldAction" class="com.liu.primer.HelloWorldAction">
<result name="success">/success.jsp</result>
</action>
</package>
</struts>
(6)在web.xml中加入Struts2 MVC框架启动配置
<filter>
<filter-name>StrutsPrepareAndExecuteFilter</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>StrutsPrepareAndExecuteFilter</filter-name>
<url-pattern>*.action</url-pattern>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
4.struts2.xml详细解释
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<!-- include节点是struts2中组件化的方式 可以将每个功能模块独立到一个xml配置文件中 然后用include节点引用 -->
<include file="struts-default.xml"></include>
<!-- package提供了将多个Action组织为一个模块的方式
package的名字必须是唯一的 ,package可以扩展 ,当一个package扩展自 另一个package时该package会在本身配置的基础上加入扩展的package
配置 父package必须在子package前配置
name:package名称
extends:继承的父package名称
abstract:设置package的属性为抽象的 抽象的package不能定义action 值true:false
namespace:定义package命名空间 该命名空间影响到url的地址,命名空间为/primer,工程名为Struts2Demo,
那么访问是的地址为http://localhost:8080/Struts2Demo/primer/xxx.action
-->
<package name="com.liu.struts2" extends="struts-default" namespace="/primer">
<interceptors>
<!-- 定义拦截器
name:拦截器名称
class:拦截器类路径
-->
<interceptor name="timer" class="com.liu.timer"></interceptor>
<interceptor name="logger" class="com.liu.logger"></interceptor>
<!-- 定义拦截器栈 -->
<interceptor-stack name="mystack">
<interceptor-ref name="timer"></interceptor-ref>
<interceptor-ref name="logger"></interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- 定义默认的拦截器 每个Action都会自动引用
如果Action中引用了其它的拦截器 默认的拦截器将无效 -->
<default-interceptor-ref name="mystack"></default-interceptor-ref>
<!-- 全局results配置 -->
<global-results>
<result name="input">/error.jsp</result>
</global-results>
<!-- Action配置 一个Action可以被多次映射(只要action配置中的name不同)
name:action名称
class: 对应的类的路径
method: 调用Action中的方法名
-->
<action name="hello" class="com.liu.struts2.Action.LoginAction">
<!-- 引用拦截器
name:拦截器名称或拦截器栈名称
-->
<interceptor-ref name="timer"></interceptor-ref>
<!-- 节点配置
name : result名称 和Action中返回的值相同
type : result类型 不写则选用superpackage的type struts-default.xml中的默认为dispatcher
-->
<result name="success" type="dispatcher">/talk.jsp</result>
<!-- 参数设置
name:对应Action中的get/set方法
-->
<param name="url">http://www.sina.com</param>
</action>
</package>
</struts>
5.细节、配置
(1)拦截器和过滤器的区别
相同点:都起拦截作用
不同点: * 过滤器是java EE 中的规范,任何javaWeb程序都可以使用.
* 拦截器是Struts2框架独有的,离开了Struts2框架,拦截器将不能使用,拦截器是依赖于struts2框架的.
* 过滤器负责拦截请求路径,解析xml文件
* 其他拦截功能交给拦截器处理.
(2)Action名称的搜索顺序
获得请求路径的uri:http://server/struts2/path1/path2/path3/test.action
* 首先寻找namespace为/path1/path2/path3的package,存在则找action,不存在则下一步
* 则再找namespace为/path1/path2的package
* 再找namespace为/path1的package
* 上边都找不到,则找默认的namespace,默认的为"/".此时如果再找不到,页面会提示找不到action
(3)Action配置中的各项默认值
* 如果没有为action指定class,默认是com.opensymphony.xwork2.ActionSupport执行ActionSupport中的execute方法
* 如果没有为action指定method,默认执行action中的execute()方法.此方法中只有一句话:return "success";
* 如果没有指定result的那么属性,默认值为success.
* 如果请求的路径查不到action的情况下,程序运行会抛出异常,可以通过配置默认的action:<default-action-ref name="helloWorldAction"></default-action-ref>
(4)struts2处理的请求后缀
* StrutsPrepareAndExecuteFilter是struts2框架的核心控制器,它负责拦截<url-pattern>/*<url-pattern>
指定的所有用户请求,当用户请求到达时,该filter会过滤用户的请求.
默认情况下,只拦截请求路径不带后缀或者后缀以.action结尾的路径,否则struts2框架将略过该请求的处理.
此默认的后缀是根据配置文件struts2-core..这个核心包下的org.apache.struts2/default.properties文件
定义的常量决定的:struts.action.extension=action,,
* 后缀的自定义配置:两种方式
第一种:在struts.xml中配置(建议方式)
配置struts2只处理以.do或者.go结尾的后缀请求路径:在struts.xml中配置如下:
<struts>
<constant name="struts.action.extension" value="do,go"/>
</struts>
第二种:struts.properties中配置(创建此文件并放在src下,即classes下)
配置如下:struts.action.extension=do,go
* 常量加载顺序(注意是常量,不仅仅只是配置后缀的常量)
由于常量可以在多个配置文件中进行定义,因此需要了解struts2加载常量的搜索顺序.
①struts-default.xml
②struts-plugin.xml
③struts.xml(自己创建)
④struts.properties(自己创建)
⑤web.xml
如果在多个文件中配置了同一个常量,则后一个文件中配置的常量值会覆盖前面文件中配置的常量值.
(5)常用的常量介绍
* 指定默认编码集,作用于HttpServletRequest的setCharacterEncoding方法 和freemarker 、velocity的输出
<constant name="struts.i18n.encoding" value="utf-8"/>
* 配置请求后缀
<constant name="struts.action.extension" value="do"/>
* 设置浏览器是否缓存静态内容,默认值为true(生产环境下使用),开发阶段最好关闭
<constant name="struts.serve.static.browserCache" value="false"/>
* 配置当国际化文件修改时,重新加载该国际化资源文件,默认是false(不重新加载)
<constant name="struts.i18n.reload" value="true"/>
* 当struts的配置文件修改后,系统是否自动重新加载该文件,默认为false
<constant name="struts.configuration.xml.reload" value="true"/>
* 开发模式下使用,这样可以打印出更详细的错误信息,默认为false
<constant name="struts.devMode" value="true"/>
* 默认的视图主题
<constant name="struts.ui.theme" value="simple"/>
* 与spring集成时,指定由spring负责action对象的创建
<constant name="struts.objectFactory" value="spring"/>
* 设置struts2是否支持动态方法调用,默认为true.
<constant name="struts.enable.DynamicMethodInvocation" value="false"/>
* 上传文件的大小限制
<constant name="struts.multipart.maxSize" value="10701096"/>
(6)inclue指定多个struts配置文件
* 随着应用规模的增加,系统中Action的数量也会大量增加,导致struts.xml配置文件变的非常臃肿.
为了避免struts.xml文件过于庞大、臃肿,并提高可读性,可以将一个struts.xml配置文件分解成多个配置文件,
然后在struts.xml中用include包含其他配置文件.
示例:<struts>
<include file="struts-user.xml"/>
<include file="struts-order.xml"/>
</struts>
(7)struts2结果类型
* 每个action方法都将返回一个String类型的值,struts将根据这个值来决定响应什么结果.
每个action声明都必须包含有数量足够多的result元素,每个result元素分别对应着action方法的一个返回值.
* result元素可以有下面两个属性:
name:结果的名字,必须与action方法的返回值相匹配,默认值为success.
type:响应结果的类型,默认值为dispatcher
* 具体结果类型的声明在struts2-core...核心包下的struts-default.xml配置文件中的<result-types>节点下.
(8)结果类型:dispatcher(转发)
* 该结果类型有一个location参数,它是一个默认参数,写不写效果一样.
* dispatcher结果类型将把控制权转发给应用程序里的某个资源.
但它不能把控制权转发给一个外部资源,若需要把控制权重定向到一个外部资源,应该使用redirect结果类型.
* dispatcher的两种写法:
方法一:<result name="success" type="dispatcher">/result/success.jsp</result>
方法二:<result name="success" type="dispatcher">
<param name="location">/result/success.jsp</param>
</result>
(9)结果类型:redirect
* redirect结果类型接受下面这些参数:
location:用来给出重定向的目的地.
parse:用来表明是否把location参数的值视为一个OGNL表达式来解释,默认值是true.
* 同上,也有两种方式,二者等同
<result name="successredirect" type="redirect">/result/success.jsp</result>
<result name="successredirect" type="redirect">
<param name="location">/result/success.jsp</param>
</result>
(10)结果类型:redirectAction
* redirectAction结果类型把响应重定向到另一个Action
* redirectAction结果类型接受下面这些参数:
actionName:指定"目的地"动作的名字,他是默认属性.
namespace:用来指定"目的地"动作的命名空间,如果没有配置该参数,Struts会把当前Action所在的命名空间作为"目的地"的命名空间.
示例:<result name="redirectActionSuccess" type="redirectAction">
<param name="actionName">HelloWorldAction</param>
<param name="namespace">/primer</param>
</result>
(11)通配符
* 在action中增加新的方法:
自定义的方法须与execute方法的方法名不同,其他都一样,只有这样struts2才识别.
* 一个web应用可能有成千上百个action声明,可以利用struts提供的通配符映射机制把多个彼此相思的映射关系简化为一个映射关系.
* 通配符映射规则:
①若找到多个匹配,没有通配符的那个将胜出.
②若指定的动作不存在,struts将会尝试把这个uri与任何一个包含着通配符*的动作名进行匹配.
③若struts找到的带有通配符的匹配不止一个,最后一个匹配将胜出.
④被通配符匹配到的uri字符串的子串可以用{1},{2}来引用,{1}匹配第一个子串,{2}匹配第二个子串.而{0}匹配整个uri
⑤可以匹配零个或多个字符,但不包括/字符,如果想把/字符包括在内,需要使用**,如果需要对某个字符进行转义,需要使用\.
* 示例:
<!--原始写法-->
<package name="pattern" namespace="/pattern" extends="struts-default">
<action name="BookAction_add" class="com.liu.pattern.BookAction" method=="add">
<result name="add">/pattern/BookAction.jsp</result>
</action>
<action name="BookAction_delete" class="com.liu.pattern.BookAction" method=="delete">
<result name="delete">/pattern/BookAction.jsp</result>
</action>
<action name="UserAction_add" class="com.liu.pattern.UserAction" method=="add">
<result name="add">/pattern/UserAction.jsp</result>
</action>
<action name="UserAction_delete" class="com.liu.pattern.UserAction" method=="delete">
<result name="delete">/pattern/UserAction.jsp</result>
</action>
</package>
<!--改为通配符写法-->
<package name="pattern" namespace="/pattern" extends="struts-default">
<action name="*_*" class="com.liu.pattern.{1}" method="{2}">
<result name="add">/pattern/{1}.jsp</result>
<result name="delete">/pattern/{1}.jsp</result>
</action>
</package>
(12)动态方法调用
* 动态方法调用即通过rul动态调用Action中的方法.
如果Action中存在多个方法时,我们可以使用!+方法名调用指定方法.
* 默认情况下,Struts的动态方法调用处于激活状态,若想禁用该功能,则可以在struts.xml文件中添加如下constant元素:
<constant name="struts.enable.DynamicMethodInvocation" value="false"/>
* 动态方法调用示例:
jsp页面中 <a href="${pageContext.request.contextPath}/pattern/BookAction!add.action">图书添加</a>
则会调用相应Action中的add方法.
* 通配符也可以达到一样效果.
(13)全局结果与局部结果区别
全局结果:对该包下所有action配置起作用.
局部结果:只对当前的action起作用.
struts2中应用范围内action的实例,每个 请求都会创建一个action实例.
二、struts2应用
1.类型转换
(1) 从一个HTML表单到一个Action对象,类型转换是从字符串到非字符串.
(2) struts2中,把请求参数映射到action属性的工作由Parameters拦截器负责,它是默认的defaultStack拦截器中的一员.
Parameters拦截器可以自动完成字符串和基本数据类型之间转换.但它并不能转换所有的类型.例如Date类型.因此我们需要自定义类型转换器.
(3)配置自定义的类型转换器
要使用自定义的类型转换器之前,必须先配置,这种配置既可以基于字段(局部),也可以基于类(全局).
基于类(全局)的配置:在 WEB-INF/classes/ 目录下创建 xwork-conversion.properties 文件
内容为:待转换的类型=类型转换器的全类名
java.util.Date= com.liu.converter.DateConverter
基于字段配置(局部):可以为某个动作的各个属性分别制定一个自定义的转换器.
第一种:普通实体bean的类型转换器
* 创建一个属性文件:ActionClassName-conversion.properties.该文件须和相对应的动作类(Action)放在同一目录下.
ActionClassName是Action的类名,后面的-conversion.properties是固定写法.
* 文件内容:属性名称=自定义类型转换器的全类名
createTime=com.liu.converter.DateConverter
* 示例:Action动作类内容:
public class LoginAction extends ActionSupport{
private String username;
private String psw;
private Date createTime;
public String login() {
System.out.println("loginAction --> login()");
System.err.println(username+" : "+psw+" : " + createTime);
return "success";
}
//....省略所有get,set方法
}
//类型转换器:
public class DateConvert extends DefaultTypeConverter {
@Override
public Object convertValue(Map<String, Object> context, Object value,
Class toType) {
if (value == null) {
return null;
}
if (toType == null) {
return null;
}
if (toType != java.util.Date.class) {
return null;
}
if (value instanceof java.lang.String[]) {
String str[] = (String[]) value;
SimpleDateFormat sf = new SimpleDateFormat("yyyymmdd");
try {
if (str[0] != null && str[0].length() > 0) {
return sf.parse(str[0].trim());
}
} catch (ParseException e) {
throw new Exception(e);//这里需要抛出,以显示错误信息
}
}
return super.convertValue(context, value, toType);
}
}
//LoginAction同目录下,配置文件LoginAction-conversion.properties内容:
// createTime=com.liu.action.DateConvert
// 第二种:基于模型驱动的自定义类型转换
* Properties配置文件名:javaBean名-conversion.properties
* Properties配置文件内容:createTime=com.liu.action.DateConvert
* 示例:
javaBean:User内容
public class User {
private String username;
private String psw;
private Date createTime;
//....省略get与set方法
}
//Action内容
public class LoginAction extends ActionSupport implements ModelDriven<User>{
User user = new User();
public String login() {
System.out.println("loginAction --> login()");
System.err.println(user.getUsername()+" : "+user.getPsw());
return "success";
}
public User getModel() {
return user;
}
}
//类型转换器内容与上一个一样
//与javaBean,User同一目录下须有配置文件:User-conversion.properties,其内容:
// createTime=com.liu.action.DateConvert
(4)类型转换-处理异常
* 首先转换器中要抛出异常.
* 在error.jsp中引入<%@ taglib uri="/struts-tags" prefix="s" %>
并使用<s:fielderror fieldName=""/>打印所有转化的异常错误信息(默认是英文信息)
例如:<s:fielderror fieldName="createTime"/>
name:指定Action属性的名称
* 由于在xwork-core..核心包下com\opensymphony\xwork2中的xwork-messages.properties文件定义的错误信息是英文的.
* 修改错误信息为中文:两步
第一步:在对应Action同级目录下新建xxxx.properties(名称自定义)
写入内容:xwork.default.invalid.fieldvalue=无效的字段值 "{0}"
内容可参考xwork-messages.properties,把英文翻译即可.
第二步:在struts.xml文件中加入常量,以加载该资源文件
<constant name="struts.custom.i18n.resources" value="com.liu.action.xxxx"></constant>
加载国际化资源文件,如果有多个文件,可用逗号隔开,资源文件后缀名不写.
此配置是针对多有字段给出提示.
* 针对特定字段给出提示
在xxxx.properties中增加如下内容:格式:invalid.fieldvalue.xx=提示信息
例如:invalid.fieldvalue.createTime=出生时间转化异常
2.文件上传
(1)jsp页面里使用file标签,如果上传多个文件,就必须使用多个file标签,但名字必须相同.
form中的enctype属性须设置为multipart/form-data,并把method设置为post
(2)Action中要添加3个和文件上传相关的属性:
//uploadImage是jsp页面中file标签的名字 <input type="file" name="uploadImage">
private File uploadImage;
private String uploadImageContentType;
private String uploadImageFileName;
//set和get方法省略
如果上传多个文件,可以使用数组或list
(3)单文件上传代码:
第一:jsp页面中代码
<form action="${pageContext.request.contextPath}/upload/uploadAction_saveFile.action" method="post" enctype="multipart/form-data" >
<input type="file" name="uploadImage">
<input type="submit" value="上传">
</form>
第二:Action类中代码
public class UploadAction extends ActionSupport {
private File uploadImage;
private String uploadImageContentType; //uploadImage对应jsp页面中file标签的名字
private String uploadImageFileName;
//..get set方法省略
public String upload() {
ServletContext sc = ServletActionContext.getServletContext();
String path = sc.getRealPath("/uploadfile");
File destFile = new File(path,uploadImageFileName);
try {
FileUtils.copyFile(uploadImage, destFile);
} catch (IOException e) {
e.printStackTrace();
}
return "success";
}
}
(4)多文件上传代码:
第一:jsp页面中代码
//需要引入<%@ taglib uri="/struts-tags" prefix="s" %>
<s:form action="/login/uploadAction.action" method="post" enctype="multipart/form-data">
<s:file name="uploadImage"></s:file>
<s:file name="uploadImage"></s:file>
<s:submit type="button" value="upload"></s:submit>
</s:form>
第二:Action中代码
public class UploadAction extends ActionSupport {
private File[] uploadImage;
private String[] uploadImageContentType;
private String[] uploadImageFileName;
//...省略了get,set方法
public String upload() {
ServletContext sc = ServletActionContext.getServletContext();
String path = sc.getRealPath("/uploadfile");
if(uploadImage!=null&&uploadImage.length>0) {
for(int i = 0; i<uploadImage.length;i++){
File destFile = new File(path,uploadImageFileName[i]);
try {
FileUtils.copyFile(uploadImage[i], destFile);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
return "success";
}
}
(5)设置上传文件的总开关
在struts.xml文件加载该资源文件,默认值是2M
<constant name="struts.multipart.maxSize" value="86170804"/>
可以在struts2-core...核心包下的org\apache\struts2\default.properties中查看.
(6)File Upload拦截器
* FileUpload拦截器负责处理文件的上传操作,它是默认的defaultStack拦截器中的一员.
* FileUpload拦截器有3个属性可以设置
* maximumSize:上传文件的最大长度(以字节为单位)默认值为2MB
* allowedTypes:允许上传文件的类型,各类型之间以逗号分隔.
* allowedExtensions:允许上传文件扩展名,各扩展名之间以逗号分隔.
* 可以在struts.xml文件中覆盖这3个属性
<interceptor-ref name="defaultStack">
<param name="fileUpload.maximumSize">2048576</param>
<param name="fileUpload.allowedExtensions">.doc,.txt,.jpg</param>
<param name="fileUpload.allowedTypes">text/plain,application/vnd.ms-powerpoint</param>
</interceptor-ref>
* 如果用户上传的文件大小或内容类型等不符合设置的参数限定,则会显示出错消息,与文件上传有关的出错消息在
struts-messages.properties文件里预定义(org.apache.struts2包下)
* 显示错误信息,可以在<result name="input">/upload/error.jsp</result>中的error.jsp页面中
使用<s:fielderror/>显示错误信息.
* struts-messages.properties文件
struts.messages.error.uploading=Error uploading: {0}
struts.messages.error.file.too.large=File too large: {0} "{1}" "{2}" {3}
struts.messages.error.content.type.not.allowed=Content-Type not allowed: {0} "{1}" "{2}" {3}
struts.messages.error.file.extension.not.allowed=File extension not allowed: {0} "{1}" "{2}" {3}
{0}:<input type=“file” name=“uploadImage”>中name属性的值
{1}:上传文件的真实名称
{2}:上传文件保存到临时目录的名称
{3}:上传文件的类型(struts.messages.error.file.too.large是上传文件的大小)
(7)修改错误信息为中文
第一:在上传文件的动作类Action同目录下创建资源文件 fileuploadmessage.properties
内容如下:
struts.messages.error.uploading=上传错误: {0}
struts.messages.error.file.too.large=上传文件太大: {0} "{1}" "{2}" {3}
struts.messages.error.content.type.not.allowed=上传文件的类型不允许: {0} "{1}" "{2}" {3}
struts.messages.error.file.extension.not.allowed=上传文件的后缀名不允许: {0} "{1}" "{2}" {3
第二:在struts.xml文件中加载该资源文件
<constant name="struts.custom.i18n.resources" value="com.liu.upload.fileuploadmessage"/>
3.自定义拦截器
(1)概述
* Struts2拦截器在访问某个action方法之前或之后实施拦截,struts2拦截器是可插拔的,拦截器是AOP的一种实现.
* 拦截器栈(Interceptor Stack)将拦截器按一定的顺序联结成一条链,在访问被拦截的方法时,struts2拦截器链
中的拦截器就会按其之前定义的顺序被依次调用.
* 每个拦截器都是实现了com.opensymphony.xwork2.interceptor.Interceptor接口的java类.
有三个方法需要被实现:init、intercept、destroy.
(2)自定义拦截器
第一:实现com.opensymphony.xwork2.interceptor.Interceptor接口,实现三个方法
例如:
public class MyIntercepter implements Interceptor{
public void init() {
}
public String intercept(ActionInvocation invocation) throws Exception {
System.out.println("myintercept -- > intercept()");
System.out.println("invocation.getAction()"+invocation.getAction());
System.out.println("invocation.getProxy().getAction"+invocation.getProxy().getAction());
System.out.println("invocation.getProxy().getActionName"+invocation.getProxy().getActionName());
System.out.println("invocation.getProxy().getnamespace"+invocation.getProxy().getNamespace());
System.out.println("invocation.getProxy().getMethod"+invocation.getProxy().getMethod());
Map sessionMap = invocation.getInvocationContext().getSession();
Object obj = sessionMap.get("user");
if(obj==null)
return "error";
else{
Object returnvalue = invocation.invoke();
System.out.println("returnvalue"+returnvalue);
return returnvalue.toString();
}
}
public void destroy() {
}
}
第二:在struts.xml文件中配置自定义拦截器
* 先在包中定义拦截器,然后定义拦截器栈,在自定义栈中引入默认栈,并把自定义拦截器放置到默认栈后面.
然后在要拦截的action中引入自己的拦截栈
示例: <package name="login" namespace="/login" extends="struts-default">
<interceptors>
<interceptor name="intercepter" class="com.liu.action.MyIntercepter"/>
<interceptor-stack name="MyStack">
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="intercepter"></interceptor-ref>
</interceptor-stack>
</interceptors>
<!--下面这句是覆盖底层的拦截器栈,对包中所有action都有效-->
<default-interceptor-ref name="MyStack"></default-interceptor-ref>
<action name="loginAction" class="com.liu.action.LoginAction" method="login">
<result>/login/success.jsp</result>
<result name="error">/login/error.jsp</result>
<!--在要拦截的action中引用-->
<interceptor-ref name="MyStack"></interceptor-ref>
</action>
</package>
4.手工验证(基本验证)
(1)在Action中
* 需要继承ActionSupport
* 重写Validateable接口中的validate()方法,在该方法中完成验证.
validate()方法会在其他业务方法之前执行,它会对action中的所有方法都进行校验
在方法中验证错误时,添加错误提示,this.addFieldError("sss","错误信息");
要校验指定的方法通过重写validateXxx()方法实现, validateXxx()只会校验action中
方法名为Xxx的方法。其中Xxx的第一个字母要大写。
Action示例:
public class ValidateAction extends ActionSupport {
private String username;
private String psw;
//1 接收表单参数的方法
public void setUsername(String username) {
System.out.println("setUsername方法 "+username);
this.username = username;
}
//2 验证方法
public void validate(){ //假如还有别的方法,例如add(),而我们只想校验login()方法,可以把方法名改为:validateLogin()即可.
//对用户名和密码的检测,,,
//当判断用户名或密码有误时,用this.addFieldError("sss","错误信息")来添加错误提示信息.
}
//3 业务方法
public String login(){
System.out.println("login方法***********************"+username);
return "success";
}
(2)在struts.xml文件中
* 需要在对应的action中配置<result name="input">/validate/login.jsp</result>
这里一般再转向登录页面,即在登录页面提示:"用户名或密码错误"等这类提示.
(3)在input转向的jsp页面
* 在需要显示验证错误提示的jsp页面添加:<s:fielderror/>,此标签即可将错误提示信息输出到页面中.
5.基于xml配置进行验证(验证框架)
(1)Action要继承ActonSupport或者实现Validateable接口
(2)struts.xml中对应的action中要配置name为input的result
例如:<result name="input">/login/login.jsp</result>
(3) 在与Action动作类同一目录下创建ActionClassName-validation.xml,这样一个文件,ActionClassName是action的简单类名.
例如:LoginAction-validation.xml
首先要添加约束:其规范在xwork-core..核心包下的xwork-validator-1.0.3.dtd文件中.
然后进行配置:
<validators>:根元素
<field>:指定action中要校验的属性,name属性指定将被验证的表单字段的名字.
<field-validator>:指定校验器,type指定验证规则
(系统内建的验证规则可以在xwork-core..核心包下的com.opensymphony.xwork2.validator.validators下的default.xml中找到).
<param>:子元素可以向验证程序传递参数.
<message>:子元素为校验失败后的提示信息.
示例:
要求:动作类名为:com.liu.action.LoginAction
用户名不能为null,""
密码不能为null,""并且密码的长度6-12之间
则:定义LoginAction-validation.xml
内容:
<?xml version="1.0" encoding="UTF-8"?>
<!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">
<param name="trim">true</param>
<message><![CDATA[(xml)用户名不能为空]]></message>
</field-validator>
</field>
<field name="psw">
<field-validator type="requiredstring">
<param name="trum">true</param>
<message><![CDATA[(xml)密码不能为空]]></message>
</field-validator>
<field-validator type="regex">
<param name="expression"><![CDATA[^[a-zA-Z0-9]{6,12}$]]></param>
<message><![CDATA[密码长度应在6-12之间]]></message>
</field-validator>
</field>
</validators>
(4)注意:
* 如果校验文件取名为ActionClassName-validation.xml这种格式时,会对action中的所有处理方法进行输入验证.
如果要对指定action方法实现输入校验,则文件名应为这种格式:ActionClassName-ActionName-validation.xml
ActionName为struts.xml中对应的action名称.
* jsp页面使用ognl标签时,会提示错误信息,当使用html标签时需要引入<s:fielderror/>
6.struts2标签自动回显
(1)方法一
//获取栈
ValueStack valueStack = ServletActionContext.getContext().getValueStack();
//删除栈顶的user对象
valueStack.pop();
//增加新的对象到栈顶newUser
valueStack.push(newUser);
7.令牌机制,处理表单重复提交
(1)jsp页面中增加一个隐藏域
<s:token></s:token>
(2)在struts.xml配置文件
在对应package包中增加
<!-- 在默认栈中增加token拦截器 -->
<interceptors>
<interceptor-stack name="tokenStack">
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="token">
<!-- 配置token拦截器拦截哪些方法 -->
<param name="includeMethods">save</param>
</interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- 配置struts2运行时执行的拦截器栈 -->
<default-interceptor-ref name="tokenStack"></default-interceptor-ref>
(3)在struts.xml中对应的action中增加
<!-- 当表单重复提交时,转向invalid.token所指向的页面 -->
<result name="invalid.token">/model/error.jsp</result>
以上配置加入了"invalid.token"结果,在会话的token与请求的token不一致时,将会直接返回"invalid.token"结果
(4)在error.jsp页面中加入<s:actionerror/>以打印错误信息.默认错误信息为英文
(5)修改error.jsp页面打印错误信息为中文
* 在与action同级目录下新建token.properties资源文件
* 在文件中增加如下内容:
struts.messages.invalid.token=您已经重复提交表单,请刷新后重试
该信息在struts2-core..核心包下的org.apache.struts2中的struts-messages.properties文件中找到.
* 在struts.xml文件中加载该资源文件
<constant name="struts.custom.i18n.resources" value="com.liu.model.token"></constant>