前面知道了struts2的架构图和struts2的自动封装表单参数和数据类型自动转换,今天来学struts2的第三第四个东西,输入校验和拦截器。

 一:输入校验

客户端校验进行基本校验,如检验非空字段是否为空,数字格式是否正确等。客户端校验主要用来过滤用户的误操作。作用是:拒绝误操作输入提交到服务器处理,降低服务器端负担。
  服务器端校验也必不可少,服务器端校验防止非法数据进去程序,导致程序异常,底层数据库异常。服务器端校验是保证程序有效进行及数据完整的手段.
对异常输入的过滤,就是输入校验,也称为数据校验
输入校验分为客户端校验和服务器校验:
1. 客户端校验主要是过滤正常用户的误操作,主要通过js代码完成。

2. 服务器端校验是整个应用阻止非法数据的最后防线,主要通过在应用中编程实现

我们这个地方学习的是服务器端校验。

在以前我们写一个登录页面时,并没有限制用户的输入,不管用户输入什么,我们都存入数据库中,很显然这是不行的,我们需要检测用户输入的文本是否合法,是否符合我们需要的文本格式,符合才放行,而struts2中就有这种功能,能帮我们在服务器段进行判断,比如用户名不能为空,年龄只能在0-100之间等。现在我们就来说说如何使用struts2中的校验功能。分为两种,编程式校验和配置校验(XML配置校验)

验证器的验证时机:
验证发生在execute方法之前,在struts2 的params拦截器已经把请求的参数通过反射设置到 Action 的属性之后,所以,验证框架实际上验证的是值栈中的值

验证的结果:
如果用户输入的参数完全满足验证结果,那么会继续执行execute方法。如果不满足,会跳转到Action配置中的result name="input" 的页面中中

1.1 编程式校验

下面给出一个例子:

首先创建动作类:MyValidationAction.java

 package action;

 import com.opensymphony.xwork2.ActionSupport;

 public class MyValidationAction extends ActionSupport {

     private String name;
private int age;
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the age
*/
public int getAge() {
return age;
}
/**
* @param age the age to set
*/
public void setAge(int age) {
this.age = age;
} /* (non-Javadoc)
* @see com.opensymphony.xwork2.ActionSupport#validate()
*/ public void validateTest02() {
if(name==null || name.trim().equals("") || name.length()==0){
addFieldError("name","validateTest02:请输入有效的用户名");
} if(age>120 || age<=0){
addFieldError("age","validateTest02:请输入有效的年龄");
} } public void validate() {
if(name==null || name.trim().equals("") || name.length()==0){
addFieldError("name","validate:请输入有效的用户名");
} if(age>120 || age<=0){
addFieldError("age","validate:请输入有效的年龄");
} } public String test01(){
System.out.println("test01.....");
//System.out.println("user info:"+name+","+age);
return "success";
} public String test02(){
System.out.println("test02.....");
//System.out.println("user info:"+name+","+age);
return "success";
}
}

书写表单界面:login8.jsp

 <%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>登录实例</title>
</head>
<body>
<form action = "Login8_test01" method="post">
<p>用户名 <input type = "text" name="name"/></p>
<p>密码 <input type = "text" name="age"/></p>
<input type = "submit" value = "登录"/>
</form>
</body>
</html>

struts.xml配置:请看这个action, 多出了一个返回result:input

         <action name="Login8_*" class="action.MyValidationAction" method="{1}">
<result name="success">/index.jsp</result>
<result name="input">/error.jsp</result>
</action>

