当前位置: 首页 > 编程日记 > 正文

9、 Struts2验证(声明式验证、自定义验证器)

1. 什么是Struts2 验证器

  • 一个健壮的 web 应用程序必须确保用户输入是合法、有效的.
  • Struts2 的输入验证
    • 基于 XWork Validation Framework 的声明式验证:Struts2 提供了一些基于 XWork Validation Framework 的内建验证程序. 使用这些验证程序不需要编程, 只要在一个 XML 文件里对验证程序应该如何工作作出声明就可以了. 需要声明的内容包括:
      • 哪些字段需要进行验证
      • 使用什么验证规则
      • 在验证失败时应该把什么样的出错消息发送到浏览器端
    • 编程验证:通过编写代码来验证用户输入

2、声明式验证

  • 声明式验证程序可以分为两类:
    • 字段验证: 判断某个字段属性的输入是否有效
    • 非字段验证: 不只针对某个字段,而是针对多个字段的输入值之间的逻辑关系进行校验。例如:对再次输入密码的判断。
  • 使用一个声明式验证程序需要 3 个步骤:
    • 确定哪些 Action 字段需要验证
    • 编写一个验证程序配置文件. 它的文件名必须是以下两种格式之一:
      • 若一个 Action 类的多个 action 使用同样的验证规则: ActionClassName-validation.xml
      • 若一个 Action 类的多个 action 使用 不同 的验证规则: ActionClass-alias-validation.xml
        • 例如 UserAction-User_create-validation.xml User_create为action 请求的名称
        • 不带别名的配置文件: ActionClassName-validation.xml 中的验证规则依然会发生作用. 可以把各个 action 公有的验证规则配置在其中. 但需要注意的是, 只适用于某一个 action 的请求的验证规则就不要这里再配置了.
    • 确定验证失败时的响应页面: 在 struts.xml 文件中定义一个 <result name=“input”> 的元素.
      • 示例代码 HelloWord
        • I. 先明确对哪一个 Action 的哪一个字段进行验证: age
        • II. 编写配置文件:
          • 把 struts-2.3.24.1\apps\struts2-blank\WEB-INF\classes\example 下的 Login-validation.xml 文件复制到当前 Action 所在的包下.
          • 把该配置文件改为: 把 Login 改为当前 Action 的名字.
          • afac410dgw1fae0pcl6zwj209002emxc.jpg
          • 编写验证规则: 参见 struts-2.3.24.1/docs/docs/validation.html 文档即可.
          • 在配置文件中可以定义错误消息:
 <!-- 针对 age 属性进行验证. 基于字段的验证 -->
