【Struts2】(2)Struts2校验框架、Struts2拦截器、Struts2转换器

一、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、将返回的值直接带出到要展示的页面当中去显示。

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、下 4载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、下载 4使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、下载 4使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值