创建MyValidationAction继承ActionSupport,通过重写validate()方法实现输入校验,validate()方法会校验action中所有的方法。当某个数据校验失败时,我们可以调用addFieldError()方法往系统的fieldErrors添加校验失败信息。如果系统的fieldErrors包含失败信息,sturts2会将请求转发到名为input的result。在input视图中,可以通过 <s:fielderror/>标签显示失败信息。若只想对action中的指定方法进行校验,只需将MyValidationAction中的validate()方法名称改成validateXxx()即可,其中Xxx为对应的方法名称,Xxx的第一个字母要大写。如本例中,若只想对MyValidationAction中的test02()方法进行校验,则可以将validate()方法名称改为validateTest02()即可。
加入了某个函数校验或所有函数校验方法,实际上就是在运行函数之前,先运行校验方法。
例如本利中,在浏览器输入:http://localhost:8080/Struts2Demo/login8.jsp

不输入用户名和密码,直接点击登录,可以看到就会调用校验函数Validate()!  发现name和age都校验不通过。就会通过函数addFieldError("xxx","yyy")将错误信息存起来,等回到页面在显示出来。通过下面流程图可以看出,如果filedError中有错误信息,workflow拦截器会工作,直接返回input,就会跳转到input结果码对应的界面。

我们把表页面简单修改下:让它调用test02()函数。

 <form action = "Login8_test02" method="post">
<p>用户名 <input type = "text" name="name"/></p>
<p>密码 <input type = "text" name="age"/></p>
<input type = "submit" value = "登录"/>
</form>

同样在浏览器输入:http://localhost:8080/Struts2Demo/login8.jsp,然后不输入用户名,密码直接登录,

可以看到此时,action中的两个校验函数都进行调用。和前面说明一样,如果只想对某个函数进行校验,就在校验函数后面加上函数名字。

validate()方法会校验action中所有的方法。若只想对action中的指定方法进行校验,只需将MyValidationAction中的validate()方法名称改成validateXxx()即可,其中Xxx为对应的方法名称,Xxx的第一个字母要大写。若都存在时,系统通过反射技术先调用action中的validateXxx()方法,然后再调用action中的validate()方法。

 总结:输入校验的流程。
a. 类型转换器对请求参数执行类型转换,并把转换后的值赋给action中的属性。
b. 如果在执行类型转换的过程中出现异常,系统会将异常信息保存到ActionContext,conversionError拦截器将异常信息封装到fieldErrors里。不管类型转换是否出现异常,都会进入第c步。
c. 系统通过反射技术先调用action中的validateXxx()方法,Xxx为方法名。
d. 再调用action中的validate()方法。
e. 经过上面4步,如果系统中的fieldErrors存在错误信息(即存放错误信息的集合的size大于0),系统自动将请求转发至名称为input的视图。如果系统中的fieldErrors没有任何信息,系统将执行action中的处理方法。若没有书写input结果码对应的表单界面,将会出现404错误。

1.2  xml配置检验

实际上就是调用struts2已经定义好的各种校验器,来对我们书写的动作类进行校验。

要求:

1、必须实现validateable接口,actionsupport已经实现了,所以我们只需要直接继承actionsupport即可 

2、action中必须为属性提供getXXX、setXXX方法,因为代码校验是在Action本类中来完成校验,这说明我们可以直接使用本类的private属性,但如果使用XML配置方式校验,这需要使用校验框架的代码来完成校验工作,那么校验框架需要调用Action的getXXX()方法来获取被校验的属性,所以一定要为被校验的属性提供getXXX()方法。

创建校验配置文件

命名规范:

actionClass-actionName-validation.xml  

actionClass:action的类名

actionName:action的访问名称,及在struts.xml中配置的,<action name="">,  若有动态函数传递,只想对某个函数进行校验,就需要把函数名显式写出来。

validation.xml:固定后缀名。

比如:MyValidationAction2-Login9_test01-validation.xml 这种是对特定方法进行校验

路径:必须与action同包下

下面给出我们的动作类:MyValidatorAction2.java

 package action;

 public class MyValidationAction2 {

     private String name;
private int age;
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the age
*/
public int getAge() {
return age;
}
/**
* @param age the age to set
*/
public void setAge(int age) {
this.age = age;
} public String test01(){
System.out.println("test01.....");
//System.out.println("user info:"+name+","+age);
return "success";
} }

