【Struts2】(2)Struts2校验框架、Struts2拦截器、Struts2转换器
2017-08-19 15:39
302 查看
一、Struts2校验框架
输入校验几乎是任何一个系统都需要开发的功能模块,我们无法预料用户如何输入,但是必须全面考虑用户输入的各种情况,尤其需要注意那些非正常输入。Struts2提供了功能强大的输入校验机制,通过Struts2内建的输入校验器,在应用程序中无需书写任何代码,即可完成大部分的校验功能,并可以同时完成客户端和服务器端的校验。如果应用的输入校验规则特别,Struts2也允许通过重写validate方法来完成自定义校验,另外Struts2的开放性还允许开发者提供自定义的校验器。
Struts2中可以通过重写validate方法来完成输入校验。如果我们重写了validate方法,则该方法会应用于此Action中的所有提供服务的业务方法。
1、Struts2的输入校验流程如下
(1)类型转换器负责对字符串的请求参数执行类型转换,并将这此值设置成Action的属性值。(2)在执行类型转换过程中可能出现异常,如果出现异常,将异常信息保存到ActionContext中,conversionError拦截器负责将其封装到fieldError里,然后执行第3步;如果转换过程没有异常信息,则直接进入第3步。
(3)通过反射调用validateXxx()方法,其中Xxx是即将处理用户请求的处理逻辑所对应的方法名。
(4)调用Action类里的validate()方法。
(5)如果经过上面4步都没有出现fieldError,将调用Action里处理用户请求的处理方法;如果出现了fieldError,系统将转入input逻辑视图所指定的视图资源。
2、校验示例
第1步:编写一个Action类,该Action接受页面提交过来的参数package com.action; import com.opensymphony.xwork2.ActionSupport; public class LoginValidateAction extends ActionSupport{ // Action类公用私有变量,用来做页面导航标志 private static String FORWARD = null; private String username; private String password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public void validate() { } public String execute() throws Exception { username = getUsername(); //属性值即JSP页面上输入的值 password = getPassword(); //属性值即JSP页面上输入的值 try { // 判断输入值是否是空对象或没有输入 if (username.equals("admin")&& password.equals("1234")) { // 根据标志内容导航到操作成功页面 FORWARD = "success"; } else { // 根据标志内容导航到操作失败页面 FORWARD = "input"; } } catch (Exception ex) { ex.printStackTrace(); } return FORWARD; } }
第2步:在该Action相同的目录下建一个xml文件,该文件的命名为ActionName-validation.xml,其中 ActionName为该Action的类名,例如LoginValidateAction-validation.xml。然后在xml配置文件中配置需要验证的字段。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.3//EN" "http://www.opensymphony.com/xwork/xwork-validator-1.0.3.dtd"> <validators> <field name="username"> <field-validator type="requiredstring"> <message key="用户名不能为空"/> </field-validator> </field> <field name="password"> <field-validator type="requiredstring"> <message key="密码不能为空"/> </field-validator> <field-validator type="stringlength"> <param name="minLength">6</param> <param name="maxLength">16</param> <message>密码长度应在6~16个字符之间</message> </field-validator> </field> </validators>
第3步:在struts.xml文件中配置Action,在Action配置中必须有input视图。
<!-- 通过Action类处理才导航的的Action定义 --> <action name="Login" class="com.action.LoginAction"> <result name="input">/login.jsp</result> <result name="success">/success.jsp</result> </action>
第4步:添加一个jsp页面 loginvalidate.jsp,放入一个struts标签
<%@ page language="java" pageEncoding="utf-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <!-- struts2标签库调用声明 --> <%@taglib prefix="s" uri="/struts-tags"%> <html> <head> <title>登录页面</title> </head> <body> <!-- form标签库定义,以及调用哪个Action声明 --> <s:form action="validate"> <table width="60%" height="76" border="0"> <!-- 各标签定义 --> <s:textfield name="username" label="用户名"/> <s:password name="password" label="密 码" /> <s:submit value="登录" align="center"/> </table> </s:form> </body> </html>
基础的Struts2输入校验规则:::
<validators> 对必填校验 <field name="requiredValidatorField"> <field-validator type="required"> <message>必填内容</message> </field-validator> </field> 必填字符串校验 <field name="requiredStringValidatorField"> <field-validator type="requiredstring"> <param name="trim">true</param> <message>字符串必填校验</message> </field-validator> </field> 对int类型的校验 <field name="integerValidatorField"> <field-validator type="int"> <param name="min">1</param> <param name="max">10</param> <message key="validate.integerValidatorField" /> </field-validator> </field> 对日期的校验 <field name="dateValidatorField"> <field-validator type="date"> <param name="min">01/01/1990</param> <param name="max">01/01/2000</param> <message key="validate.dateValidatorField" /> </field-validator> </field> 对email的校验 <field name="emailValidatorField"> <field-validator type="email"> <message key="validate.emailValidatorField" /> </field-validator> </field> 对URL的校验 <field name="urlValidatorField"> <field-validator type="url"> <message key="validate.urlValidatorField" /> </field-validator> </field> 对字符串长度的校验 <field name="stringLengthValidatorField"> <field-validator type="stringlength"> <param name="maxLength">4</param> <param name="minLength">2</param> <param name="trim">true</param> <message key="validate.stringLengthValidatorField" /> </field-validator> </field> 对正则表达式的校验 <field name="regexValidatorField"> <field-validator type="regex"> <param name="expression">.*\.txt</param> <message key="validate.regexValidatorField" /> </field-validator> </field> </validators>
Struts2中应用客户端输入校验:::
这里要用Struts2的标签,form的validate属性要设置为true,并且不要将theme属性指定为simple。(simple表示Struts2将把这个解析成普通的HTML标签)
二、Struts2拦截器
拦截器,在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。拦截是AOP的一种实现策略。Struts2拦截器是动态拦截Action调用的对象。它提供了一种机制,使开发者可以定义一个特定的功能模块,这个模块可以在Action执行之前或者之后运行,也可以在一个Action执行之前阻止Action执行。同时也提供了一种可以提取Action中可重用的部分的方式。
拦截器(Interceptor)是Struts 2的核心组成部分。很多功能都是构建在拦截器基础之上的,例如文件的上传和下载、国际化、转换器和数据校验等,Struts 2利用内建的拦截器,完成了框架内的大部分操作。
Struts2的拦截器和Servlet过滤器类似。在执行Action的execute方法之前,Struts2会首先执行在struts.xml中引用的拦截器,在执行完所有引用的拦截器的intercept方法后,会执行Action的execute方法。
Struts2拦截器类必须实现Interceptor接口或继承AbstractInterceptor类。
在Struts2中称为拦截器栈Interceptor Stack(放行)。拦截器栈就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序依次被调用。
1、通过Java代理实现一个拦截器
第1步:建立一个拦截器的类MyInterceptor,这里的before()和after()方法是以后拦截器会执行的方法。package com.proxy; public class MyInterceptor { public void before() { System.out.println("拦截器MyInterceptor用:before()!"); } public void after() { System.out.println("拦截器MyInterceptor调用:after()!"); } }
第2步:我们模拟一个业务组件接口ModelInterface和一个业务组件实现类ModelImpl。
package com.proxy; public interface ModelInterface { public void myfunction(); } package com.proxy; public class ModelImpl implements ModelInterface { public void myfunction() { System.out.println("业务方法调用:myfunction()"); } }
第3步:创建一个动态代理类DynamicProxy,这个类是实现
InvocationHandler接口。
InvocationHandler 是代理实例的调用处理程序实现的接口。每个代码实例都具有一个关联的调用处理程序。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的 invoke 方法。也就是说:调用一个功能,不直接调用原类而去调用它的代理,代理通过反射机制找到它的这个功能的方法。然后代理自己去执行,所以invoke()会自动执行。
package com.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class DynamicProxy implements InvocationHandler { private Object model;// 被代理对象 private MyInterceptor inceptor = new MyInterceptor();// 拦截器 /* 动态生成一个代理类对象,并绑定被代理类和代理处理器 */ public Object bind(Object business) { this.model = business; return Proxy.newProxyInstance( // 被代理类的ClassLoader model.getClass().getClassLoader(), // 要被代理的接口,本方法返回对象会自动声称实现了这些接口 model.getClass().getInterfaces(), // 代理处理器对象 this); } /* * 代理要调用的方法,并在方法调用前后调用连接器的方法 * proxy 代理类对象、method 被代理的接口方法、args被代理接口方法的参数 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; inceptor.before(); result = method.invoke(model, args); inceptor.after(); return result; } }
第4步:写个类测试一下
package com.proxy; public class TestProxy { public static void main(String[] args) { // 生成动态代理类实例 DynamicProxy proxy = new DynamicProxy(); // 生成待测试的业务组件对象 ModelInterface obj = new ModelImpl(); // 将业务组件对象和动态代理类实例绑定 ModelInterface businessProxy = (ModelInterface) proxy.bind(obj); // 用动态代理类调用方法 businessProxy.myfunction(); } }
2、Struts2框架中拦截器
第1步:创建一个拦截器的触发页面 test_interceptor.jsp<%@ page language="java" pageEncoding="UTF-8"%> <%@ taglib prefix="s" uri="/struts-tags"%> <html> <head></head> <body> <s:form action="test_interceptor"> <s:textfield name="username" label="username"></s:textfield> <s:submit name="submit"></s:submit> </s:form> </body> </html>
第2步:定义拦截器类 MyInterceptor1.java
package com.interceptor; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.Interceptor; public class MyInterceptor1 implements Interceptor { public void init() {// 覆盖Interceptor接口中的init函数 System.out.println("拦截器已经被加载"); } public void destroy() {// 覆盖Interceptor接口中的destroy函数 System.out.println("destroy"); } /* 覆盖Interceptor接口中的intercept函数 */ public String intercept(ActionInvocation invocation) throws Exception { System.out.println("调用intercept方法"); /* invocation.invoke()方法检查是否还有拦截器 有的话继续调用余下的拦截器 没有了则执行action的业务逻辑 */ String result = invocation.invoke();//放行 System.out.println("2222222"); return result; } }
第3步:Struts2配置文件,拦截器的映射
<package name="myinterceptor" extends="struts-default"> <!-- 定义拦截器 --> <interceptors> <interceptor name="myInterceptor" class="com.interceptor.MyInterceptor1"/> </interceptors> <!-- 配置action --> <action name="test_interceptor" class="com.action.InterceptorTest"> <result name="success">/interceptorsuccess.jsp</result> <result name="input">/test_interceptor.jsp</result> <!-- 将声明好的拦截器插入action中 --> <interceptor-ref name="myInterceptor" /> <interceptor-ref name="defaultStack" /> </action> </package>
第4步:通过拦截器后进入 Action
package com.action; import com.opensymphony.xwork2.ActionSupport; public class InterceptorTest extends ActionSupport { private String username; //private MyDate birth;//特殊类型需要类型转换器 public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String execute() throws Exception { System.out.println("此时所有拦截器完毕,调用action中的execute方法"); return SUCCESS; } }
第5步:通过Action处理后的视图页面 interceptorsuccess.jsp
<%@ page language="java" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <body>通过Interceptor处理后的视图页面</body> </html>
3、在Struts2中配置自定义的拦截器
1、扩展拦截器接口的自定义拦截器配置(实现接口)2、继承抽象拦截器的自定义拦截器配置(继承抽象类)
注:
struts.xml配置文件中缺省拦截器栈
<default-interceptor-ref >定义。如果定义则所有Action都会执行的缺省拦截器栈拦截器,并按照循序从上到下执行。如果哪个拦截器没有通过则下面拦截器不会执行。
如果没有定义缺省拦截器栈,则缺省拦截器栈不起作用。
三、Struts2转换器
在B/S中,将字符串请求参数转换为相应的数据类型,应该是MVC框架提供的基本功能。Struts2也提供了类型转换功能。在Struts2中分两种转换,一种是局部转换,另一种是全局类型转换。具体转换的实施需要一个转换类和一个自定义类。
(1)局部类型转换
对于int,long,double,char,float等基本类型,Struts2会自动完成类型转换,像age年龄,在输入页面是String型的,到Action后会自动转换成int型。而如果是转换成其它类类型的话,就需要自定义类型转换。这样就需要一个自定义类。要定义一个转换类,需要继承ognl.DefaultTypeConverter这个类 ,这是个类型转换的类。第1步: 编写转换类PointConverter.java
package com.converter; import java.util.Map; import ognl.DefaultTypeConverter; import com.bean.Point; public class PointConverter extends DefaultTypeConverter { public Object convertValue(Map context, Object value, Class toType) { /* * Map context页面上下文,Object value * 是要进行类型转换的值。如果是从客户端到自定义的类,那么value是个字符串。注意:它是一个字符串的数组。因为:在表单中可以有多个文本域,而所有文本域可以是同一个名字,这时是考虑通用性而作为数组处理的。如果只有一个文本域,则数组只有一个元素,下标为0。class * toType:来指定向哪一种类型转换,即是向类转换还是向客户端转换 */ if (Point.class == toType) { // 说明由客户端向类转换 Point point = new Point();// 实例化这个类 String[] str = (String[]) value; String[] values = str[0].split(","); // 下面部分代码就是进行转换处理 point.setX(Integer.parseInt(values[0])); point.setY(Integer.parseInt(values[1])); return point; } if (String.class == toType) {// 说明由类转换成String Point point = (Point) value;// 将类转成String的代码处理 return point.toString(); } return null; } }
第2步: 编写Point类。
package com.bean; public class Point { private int x, y; public String toString() { return "(" + x + "," + y + ")"; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } }
第3步: 编写Action类。TypeConverterAction.java
package com.action; import com.bean.Point; import com.opensymphony.xwork2.ActionSupport; public class TypeConverterAction extends ActionSupport{ Point point; public String execute() throws Exception { System.out.println(point.toString()); return SUCCESS; } public Point getPoint() { return point; } public void setPoint(Point point) { this.point = point; } }
第4步:编写转换属性文件。TypeConverterAction-conversion.properties内容为:point=com.converter.PointConverter
自定义类、转换类、action都创建好之后,要创建一个属性文件,放置在与action在同一包。该属性文件名为:action文件名-conversion.properties。文件中的内容如下:
point = 转换类名 即 point=com.PointConverter
注意:
(1)point是Action的一个属性,转换类指明所使用哪个转换类对此属性进行转换。
ActionName+”-validation.xml”
(2)有两种类型的转换器:
一是局部类型转换器。仅仅对某个Action的属性起作用。属性文件名:ActionName-conversion.properties 。内容:属性名=类型转换器类,如date=com.DateConverter 。存放位置与ActionName类相同路径。
二是全局类型转换器。对所有Action的特定类型的属性都会生效。属性文件名:xwork-conversion.properties 。内容如java.util.Date= com.DateConverter.存放位置为WEB-INF/classes/目录下。
第5步:编写JSP页面。
第5步:编写JSP页面。 <%@ page language="java" pageEncoding="UTF-8"%> <%@ taglib prefix="s" uri="/struts-tags"%> <html> <body> <s:form action="converter"> <s:textfield name="point" label="point"></s:textfield> <s:submit name="submit"></s:submit> </s:form> </body> </html>
类型转换的流程
1、用户进行请求,根据请求名在struts.xml中寻找Action。2、在Action中,根据请求域中的名字去寻找对应的set方法。找到后在赋值之前会检查这个属性有没有自定义的类型转换。没有的话,按照默认进行转换;如果某个属性已经定义好了类型转换,则会去检查在Action同一目录下的 action文件名-conversion.properties 文件。
3、从文件中找到要转换的属性及其转换类。
4、然后进入转换类中,在此类中判断转换的方向。我们是先从用户请求开始的,所以这时先进入从字符串到类的转换。返回转换后的对象。流程返回Action。
5、将返回的对象赋值给Action中的属性,执行Action中的execute()。
6、执行完execute()方法,根据struts.xml的配置转向页面。
7、在jsp中显示内容时,根据页面中的属性名去调用相应的get方法,以便输出。
8、在调用get方法之前,会检查有没有此属性的自定义类型转换。如果有,再次跳转到转换类当中。
9、在转换类中再次判断转换方向,进入由类到字符串的转换,完成转换后返回字符串。
10、将返回的值直接带出到要展示的页面当中去显示。
相关文章推荐
- 框架 day28 Struts2-封装数据,类型转换,数据校验,国际化,拦截器
- struts2使用XML框架进行输入校验
- Struts2学习总结(3)--值栈,Ognl表达式,Struts标签库,国际化,数据校验,拦截器
- 主题:Struts2的校验框架,找不到DTD信息
- Struts2校验框架应用总结
- struts2:数据校验,通过XWork校验框架实现(validation.xml)
- Struts2 Field校验框架message元素key的使用方式
- 框架学习之Struts2 第三节 请求参数的接收和自定义类型转换器
- .Java程序员从笨鸟到菜鸟之(四十七)细谈struts2(九)内置拦截器和自定义拦截器详解(附源码) 分类: 学习专区 框架Struts2 Java程序员从笨鸟到菜鸟 2012-05-08 12:
- struts2的XML校验框架小体会
- Struts2 校验框架学习笔记
- struts2基于验证框架的输入校验
- struts2中使用validation框架进行校验的注意事项
- struts2中validation校验框架的原理和使用
- JAVAEE——struts2_04:自定义拦截器、struts2标签、登陆功能和校验登陆拦截器的实现
- Struts2基础数据校验和框架校验
- Struts2自定义拦截器实例—登陆权限验证+验证框架
- JavaWeb框架_Struts2_(三)---->Struts2的拦截器
- struts2知识之--1.struts的验证框架的校验
- day27-struts2---day02( 类型转换,数据校验,国际化,拦截器)