客户端校验和服务器端校验
数据的输入校验分为客户端校验和服务器端校验,客户端校验主要是过滤正常用户的误操作,主要通过JavaScript代码完成;服务器端校验是整个应用阻止非法数据的最后防线,主要通过在应用中编程实现。
客户端校验
客户端校验的步骤一般通过JavaScript实现,来过滤常见的错误操作和用户的误操作,步骤如下:
1、编写校验函数;
2、在提交表单的事件中调用校验函数;
3、根据校验函数来判断是否进行表单提交;
一个简单的客户端校验案例
<%--
Created by IntelliJ IDEA.
User: mairr
Date: 17-12-5
Time: 下午10:07
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page language = "java" import = "java.util.*" pageEncoding="utf-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
<title>注册界面</title>
<script type="text/javascript" >
// 去掉前后的空格
function deltrim(x) {
while (x.length > 0 && x.charAt(0) == ' ')
x = x.substring(1, x.length);
while (x.length > 0 && x.charAt(x.length - 1) == ' ')
x = x.substring(0, x.length - 1);
return x;
}
// 非空验证
function isNULL(elem,message){
var va = deltrim(elem.value);
if(va == " ") {
alert(message);
elem.focus();
return false;
}
return true;
}
// 验证帐号,帐号只能是小写字母数字,并且只能以字母开头
function validateId(){
var first = document.forms[0].id.value.charAt(0);
var exp = /^[a-z0-9]+$/;
if(isNULL(document.forms[0].id,"请输入帐号")){ // 验证非空
// 验证首字符
if((first >= 'a' && first <= 'z') || (first >= 'A' && first <= 'Z')){}
else{
alert("帐号首字符必须是字母!");
document.forms[0].id.focus();
return false;
}
if(!exp.test(document.forms[0].id.value)){
alert("帐号必须是字母或者数字!");
document.forms[0].id.focus();
return false;
}
return true;
}
else{
return false;
}
}
// 验证密码,密码要在8位以上,且需要有字母或者数字之外的字符
function validatepwd(){
var exp = /^[a-z0-9]+$/;
if(isNULL(document.forms[0].pwd," 请输入密码")){ //验证非空
if(document.forms[0].pwd.value.length <= 8){
alert("密码大于8位");
document.forms[0].pwd.focus();
return false;
}else{
if(exp.test(document.forms[0].pwd.value)){
alert("密码要有字母和数字之外的字符!");
document.forms[0].pwd.focus();
return false;
}
}
}else{
return false;
}
if(document.forms[0].pwd.value != document.forms[0].repwd.value)
{
alert("两次密码不一样!");
document.forms[0].pwd.focus();
return false;
}
return true;
}
// 验证邮箱,右边为六位数子
function checkcode() {
var exp = /^[0-9]+$/;
if(isNULL(document.forms[0].ecode,"请输入邮编")){ // 验证非空
if(document.forms[0].ecode.value.length != 6){
alert("邮编为6位");
document.forms[0].ecode.focus();
return false;
}else{
if(!exp.test(document.forms[0].ecode.value)){
alert("邮编为数字");
document.forms[0].ecode.focus();
return false;
}
}
return true;
}else{
return false;
}
}
// 验证E-mail的基本格式
function checkEmail(){
var exp = /^\w+((-\w+)|(\.\w+))*@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/;
if(isNULL(document.forms[0].email,"请输入Email")){ // 验证非空
if(!exp.test(document.forms[0].email.value)){
alert("Email格式错误");
document.forms[0].email.focus();
return false;
}
return true;
}else{
return false;
}
}
// 提交按钮
function gogo(){
if(validateId() && validatepwd() && checkcode() && checkEmail()){
document.forms[0].submit();
return true;
}
return false;
}
</script>
</head>
<body>
<s:form action ="" theme="simple">
<table>
<tr>
<td>登录帐号</td>
<td><s:textfield name="id"/></td>
</tr>
<tr>
<td>密码</td>
<td><s:password name="pwd"/></td>
</tr>
<tr>
<td>确认密码</td>
<td><s:password name="repwd"/></td>
</tr>
<tr>
<td>邮编</td>
<td><s:textfield name = "ecode"/></td>
</tr>
<tr>
<td>Mail</td>
<td><s:textfield name = "email"/></td>
</tr>
<tr>
<td><input type="button" value="提交" onclick="return gogo()" /></td>
<td><s:reset value = "重置"/></td>
</tr>
</table>
</s:form>
</body>
</html>
通过点击button触发校验方法,校验通过提交表单,否则不提交并提示错误
服务器端校验
服务器对于系统的安全性、完整性、健壮性起到至关重要的作用。Struts2框架提供了一套验证框架,通过验证框架能够非常简单和快速地完成输入校验。
在服务器端,对于输入校验Struts2提供了两种实现方法:一是采用手工编写代码实现;另外一种是,给予XML配置方式的实现(校验框架校验)。接下来详细介绍这两种方法。
手动实现数据校验
手动编程校验主要是通过在类中编写校验逻辑代码,有两种方式i:一是在Action类中重写validate()方法;二是在Action类中重写validateXxx()方法,Xxx是方法名,第一个字母大写。
重写validate方法实现校验
validate()方法会校验Action中所有与execute()方法签名相同的方法。当某个数据校验失败时,在validate()方法中应该调用addFiledError()方法向系统fieldErrors添加校验失败信息。为了使用addFileError方法,Action类需要继承ActionSupport。
如果系统的fieldErrors包含失败信息,Struts2会将请求转发到名为input的result。在input视图中可以通过
示例如下:
validate.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>数据校验测试</title>
<style type="text/css">
form {
width: 300px;
margin: 0 auto;
margin-top: 0px;
margin-top: 40px;
}
</style>
</head>
<body>
<s:form action="validate" theme="simple" namespace="/">
<table>
<tr>
<td>登录帐号</td>
<td><s:textfield name="id" /></td>
</tr>
<tr>
<td>密码</td>
<td><s:password name="pwd" /></td>
</tr>
<tr>
<td>确认密码</td>
<td><s:password name="repwd" /></td>
</tr>
<tr>
<td><input type="submit" value="提交"s /></td>
<td><s:reset value="重置" /></td>
</tr>
</table>
<!--显示this.addFieldError("id","id不能为空")的信息-->
<s:fielderror fieldName="id"/>
<!--显示所有校验失败信息-->
<s:fielderror/>
</s:form>
<br>
<s:debug></s:debug>
</body>
</html>
struts.xml
<!-- 数据校验 -->
<action name="validate" class="action.ValidateAction" method="login">
<result name="input">validate.jsp</result>
<result name="success">/success.jsp</result>
</action>
ValidateAction.java
/**
*
*/
package action;
import com.opensymphony.xwork2.ActionSupport;
/**
* @author Administrator
*
*/
public class ValidateAction extends ActionSupport{
private String id;
private String pwd;
private String repwd;
public String login() throws Exception {
return SUCCESS;
}
public void validate() {
System.out.println("重写validate方法校验");
if (id == null || id.trim().equals("")) {
this.addFieldError("id", "id不能为空");
}
if (pwd == null || pwd.trim().equals("")) {
this.addFieldError("pwd", "密码不能为空");
} else {
if (pwd.length() < 6 || pwd.length() > 12) {
this.addFieldError("pwdlength", "密码的长度在6~12位之间");
}
}
if (!pwd.equals(repwd)) {
this.addFieldError("pwdsame", "两次密码不一致");
}
}
/**
* @return the id
*/
public String getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(String id) {
this.id = id;
}
/**
* @return the pwd
*/
public String getPwd() {
return pwd;
}
/**
* @param pwd the pwd to set
*/
public void setPwd(String pwd) {
this.pwd = pwd;
}
/**
* @return the repwd
*/
public String getRepwd() {
return repwd;
}
/**
* @param repwd the repwd to set
*/
public void setRepwd(String repwd) {
this.repwd = repwd;
}
}
重写validateXxx()方法校验
将validate方法改为
public void validateLogin() {
System.out.println("validateLogin方法的校验");
if (id == null || id.trim().equals("")) {
this.addFieldError("id", "id不能为空");
}
if (pwd == null || pwd.trim().equals("")) {
this.addFieldError("pwd", "密码不能为空");
} else {
if (pwd.length() < 6 || pwd.length() > 12) {
this.addFieldError("pwdlength", "密码的长度在6~12位之间");
}
}
if (!pwd.equals(repwd)) {
this.addFieldError("pwdsame", "两次密码不一致");
}
validateXxx()只会校验Action中方法名为Xxx()的方法,其中Xxx的第一个字母要大写。重写validateXxx()方法进行输入校验与重写validate()方法基本一样,唯一不同的就是校验的方法名不同。
struts2的输入校验的流程
经过前面讲解,可以知道,Struts2输入校验需要经过一下几个步骤:
1、类型转器对请求参数执行类型转换,并且把转换后的值赋给Action中的属性。
2、如果在执行转换过程中出现了异常,系统会把异常信息保存到ActionContext , conversionError拦截器将异常信息添加到fieldError里。不管类型转换是否出现异常,都会进入步骤三;
3、系统通过反射技术先调用Action中的validateXxx()方法,Xxx为方法名字。
4、再调用Action中的validate()方法;
5、经过上面的4个步骤,如果系统中的fieldError存在错误信息(即存放错误信息的集合的size大于0),系统自动将请求转发至名称为input的视图。如果系统中的fileError没有任何错误信息,系统将执行Action中的处理方法。
6、检查Action同目录下是否有校验文件,有的话进行相关校验处理,校验文件格式为Action类名-validation.xxml或者Action类名-action映射名-validation.xml(一个Action类对应多个Action时)
Struts2内置的校验器
Struts2框架提供的内置校验器如下:
1、required:必填校验器,要求field的值不能为null;
2、 requiredstring:必填字符串校验器,要求field的值不能为null,并且长度大于0,默认情况下会对字符串去掉前后空格;
3、 stringlength:字符串长度校验器,要求field的值必须在指定的范围内,否则校验失败;minLength参数指定最小长度,maxLength参数指定最大长度,trim参数指定校验field之前是否去掉字符串前后空格;
4、regex:正则表达式校验器,检查被校验的field是否匹配一个正则表达式。expression参数指定正则表达式, caseSensitive参数指定进行正则表达式匹配时,是否区分大小写,默认值为true;
5、int:整数校验器,要求field的整数值必须在指定范围内,mini指定最小值,max最大值;
6、double:双精度浮点数校验器,要求field的双进度浮点数必须在指定范围内,mini指定最小值,max最大值;
7、fieldexpression:字段OGNL表达式校验器,要求field满足一个OGNL表达式,expression参数指定一个OGNL表达式,该逻辑表达式基于ValueStack进行求值,返回true时校验通过,否则不通过。该校验器只能用于
8、email:邮件地址校验器,要求如果field的值非空,则必须是合法的邮件地址;
9、url:网址校验器,要求如果field的值非空,则必须是合法的URL地址i;
10、date:日期校验器,要求field的日期值必须在指定的范围内,mini指定最小值,max指定最大值;
11、conversion:转换校验器,指定在类型转换失败时,提示错误信息;
12、visitor:用于校验Action中的复合属性,指定一个校验文件用于校验复合中的属性;
13、expression:OGNL表达式表达式校验,expression参数指定OGNL表达式,该逻辑表达式基于ValueStack进行求值,返回true时校验通过,否则不通过,该校验器不用在字段校验器的配置中,只能用于
内置校验器的配置
校验文件放在Action类的目录下,命名规则和Action的类名有关。
ActionName-validation.xml:其中ActionName就是需要校验的Action的类名。在struts.xml文件的Action定义中,需要定义input的逻辑视图名,将input逻辑视图映射到login.jsp页面。在这种校验方式下,无需书写校验代码,只需要通过配置文件指定校验规则即可,因此提供了更好的可维护性。当校验失败时,返回input结果。
ActionName-action-validation.xml:其中ActionName就是需要校验的Action的类名;action是action的映射名,也就是在struts.xml中配置的action名字,而不是action的方法。
校验文件的配置方法
配置文件有两种方法来校验:
- 使用
<validator>
- 使用
<field-validator>
<?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="id">
<!-- <field-validator type="requiredstring"> <message>你的用户名必须存在</message>
</field-validator> -->
<field-validator type="stringlength">
<param name="minLength">6</param>
<param name="maxLength">12</param>
<message>你的用户名长度必须在4到20之间</message>
</field-validator>
</field>
<!-- 方法二 -->
<validator type="requiredstring">
<param name="fieldName">id</param>
<param name="fieldName">pwd</param>
<message>用户名密码必须存在</message>
</validator>
</validators>
<validator>
配置一个校验规则,适用于多个属性,type是校验规则,参数fieldName是属性名,message是fieldError的值
<field name="属性名">
下可以配置多个<field-validator>
,即一个属性可以配置多个校验规则
我们一般将通用的校验规则使用<validator>
配置,其他的用<field-validator>
配置
校验文件使用实例如下
我们用的还是上面的哪个例子,只是将validate方法和validateXxx方法注释掉
ValidateAction-validate-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="id">
<!-- <field-validator type="requiredstring"> <message>你的用户名必须存在</message>
</field-validator> -->
<field-validator type="stringlength">
<param name="minLength">6</param>
<param name="maxLength">12</param>
<message>你的用户名长度必须在4到20之间</message>
</field-validator>
</field>
<field name="repwd">
<field-validator type="requiredstring">
<message>确认密码必须存在</message>
</field-validator>
<field-validator type="fieldexpression">
<param name="expression"><![CDATA[pwd==repwd]]></param>
<message>密码不一致,请重新输入</message>
</field-validator>
</field>
<!-- <field name="pwd"> <field-validator type="requiredstring"> <message>你的密码必须存在</message>
</field-validator> </field> -->
<!-- 方法二 -->
<validator type="requiredstring">
<param name="fieldName">id</param>
<param name="fieldName">pwd</param>
<message>用户名密码必须存在</message>
</validator>
<!-- <validator type="fieldexpression"> <param name="fieldName">pwd</param>
<param name="expression"><![CDATA[(pwd==repwd)]]></param> <message>两个密码必须相同</message>
</validator> -->
</validators>
注意:
1、在使用时maxLength和minLength的L是大写的,小写会不起作用
2、校验文件的头部版本需要和你的xwork中的xwork-validator-1.0.3.dtd中的头部保持一致,不然由于版本问题可能不起作用
3、required和requiredstring的不同,require只要求有该属性不为空就可以了,但是表单不填的话会是空字符串,不是空,而requiredstring要求field的值不能为null,并且长度大于0,默认情况下会对字符串去掉前后空格,这就保证了表单必填的要求
效果如下:
常见的各种类型校验器配置
1、类型转换检验器:
(1)非字段校验:
<validator type="conversion">
<param name="fieldName">myField</param>
<message>类型转换错误</message>
<param name ="repopulateField">true</param>
</validator>
(2)字段校验:
<field name="myField">
<field-validator type="conversion">
<message>类型转换错误</message>
<param name ="repopulateField">true</param>
</field-validator>
</field>
fieldName:该参数指定检查是否存在转换异常的字段名称,如果是字段校验,则不用指定该参数。
repopulateField:该参数指定当类型转换失败后,返回input页面时,类型转换失败的表单是否保留原来的错误输入。true为保留,false为不保留。
2、日期校验器:
(1)非字段校验:
<validator type="date">
<param name="fieldName">birthday</param>
<param name="min">1990-01-02</param>
<param name="max">2010-07-28</param>
<message>生日数据错误</message>
</validator>
(2)字段校验:
<field name="birthday">
<field-validator type="date">
<param name="min">1990-01-01</param>
<param name="max">2010-07-28</param>
<message key="error.birthday"></message>
</field-validator>
</field>
min:指定字段日期值的最小值,该参数为可选参数。
max:指定字段日期值的最大值,该参数为可选参数。
3、浮点数值校验器:
(1)非字段校验:
<validator type="double">
<param name="fieldName">percentage</param>
<param name="minInclusive">20.1</param>
<param name="maxInclusive">50.1</param>
<message>生日数据错误</message>
</validator>
(2)字段校验:
<field name="percentage">
<field-validator type="double">
<param name="minInclusive">20.1</param>
<param name="maxInclusive">50.1</param>
<message key="error.percentage"></message>
</field-validator>
</field>
minInclusive|minExclusive:指定字段的最小值,包含该值|不包含该值。
maxInclusive|maxExclusive:指定字段的最大值, 包含该值|不包含该值。
4、邮件地址校验器:
(1)非字段校验:
<validator type="email">
<param name="fieldName">MyEmail</param>
<message>非法的邮件地址</message>
</validator>
(2)字段校验:
<field name="MyEmail">
<field-validator type="email">
<message>非法的邮件地址</message>
</field-validator>
</field>
5、表达式校验器:
<validator type="expression">
<param name="expression">.......</param>
<message>Failed to meet Ognl Expression...</message>
</validator>
expression:该参数为一个逻辑表达式,该参数使用OGNL表达式,并基于值栈计算,返回一个Boolean类型值。
6、字段表达式校验器:
(1)非字段校验:
<validator type="fieldexpression">
<param name="fieldName">myField</param>
<param name="expression"><![CDATA[#myCreditLimit > #myGirfriendCreditLimit]]></param>
<message>My credit limit should be MORE than my girlfriend</message>
</validator>
(2)字段校验:
<field name="myField">
<field-validator type="fieldexpression">
<param name="expression"><![CDATA[#myCreditLimit > #myGirfriendCreditLimit]]></param>
<message>My credit limit should be MORE than my girlfriend</message>
</field-validator>
</field>
7、整数校验器:
(1)非字段校验:
<validator type="int">
<param name="fieldName">age</param>
<param name="min">10</param>
<param name="max">100</param>
<message>年龄必须在在${min}到${max}之间</message>
</validator>
(2)字段校验:
<field name="age">
<field-validator type="int">
<param name="min">10</param>
<param name="max">100</param>
<message>年龄必须在在${min}到${max}之间</message>
</field-validator>
</field>
8、正则表达式校验器:
(1)非字段校验:
<validator type="regex">
<param name="fieldName">myStrangePostcode</param>
<param name="expression"><![CDATA[([aAbBcCdD][123][eEfFgG][456])]></param>
</validator>
(2)字段校验:
<field name="myStrangePostcode">
<field-validator type="regex">
<param name="expression"><![CDATA[#myCreditLimit > #myGirfriendCreditLimit]]></param>
<message>My credit limit should be MORE than my girlfriend</message>
</field-validator>
</field>
expression:为必选参数,指定匹配有的表达式。
caseSensitive:指明进行匹配时,是否区分大小写,为可选参数,默认为true。
9、必填校验器:
(1)非字段校验:
<validator type="required">
<param name="fieldName">username</param>
<message>用户名不能为空</message>
</validator>
(2)字段校验:
<field name="username">
<field-validator type="required">
<message>用户名不能为空</message>
</field-validator>
</field>
10、必填字符串校验器:
(1)非字段校验:
<validator type="requiredstring">
<param name="fieldName">username</param>
<param name="trim">true</param>
<message>用户名不能为空</message>
</validator>
(2)字段校验:
<field name="username">
<field-validator type="requiredstring">
<param name="trim">true</param>
<message>用户名不能为空</message>
</field-validator>
</field>
trim:可选参数,用于指定是否在校验之前对字符串进行整理,默许为true。
11、字符串长度校验器:
(1)非字段校验:
<validator type="stringlength">
<param name="fieldName">username</param>
<param name="minLength">4</param>
<param name="maxLength">10</param>
<message>用户名长度在${minLength}到${maxLength}之间</message>
</validator>
(2)字段校验:
<field name="username">
<field-validator type="stringlength">
<param name="minLength">4</param>
<param name="maxLength">10</param>
<param name="trim">true</param>
<message key="error.length.username"></message>
</field-validator>
</field>
12、网址校验器:
(1)非字段校验:
<validator type="url">
<param name="fieldName">myHomePage</param>
<message>Invalid homepage url</message>
</validator>
(2)字段校验:
<field name="myHomePage">
<field-validator type="url">
<message>Invalid homepage url</message>
</field-validator>
</field>
13、visitor校验器:
该校验器名称为:visitor,用来校验Action中定义的复合类型属性,支持简单的复合类型、数组类型、Map等集合类型。
(1)非字段校验:
<validator type="visitor">
<param name="fieldName">user</param>
<param name="context">myContext</param>
<param name="appendPrefix">true</param>
</validator>
(2)字段校验:
<field name="user">
<field-validator type="visitor">
<param name="context">myContext</param>
<param name="appendPrefix">true</param>
</field-validator>
</field>
参考
JavaWeb框架Struts2(六)—–>Struts2的输入校验
细谈struts2(五)action基础知识和数据校验
Struts2内建校验器(基于校验框架的文件校验)