然后给出我们的登录表单:login9.jsp

 <%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>登录实例</title>
</head>
<body>
<form action = "Login9_test01" method="post">
<p>用户名 <input type = "text" name="name"/></p>
<p>密码 <input type = "text" name="age"/></p>
<input type = "submit" value = "登录"/>
</form>
</body>
</html>

给出struts.xml配置:

         <action name="Login9_*" class="action.MyValidationAction2" method="{1}">
<result name="success">/index.jsp</result>
<result name="input">/error.jsp</result>
</action>

下面给出最主要的validator配置:MyValidationAction2-Login9_test01-validation.xml

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
"-//Apache Struts//XWork Validator 1.0.2//EN"
"http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd"> <validators> <field name ="name"> <!--action中需要校验的属性 -->
<field-validator type="requiredstring"> <!-- 指定校验器 -->
<param name="trim"> true</param> <!-- 为校验器中的属性trim注值,trim默认值-->
<message>用户名不能为空</message> <!-- 校验失败后的提示信息 -->
</field-validator>
</field> <field name="age"> <!-- action中需要校验的属性 -->
<field-validator type="int"> <!-- 指定校验器类型 -->
<param name="min">0</param> <!-- 为校验器中参数配置 -->
<param name="max">120</param> <!-- 为校验器中参数配置 -->
<message>年龄输入不对</message> <!-- 校验失败后输出错误提示信息 -->
</field-validator> <field-validator type="required">
<message>请输入年龄</message>
</field-validator>
</field> </validators>

主要是书写这个xml配置。注意各个字段配置。

下面在浏览器输入:http://localhost:8080/Struts2Demo/login9.jsp

不输入任何用户名等,直接点击登录,如右图所以,显示成功。

看控制台输出:

16:08:10.208 [http-bio-8080-exec-15] ERROR action.MyValidationAction2 - Validation error for name:用户名不能为空
test01.....

由控制台输出可以看到,

1:校验中的错误提示信息显示在了控制台,并没有回显到表单界面。也就是没有像上面那样返回码input。

2:并且虽然校验不过,依然把函数运行完了,我们看到输出了“test01.....”

要是这样就感觉没什么用????

通过找资料发现,通过xml配置校验应该和上面一样,也会返回结果码input,并将错误信息回显在表单。哪儿错了呢???

查看code才发现,是我的action没有继承ActionSupport这个父类。导致功能不全。

然后我们action加上父类,public class MyValidationAction2 extends ActionSupport {}

同样按照上面运行,在浏览器就会输出下面信息,而控制台就不会输出任何信息。

所以两种配置方法一样。

校验规则有很多,在xwork-core-xxx.jar/com.opensymphony.xwork2/validator/validators/default.xml中就能够找到所有的校验规则。

总结:如果让我自己选的话,肯定是选择xml配置校验的方法,因为,能使用struts2中的一些校验规则,就无需自己编写了,不过到后面应该都有其他更方便的校验方法,而不会使用struts2内置的这些校验。

 二:拦截器

可以说拦截器是struts2的最主要部分之一。struts2也提供了很多拦截器。大家不要以为拦截器就是用来拦截的,其实他帮助我们解决了很多工作。

学到现在,其实我们已经用了很多个拦截器:

参数静态封装,我们用了staticparam

参数动态封装,我们用param,modelDriven

自动类型转换,我们用convert

上面讲述的校验器,我们也用了拦截器validation.

所以拦截器不是用来拦截的。

系统提供的拦截器

现在应该都知道了,前面说表单提交参数自动封装时就提到了好几种拦截器,而上面说校验数据也提到了两种拦截器,基本上我们也知道拦截器的作用是啥了,就是在到达action之前做的很多处理,提前帮我们做事情的一种机制,而我们并不需要编写这些拦截器,因为struts2已经帮我们写好了常用的一些拦截器,并且有个defaultStack的拦截器栈,我们使用的action就经过struts2提供的这个默认拦截器栈。其中有18个,也就是说,如果不修改默认拦截器栈,那么每次我们访问action,都会经过这18个拦截器栈,我们来看看哪18个,struts2的默认拦截器栈(18个拦截器):