<field name="age"><field-validator type="int"><param name="min">20</param><param name="max">60</param><message>年龄范围在${min}-${max}中!</message></field-validator>
</field>

  • 错误消息还可以国际化
    • <message key="error.int"/>
    • 再在国际化文件中加入键值对:error.int=年龄范围在${min}-${max}中!
  • 若验证失败, 则转向 input 的那个 result. 所以需要配置 name=input 的 result
    <result name="input">/validation.jsp</result>

  • 如何显示错误消息呢 ?
    • 若使用的是非 simple, 则自动显示错误消息.
    • 若使用的是 simple 主题, 则需要 s:fielderror 标签或直接使用 EL 表达式(使用 OGNL)
      ${fieldErrors.age[0] } OR <s:fielderror fieldName="age"></s:fielderror>

  • 如果对于同一个Action类下,想对不同的 action 请求应答,多个 action 请求使用不同的验证规则,怎么办呢?
    • 可以为每一个不同的 action 清秀定义其对应的验证文件: ActionClassName-AliaseName-validation.xml (AliaseName 为action 请求的别名)

  • Struts2 内建的验证规则
    * conversion validator:转换验证器* date validator:日期验证器* double validator:浮点验证器* email validator:email 验证器* expression validator:表达式验证器* fieldexpression validator:字段表达式验证器* int validator:整型验证器* regex validator:正则表达式验证器* required validator:非空验证器* requiredstring validator:非空字符串验证器* stringlength validator:字符串长度验证器* url validator:url 格式验证器* visitor validator:复合属性验证器

  • Struts2 声明式验证原理解析
    • Struts2 的 Validation 拦截器负责加载和执行已注册的验证程序,它是 defaultStack 拦截器的一员
    • afac410dgw1fae0yfjc9xj20nt0d1gnu.jpg
    • 每个验证规则都对应一个具体的验证器,在 xwork-core-2.3.16.3.jar!/com/opensymphony/xwork2/validator/validators/default.xml 有对应的关联关系
    • afac410dgw1fae0z4bi27j20x10av13j.jpg
  • 配置文件与验证器属性
    • afac410dgw1fae1bno3v6j20x20dtn1i.jpg
  • Struts2 内建的验证程序
    • required: 确保某给定字段的值不是空值 null “”
    • requiredstring: 确保某给定字段的值既不是空值 null, 也不是空白.
      • trim 参数. 默认为 true, 表示 struts 在验证该字段值之前先剔除前后空格.
    • stringlength: 验证一个非空的字段值是不是有足够的长度.
      • minLength: 相关字段的最小长度. 若没有给出这个参数, 该字段将没有最小长度限制
      • maxLength:相关字段的最大长度. 若没有给出这个参数, 该字段将没有最大长度限制
      • trim: 在验证之前是否去除前后空格
    • date: 确保某给定日期字段的值落在一个给定的范围内
      • max:相关字段的最大值. 若没给出这个参数, 该字段将没有最大值限制
      • min:相关字段的最小值. 若没给出这个参数, 该字段将没有最小值限制
    • email: 检查给定 String 值是否是一个合法的 email
    • url: 检查给定 String 值是否是一个合法的 url
    • regex: 检查某给定字段的值是否与一个给定的正则表达式模式相匹配.
      • expresssion*: 用来匹配的正则表达式
      • caseSensitive: 是否区分字母的大小写. 默认为 true
      • trim: 是否去除前后空格. 默认为 true
    • int: 检查给定整数字段值是否在某一个范围内
      • min: 相关字段的最小值. 若没给出这个参数, 该字段将没有最小值限制
      • max: 相关字段的最大值. 若没给出这个参数, 该字段将没有最大值限制
    • conversion: 检查对给定 Action 属性进行的类型转换是否会导致一个转换错误. 该验证程序还可以在默认的类型转换消息的基础上添加一条自定义的消息
    • expression 和 fieldexpression: 用来验证给定字段是否满足一个 OGNL 表达式.
      • 前者是一个非字段验证程序, 后者是一个字段验证程序.
      • 前者在验证失败时将生成一个 action 错误, 而后者在验证失败时会生成一个字段错误
      • expression*: 用来进行验证的 OGNL 表达式

  • 使用Annotations验证
    • 实际上,我们查看 struts2 官方文档发现,官方文档更加推荐我们使用注解的方式进行验证
      • 注解方式验证

  • 短路验证器
    • <validator …/> 元素和 <field-validator …/> 元素可以指定一个可选的 short-circuit 属性,该属性指定该验证器是否是短验证器,默认值为 false。
      对同一个字段内的多个验证器,如果一个短路验证器验证失败,其他验证器不会继续校验
<field-validator type="int" short-circuit="true">
<validator type="email" short-circuit="true">
<!-- 针对 age 属性进行验证. 基于字段的验证 -->
<field name="age"><!-- 设置短路验证,当前验证未通过,不进行后面的验证 --><field-validator type="conversion" short-circuit="true"><message>当前年龄无法读取!</message></field-validator><field-validator type="int"><param name="min">20</param><param name="max">60</param><message key="error.int" /></field-validator>
</field>
  • 若类型转换失败, 默认情况下还会执行后面的拦截器, 还会进行 验证. 可以通过修改 ConversionErrorInterceptor 源代码的方式使
    • 当类型转换失败时, 不再执行后续的验证拦截器, 而直接返回 input 的 result
Object action = invocation.getAction();
if (action instanceof ValidationAware) {ValidationAware va = (ValidationAware) action;if(va.hasErrors() || va.hasActionErrors()){return "input";}
}

  • 非字段验证
<!-- 非字段验证 -->
<validator type="expression"><param name="expression"><![CDATA[password==repassword]]></param><message>Password is not equals to repassword</message>
</validator>
  • 显示非字段验证的错误消息, 使用 s:actionerror 标签: <s:actionerror/>

  • 字段验证 vs 非字段验证
    • 字段验证字段优先,可以为一个字段配置多个验证规则
    • 非字段验证验证规则优先
    • 大部分验证规则支持两种验证器,但个别的验证规则只能使用非字段验证,例如 表达式验证

  • 错误消息的重用性
    • 多个字段使用同样的验证规则,可否使用同一条验证消息 ?