找到defaultStack

其中我们应该了解很多个了,277行,i18n用来做国际化,281行,modeDriven用来数据封装的,282行fileUpload,上传下载的,285行staticParams用来获取静态参数的,287行params用做数据封装的,290行conversionError标识数据类型转换异常处理的,291行,validation用来做输入校验的 292行workflow用来检测<filederror>是否有值,有值则跳到input结果码对应的页面。 其他的还没讲到到后面我都会一一讲解清楚的,先大概了解一下。

自定义拦截器

大多数功能的拦截器struts2都已经帮我们写好了,但是有一些,我们需要自己在往其中功能,那就必须自定义拦截器了。自定义拦截器很简单,就分两步即可。

第一步:编写拦截器类MyInterceptor,继承AbstractInterceptor类。(它帮我们实现了Interceptor接口)。

 package action;

 import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor; public class MyInterceptor extends AbstractInterceptor { @Override
public String intercept(ActionInvocation invocation) throws Exception { System.out.println("My interceptor......");
return null;
} public String test01(){ System.out.println("test01....."); return "success";
} }

第二步:注册拦截器,在struts.xml中注册

在<package>声明拦截器

在<action>中引用拦截器

直接在上面例子中进行修改,给package配置这个拦截器。struts.xml配置如下

     <package name="zsy" namespace="/" extends="struts-default">

         <interceptors>
<interceptor name = "MyInterceptor" class ="action.MyInterceptor"></interceptor>
</interceptors> <action name="Login9_*" class="action.MyValidationAction2" method="{1}">
<result name="input">/error.jsp</result>
<result name="success">/index.jsp</result>
<interceptor-ref name="MyInterceptor"></interceptor-ref>
</action> </package>

但是一般不用这种,因为Struts2有这么一种机制,一旦为Action指定了拦截器,那么就不会再为这个Action执行默认拦截器了,即defaultStack这个拦截器栈中的拦截器都不会执行,也就是说,这个Action没有输入校验、没有参数注入、没有国际化、没有…,这是不行的,

如果我们此时在浏览器输入:http://localhost:8080/Struts2Demo/login9.jsp

浏览器不会有任何输出,在控制台只输出:My interceptor......

所以这样肯定是不可以的。所以我们需要在这个<action>元素中再引用defaultStack拦截器栈。

修改struts.xml如下:

     <package name="zsy" namespace="/" extends="struts-default">

         <!-- 申明拦截器 -->
<interceptors>
<interceptor name = "MyInterceptor" class ="action.MyInterceptor"></interceptor>
</interceptors> <action name="Login9_*" class="action.MyValidationAction2" method="{1}">
<result name="input">/error.jsp</result>
<result name="success">/index.jsp</result>
<!-- 引用默认拦截器栈 -->
<interceptor-ref name="defaultStack"></interceptor-ref>
<!-- 使用自定义的拦截器 -->
<interceptor-ref name="MyInterceptor"></interceptor-ref> </action> </package>

先调用默认拦截器栈,然后调用自定义拦截器,在浏览器输入:http://localhost:8080/Struts2Demo/login9.jsp

浏览器输出:证明默认拦截器生效了。

但是我们自定义加的拦截器没有运行,在控制台没有任何输出。

然后我们把定义的顺序在struts.xml修改下,将自定义拦截器放在前面,默认拦截器放在后面,如下:

  <!-- 使用自定义的拦截器 -->
<interceptor-ref name="MyInterceptor"></interceptor-ref>
<!-- 引用默认拦截器栈 -->
<interceptor-ref name="defaultStack"></interceptor-ref>