<!-- 针对 age 属性进行验证. 基于字段的验证 -->
<field name="age"><!-- 设置短路验证,当前验证未通过,不进行后面的验证 --><field-validator type="conversion" short-circuit="true"><message>当前年龄无法读取!</message></field-validator><field-validator type="int"><param name="min">20</param><param name="max">60</param><message key="error.int" /></field-validator>
</field>
<field name="count"><field-validator type="int"><param name="min">1</param><param name="max">10</param><message key="error.int"></message></field-validator>
</field>
# i18n
age=年龄
count=数量
#fieldName为检验时传递过来的filed,对应age=年龄 count=数量
error.int=${getText(fieldName)}范围在${min}-${max}中!
  • afac410dgw1fae24bit8sj20ti0eh790.jpg

  • 自定义验证器
    • 自定义验证器必须实现 Validator 接口.
    • ValidatorSupport 和 FieldValidatorSupport 实现了 Validator 接口
      • afac410dgw1fae27svlj3j20ln02x3z7.jpg
      • 若需要普通的验证程序, 可以继承 ValidatorSupport 类
      • 若需要字段验证程序, 可以继承 FieldValidatorSupport 类
      • 若验证程序需要接受一个输入参数, 需要为这个参数增加一个相应的属性
    • 注册验证程序:
      • 自定义验证器需要在类路径里的某个 validators.xml 文件里注册:
      • 验证框架首先在根目录下找validators.xml文件,没找到validators.xml文件,
      • 验证框架将调用默认的验证设置,即default.xml里面的配置信息.
  • 示例代码:
    • 自定义一个 18 位身份证验证器
    • 编写验证器类
public class IDCardValidation extends FieldValidatorSupport {@Overridepublic void validate(Object object) throws ValidationException {//1、获取字段名称String fieldName = getFieldName();//2、获取值Object value = this.getFieldValue(fieldName, object);//3、验证IDCard idCard = new IDCard();boolean result =  idCard.Verify(value.toString());//4、验证失败加入错误消息if (!result) {addFieldError(fieldName, object);}}
}
  • 在 validators.xml 文件中进行注册
    • 参考 /com/opensymphony/xwork2/validator/validators/default.xml
<validators><validator name="idCard"class="org.pan.validation.app.MyValidation.IDCardValidation"></validator>
</validators>
  • 在验证配置文件中使用
 <!-- 测试自定验证器 -->
<field name="idCard"><field-validator type="idCard"><message>This is Not IDCard</message></field-validator>
</field>