同样进行上面测试,浏览器不会有任何输入,在控制台只输出:My interceptor......

也就是自定义拦截器运行了,可是默认拦截器没有运行。???????其实是前面一个地方有错误,请看下面解决办法。

所以这种方案也不行,并且因为只有一个action,如果有十几个action呢?需要为每个action配置默认拦截器栈和自定义拦截器,也很麻烦。

创建一个拦截器栈,将默认拦截器栈和自定义拦截器加入其中,然后将struts2的默认拦截器栈修改为我们新构建的拦截器栈。

看struts.xml配置:

  <package name="zsy" namespace="/" extends="struts-default">

         <!-- 申明拦截器 -->
<interceptors>
<interceptor name = "MyInterceptor" class ="action.MyInterceptor"></interceptor>
<!-- 创建新的拦截器栈 -->
<interceptor-stack name ="myStack">
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="MyInterceptor"></interceptor-ref> </interceptor-stack>
</interceptors>
<!-- 将默认拦截器栈修改为使用我们自定义的拦截器栈 -->
<default-interceptor-ref name = "myStack"></default-interceptor-ref> <action name="Login9_*" class="action.MyValidationAction2" method="{1}">
<result name="input">/error.jsp</result>
<result name="success">/index.jsp</result> <!-- <interceptor-ref name="myStack"></interceptor-ref> --> </action> </package>
 <default-interceptor-ref name = "myStack"></default-interceptor-ref>这个是整个package中所有action都用这个重新定义的拦截器栈。
<!--  <interceptor-ref name="myStack"></interceptor-ref> --> 也可以配置这个,在action中配置,只是这个action用自己新定义的拦截器栈。其他action随便。

同样进行上面的测试,发现默认拦截器运行了,自定义拦截器没有运行。那么问题出在哪儿了?不可能只能运行一个啊。

下面查出原因是因为我们自定义的拦截器类书写错误,没有加入递归调用String invoke = invocation.invoke();

想想,我们的拦截器是怎么一次运行起来的,就是一个个相互递归调用。所以修改后的自定义拦截器如下:

 package action;

 import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor; public class MyInterceptor extends AbstractInterceptor { @Override
public String intercept(ActionInvocation invocation) throws Exception { System.out.println("My interceptor......");
String invoke = invocation.invoke(); return invoke; } public String test01(){ System.out.println("test01....."); return "success";
} }

然后在进行测试,无论自定义拦截器放前面还是后面,都可以被调用了。

到此,拦截器我们就可以自己定义了。

了解了struts2中数据校验的功能和struts2中的18个拦截器,还有如何自定义拦截器这些操作,个人感觉还是没有难度的,现在只是在学习知识,学会这个知识点,等后面使用struts2来写一个小的demo,就会将所有零碎的知识点整合到一起。好好努力。

主要参考博客:

https://www.cnblogs.com/whgk/p/6593916.html-------写的非常好。

Struts2各个功能详解(2)-输入校验和拦截器的更多相关文章

  1. struts2(三) 输入校验和拦截器

    前面知道了struts2的架构图和struts2的自动封装表单参数和数据类型自动转换,今天来学struts2的第三第四个东西,输入校验和拦截器, --WH 一.输入校验 在以前我们写一个登录页面时,并 ...

  2. Struts2学习(三)———— 输入校验和拦截器

    一.输入校验 在以前我们写一个登录页面时,并没有限制用户的输入,不管用户输入什么,我们都存入数据库中,很显然这是不行的,我们需要检测用户输入的文本是否合法,是否符合我们需要的文本格式,符合菜放行,而s ...

  3. struts2各个功能详解(1)----参数自动封装和类型自动转换

    struts2里面的各个功能,现在确实都不清楚,完全属于新学! 通过前面的例子,有时就会疑问,这些jsp中的数据信息是怎么传送给action的?例如: <form action = " ...

  4. 第15.44节、PyQt输入部件:QAbstractSlider派生类QScrollBar滚动条、QSlider滑动条、QDial刻度盘功能详解

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 一.引言 Designer中的输入部件Horizo ...

  5. 第15.42节、PyQt输入部件:QFontComboBox、QLineEdit、QTextEdit、QPlainText功能详解

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 一.引言 输入部件量比较多,且功能很丰富,但除了用于编写编辑器.浏览器 ...

  6. 第三十五章、PyQt输入部件:QFontComboBox、QLineEdit、QTextEdit、QPlainText功能详解

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 一.引言 输入部件量比较多,且功能很丰富,但除了用于编写编辑器.浏览器 ...

  7. 第15.41节、PyQt(Python+Qt)入门学习:输入部件QComboBox组合框功能详解

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 一.概述 Designer中输入工具部件中的Combo Box组合框与 ...

  8. SVN功能详解

    SVN功能详解   TortoiseSVN是windows下其中一个非常优秀的SVN客户端工具.通过使用它,我们可以可视化的管理我们的版本库.不过由于它只是一个客户端,所以它不能对版本库进行权限管理. ...

  9. SNS社交系统“ThinkSNS V4.6”活动应用功能详解及应用场景举例

    sns社交系统ThinkSNS目前拥有功能:朋友圈(微博).微吧(论坛).频道.积分商城.IM即时聊天.直播.问答.活动.资讯(CMS).商城.广场.找人.搜索.评论.点赞.转发.分享.话题.积分.充 ...

随机推荐

  1. 架构师技能图谱 V1.2

    系统架构能力 基本理论 扩展性设计 可用性设计 可靠性设计 一致性设计 负载均衡设计 过载保护设计 灾难恢复和备份 协议设计 二进制协议 文本协议 接入层架构设计 DNS 轮询 动静态分离 静态化 反 ...

  2. 更多的bash命令

    深入介绍Linux系统管理命令,可以使用这些命令处理系统上的数据文件: 1.监控程序 1.1.进程的查看 ps 查看进程 GNU ps 命令支持3种不同的命令行参数: 1.Unix类型参数,前面一条短 ...

  3. hive 表新增字段后更新分区无法显示数据

    解决方案: 1.删除分区后重新跑数据 alter table drop partition(分区字段=“”): 2.新增字段运行程序后其实数据已经有了,只是查询hive的时候无法显示出来, 这个时候只 ...

  4. Android几种视频播放方式,VideoView、SurfaceView+MediaPlayer、TextureView+MediaPlayer,以及主流视频播放器开源项目

    简单的说下一Android的几种视频播放功能: 1.VideoView:最简单的视频播放 <FrameLayout xmlns:android="http://schemas.andr ...

  5. Hexo NexT主题/cnblog等博客增加点击出现红心的特效

    查看效果 每日前端 我的博客 实现:1.下载这段js代码到项目目录 ===>下载地址2.在需要的地方添加js代码 <script type="text/javascript&qu ...

  6. 字节码操作JAVAssist

    字节码操作Javassist 字节码:字节码是设计被用来将代码高效的传送给多种软件平台.硬件平台,字节码的设计也实现了Java的平台无关性,字节码比机器码更抽象,它通常被认为是包含了一个可执行文件的二 ...

  7. VS编写一个项目的路径规划

    原文路径:http://blog.csdn.net/puttytree/article/details/7838419 https://www.cnblogs.com/zhehan54/p/45678 ...

  8. idea搭建ssm框架

    1.file-->new-->project-->maven.... 2.建立后的目录: 3.pom.xml依赖建立: <?xml version="1.0" ...

  9. Java学习随笔(2)--爬虫--天气预报

    public class Spiderweather { public static void main(String[] args) { List<String> list = null ...

  10. mysql监控执行的sql语句

    转载 https://blog.csdn.net/nzjdsds/article/details/77513869 MySQL用SQL开启general_log并设置路径 2017年08月24日 00 ...