  • 编程验证
    • Struts2 提供了一个 Validateable 接口, 可以使 Action 类实现这个接口以提供编程验证功能.
    • ActionSupport 类已经实现了 Validateable 接口
    • afac410dgw1fae2hb1evgj20if04ft94.jpg

转载于:https://www.cnblogs.com/MPPC/p/6130112.html

相关文章:

java中使用队列:java.util.Queue

在java5中新添加了java.util.Queue接口&#xff0c;用以支持队列的常见操作。该接口扩展了java.util.Collection接口。Queue使用时要尽量避免Collection的add()和remove()方法&#xff0c;而是要使用offer()来添加元素&#xff0c;使用poll()来获取并移出元素。它们的优点是通过…

xCode BuildSetting 设置

一 编译选项设置 1 Optimization Level 编译器的优化级别 编译策略是对代码编译过程的优化,优化后的代码效率比较高&#xff0c;但是可读性比较差&#xff0c;且编译时间更长。 release模式设置为Fastest, Smallest[-Os] Debug模式设置为None 设置参数None编译器不会尝试优…

react绑定this_React绑定模式:处理“ this”的5种方法

react绑定thisJavaScript’s this keyword behavior has confused developers for ages.JavaScript的this关键字行为使开发人员困惑了很长时间。 There are at least five ways to handle the this context in React. Let’s consider the merits of each approach.在React中至…

php 文件限速下载代码

<?php include("DBDA.class.php"); $db new DBDA(); $bs $_SERVER["QUERY_STRING"]; //获取由提交界面传过来的参数 $bss substr($bs,3); //截取 后面的值$sql "select video from shangpin where id{$bss}"; //获取视频文件路径 $s…

【Java】Linux下安装配置Oracle JDK 1.7版本

1 环境 Vmware虚拟机中的Ubuntu 12.04 32位系统 2具体安装步骤 ①下载最新的jdk包 注意jdk区分32位版本和64位版本&#xff0c;要与Ubuntu兼容才行 下载地址 http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html ②创建一个目录&#xff0c;…

Swift 换肤方案的实现使用SwiftTheme框架

SwiftTheme 框架进行换肤 本地创建多个plist文件 设置不同图片颜色数组 飞机票 demo Foundationimport SwiftTheme// 创建一个枚举类型进行换肤 enum ChangeTheme:Int {case theme1 0;case theme2 1;case theme3 2;// 创建一个静态方法去换肤 去加载本地的plist文件stati…

linux生日_代码简介:让我们用25个Linux事实来庆祝Linux的25岁生日。

linux生日Here are three stories we published this week that are worth your time:这是我们本周发布的三个值得您关注的故事&#xff1a; Linux is 25. Yay! Let’s celebrate with 25 stunning facts about Linux: 6 minute read Linux是25。是的&#xff01; 让我们用有关…

网页中;window.onerror=function(){return!0};

在浏览网页的时候发现一段&#xff1a;window.οnerrοrfunction(){return!0}; 于是就顺手点了搜索&#xff0c;发现是被 adsafe关闭了 。 把adsafe退出就能显示了。 转载于:https://www.cnblogs.com/Tiramisu001/p/6136931.html

xib 拖关联控件的时候报Could not insert new outlet connection错误

~/Library/Developer/XCode/DerivedData 目录中删除对应的项目文件 重新打开工程即可

hdu 4901

计数dp 做不出来真是惭愧。。。 #include <cstdio> #include <cstdlib> #include <cmath> #include <stack> #include <vector> #include <sstream> #include <cstring> #include <string> #include <map> #include <…

初创企业股权架构_初创企业如何以每月不到200美元的价格利用生产级基础架构...

初创企业股权架构Before you can launch a new service, you need infrastructure. You want reliability, scalability, and many other -ilities. But you don’t want to break the bank.在启动新服务之前&#xff0c;您需要基础架构。 您需要可靠性&#xff0c;可伸缩性和许…

git review devops过程

自己搭建的devops环境是gitlab/gerrit/jenkins 1. 首先自己checkout一个自己的代码分支&#xff0c;一般不要在master上做直接修改 2. 修改后git add file, git commit 3. git review 4. jenkins自动部署测试 5. 人工review代码&#xff0c;如果可以就提交并merge&#xff0c;…

swift判断iPhone 各种型号

// iPhoneXR let iPhoneXR:Bool __CGSizeEqualToSize(CGSize(width: 828, height: 1792), UIScreen.main.currentMode?.size ?? CGSize(width: 0, height: 0)); // iPhoneX let iPhoneX:Bool __CGSizeEqualToSize(CGSize(width: 1125, height: 2436), UIScreen.main.curr…

轻有力读后感ppt_如果您希望招聘人员认真对待您,请建立强有力的个人叙述。...

轻有力读后感pptby Garreth Dottin通过Garreth Dottin 如果您希望招聘人员认真对待您&#xff0c;请建立强有力的个人叙述。 (If you want recruiters to take you seriously, build a strong personal narrative.) We’ve all been there. Hunched over a desk. Scrolling th…

每天一个linux命令(10):cat 命令

cat命令的用途是连接文件或标准输入并打印。这个命令常用来显示文件内容&#xff0c;或者将几个文件连接起来显示&#xff0c;或者从标准输入读取内容并显示&#xff0c;它常与重定向符号配合使用。 1&#xff0e;命令格式&#xff1a; cat [选项] [文件]... 2&#xff0e;命令…

Swift 中使用Alamofire 免证书的设置

let manager SessionManager.defaultmanager.delegate.sessionDidReceiveChallenge {session,challenge inreturn (URLSession.AuthChallengeDisposition.useCredential,URLCredential(trust:challenge.protectionSpace.serverTrust!))}

“System.Data.OracleClient.OracleConnection”已过时

处理办法&#xff1a; 在oracle 安装目录下 找到 Oracle.DataAccess.dll添加引用&#xff0c;然后 using Oracle.DataAccess.Client;其他的都不用动&#xff0c;即可。连接字符串中 如有 用的是 userxxx 就改成user idxxx把原来 Using 的System.Data.OracleClient去掉即可。 --…

我开发的代码,如何申请版权_代码简介:我花了3个月时间申请开发人员职位。 这是我学到的。...

我开发的代码,如何申请版权Here are three stories we published this week that are worth your time:这是我们本周发布的三个值得您关注的故事&#xff1a; I spent 3 months applying to jobs after a coding bootcamp. Here’s what I learned: 5 minute read 编码训练营结…

Chapter 2 Open Book——29

Which left me with nothing to do but try to not look at him…unsuccessfully. 我没什么事情可以做但是我尝试不去看他&#xff0c;但是失败了。 I glanced up, and he was staring at me, that same inexplicable look of frustration in his eyes. 我瞥了一眼&#xff0c;…

js回调与异步加载的用法

以前还是菜鸟的时候&#xff08;虽然现在依然很菜 -_-|| &#xff09;对异步加载与回调函数的技术无比向往&#xff0c;但也一直没有使用过&#xff0c;这次因为页面逻辑太过复杂&#xff0c;一堆请求逻辑&#xff0c;如果还是用顺序请求&#xff0c;页面的速度。。。 领导又要…

Swift 字符串去除换行符空格符

capitalizedLetters&#xff1a;大写controlCharacters&#xff1a;控制符 whitespacesAndNewlines&#xff1a;空格换行 decimalDigits&#xff1a;小数 letters&#xff1a;文字 lowercaseLetters&#xff1a;小写字母 uppercaseLetters&#xff1a;大写字母 nonBaseCharacte…

谈论源码_6,000名自由职业者谈论金​​钱,幸福和对未来的希望

谈论源码More than 6,000 US-based freelancers responded to a new in-depth survey. I dug through the data and pulled out the most interesting insights, which paint a picture of optimistic professionals who have taken control of their own destiny.超过6,000名美…

第一篇随笔——新的开端

新的开端 这是我第一次开通博客也是第一次在博客上写随笔&#xff0c;这既是博客的新开端也是JAVA学习的新开端&#xff0c;希望能好好经营这第一个博客~。 觉得自己专业吗&#xff1f;对专业的期望 对于这个问题我不得不坦然承认虽然进入信安专业已经有一年的时间了&#xff0…

快速入门linux系统的iptables防火墙 1 本机与外界的基本通信管理

概述 iptables是一种运行在linux下的防火墙组件&#xff0c;下面的介绍可以快速的学习iptables的入门使用。 特点&#xff08;重要&#xff09; 它的工作逻辑分为 链、表、规则三层结构。数据包通过的时候&#xff0c;在对应表中&#xff0c;规则从上向下匹配&#xff0c;匹配到…

iOS 根据数组中的字典的value值进行排序

NSMutableArray *resArr [NSMutableArray array];// 先把所有值的装进一个数组中NSMutableArray *valArr [NSMutableArray array];for (int i 0; i < arr.count; i ) {NSDictionary *dic arr[i];NSString * str [NSString stringWithFormat:"%-%d",dic["…

矢量数编码有哪几种类型_6种最理想的编码工作(以及吸引每个人的类型)

矢量数编码有哪几种类型by David Venturi大卫文图里(David Venturi) 6种最理想的编码工作(以及吸引每个人的类型) (The 6 most desirable coding jobs (and the types of people drawn to each)) Free Code Camp问了15,000个人&#xff0c;他们是谁&#xff0c;以及他们如何学…

sleep和wait到底什么区别

wait是在当前线程持有wait对象锁的情况下&#xff0c;暂时放弃锁&#xff0c;并让出CPU资源&#xff0c;并积极等待其它线程调用同一对象的notify或者notifyAll方法。注意&#xff0c;即使只有一个线程在等待&#xff0c;并且有其它线程调用了notify或者notifyAll方法&#xff…

Swift Code Snippet

1 swi_crecell func numberOfSections(in tableView: UITableView) -> Int {return 1;}func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {return 5;}// cell高度func tableView(_ tableView: UITableView, heightForRowAt indexPa…

Cocos2d-x lua 编译到Android设备

需要完成Android下ant,ndk,sdk(adt)的环境配置.Java环境配置. 也可以搭建VS下的Lua开发环境. 首先新建项目 cocos new -l lua -d (...address) 然后编译 cocos run -p win32 -s (...address) --ap 19 后面的--ap 19是版本控制. 然后在Eclipse中Import项目,右键项目Build Path添…

c# 数据可视化_#OpenVisConf上的22位数据可视化从业者的10点收获

c# 数据可视化by Siena Duplan通过锡耶纳杜普兰(Siena Duplan) #OpenVisConf上的22位数据可视化从业者的10点收获 (10 Takeaways from 22 Data Visualization Practitioners at #OpenVisConf) Update | May 13, 2016: Videos of all talks are officially live!更新| 2016年5月…