Struts 2 数据校验要用到的类和两种校验方式以及一些校验问题的解决
通过继承ActionSupport类来完成Action开发,ActionSupport类不仅对Action接口进行简单实现, 同时增加了验证、本地化等支持 。真实开发中自定义Action都需要继承该类。对用户登录添加表单验证功能
ActionSupport类的作用:
struts2不要求我们自己设计的action类继承任何的struts基类或struts接口,但是我们为了方便实现我们自己的action,大多数情况下都会继承com.opensymphony.xwork2.ActionSupport类,并重写此类里的public String execute() throws Exception方法。因为此类中实现了很多的实用借口,提供了很多默认方法,这些默认方法包括国际化信息的方法、默认的处理用户请求的方法等,这样可以大大的简化Acion的开发。 Struts2中通常直接使用Action来封装HTTP请求参数,因此,Action类里还应该包含与请求参数对应的属性,并且为属性提供对应的getter和setter方法。
那么Action 接口和 ActionSupport类的区别是什么呢?
Action接口有:
public static final String SUCCESS = "success";
public static final String NONE = "none";
public static final String ERROR = "error";
public static final String LOGIN = "login";
public String execute() throws Exception;
可以看到有五个静态常量和返回类型为String 的execute()
而Actionsupport这个工具类在实现了Action接口的基础上还定义了一个validate()方法,重写该方法,它会在execute()方法之前执行,如校验失败,会转入input处,必须在配置该Action时配置input属性。
另外,Actionsupport还提供了一个getText(String key)方法还实现国际化,该方法从资源文件上获取国际化信息.
这样在自定义标签时可以定义一个变量为new actionsupport对象实现国际化。
Actionsupport类有(源码):
public class ActionSupport implements Action, Validateable, ValidationAware, TextProvider, LocaleProvider, Serializable {
protected static Logger LOG = LoggerFactory.getLogger(ActionSupport.class);
private final ValidationAwareSupport validationAware = new ValidationAwareSupport();
private transient TextProvider textProvider;
private Container container;
public void setActionErrors(Collection<String> errorMessages) {
validationAware.setActionErrors(errorMessages);
}
public Collection<String> getActionErrors() {
return validationAware.getActionErrors();
}
public void setActionMessages(Collection<String> messages) {
validationAware.setActionMessages(messages);
}
public Collection<String> getActionMessages() {
return validationAware.getActionMessages();
}
@Deprecated
public Collection<String> getErrorMessages() {
return getActionErrors();
}
@Deprecated
public Map<String, List<String>> getErrors() {
return getFieldErrors();
}
public void setFieldErrors(Map<String, List<String>> errorMap) {
validationAware.setFieldErrors(errorMap);
}
public Map<String, List<String>> getFieldErrors() {
return validationAware.getFieldErrors();
}
public Locale getLocale() {
ActionContext ctx = ActionContext.getContext();
if (ctx != null) {
return ctx.getLocale();
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("Action context not initialized");
}
return null;
}
}
public boolean hasKey(String key) {
return getTextProvider().hasKey(key);
}
public String getText(String aTextName) {
return getTextProvider().getText(aTextName);
}
public String getText(String aTextName, String defaultValue) {
return getTextProvider().getText(aTextName, defaultValue);
}
public String getText(String aTextName, String defaultValue, String obj) {
return getTextProvider().getText(aTextName, defaultValue, obj);
}
public String getText(String aTextName, List<?> args) {
return getTextProvider().getText(aTextName, args);
}
public String getText(String key, String[] args) {
return getTextProvider().getText(key, args);
}
public String getText(String aTextName, String defaultValue, List<?> args) {
return getTextProvider().getText(aTextName, defaultValue, args);
}
public String getText(String key, String defaultValue, String[] args) {
return getTextProvider().getText(key, defaultValue, args);
}
public String getText(String key, String defaultValue, List<?> args, ValueStack stack) {
return getTextProvider().getText(key, defaultValue, args, stack);
}
public String getText(String key, String defaultValue, String[] args, ValueStack stack) {
return getTextProvider().getText(key, defaultValue, args, stack);
}
public String getFormatted(String key, String expr) {
Map<String, Object> conversionErrors = ActionContext.getContext().getConversionErrors();
if (conversionErrors.containsKey(expr)) {
String[] vals = (String[]) conversionErrors.get(expr);
];
} else {
final ValueStack valueStack = ActionContext.getContext().getValueStack();
final Object val = valueStack.findValue(expr);
return getText(key, Arrays.asList(val));
}
}
public ResourceBundle getTexts() {
return getTextProvider().getTexts();
}
public ResourceBundle getTexts(String aBundleName) {
return getTextProvider().getTexts(aBundleName);
}
public void addActionError(String anErrorMessage) {
validationAware.addActionError(anErrorMessage);
}
public void addActionMessage(String aMessage) {
validationAware.addActionMessage(aMessage);
}
public void addFieldError(String fieldName, String errorMessage) {
validationAware.addFieldError(fieldName, errorMessage);
}
public String input() throws Exception {
return INPUT;
}
public String doDefault() throws Exception {
return SUCCESS;
}
public String execute() throws Exception {
return SUCCESS;
}
public boolean hasActionErrors() {
return validationAware.hasActionErrors();
}
public boolean hasActionMessages() {
return validationAware.hasActionMessages();
}
public boolean hasErrors() {
return validationAware.hasErrors();
}
public boolean hasFieldErrors() {
return validationAware.hasFieldErrors();
}
public void clearFieldErrors() {
validationAware.clearFieldErrors();
}
public void clearActionErrors() {
validationAware.clearActionErrors();
}
public void clearMessages() {
validationAware.clearMessages();
}
public void clearErrors() {
validationAware.clearErrors();
}
public void clearErrorsAndMessages() {
validationAware.clearErrorsAndMessages();
}
public void validate() {
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public void pause(String result) {
}
private TextProvider getTextProvider() {
if (textProvider == null) {
TextProviderFactory tpf = new TextProviderFactory();
if (container != null) {
container.inject(tpf);
}
textProvider = tpf.createInstance(getClass(), this);
}
return textProvider;
}
@Inject
public void setContainer(Container container) {
this.container = container;
}
可以看到里面有很多的方法,但我们很明显看到有一个我们很了解的,validate(),数据校验的方法。通过这个方法,我们可以登录时,用户名和密码为空的提示,或其他··
现在举一个简单的例子:当用户名和密码为空,给客户一个友好提示。
下面通过两种方式来阐述Struts 2的数据校验功能。
1. 编码方式校验
1) Action一定要继承自ActionSupport
2) 针对某个要进行校验的请求处理方法编写一个 public void validateXxx()方法,在方法内部进行表单数据校验.
3) 也可针对所有的请求处理方法编写public void validate()方法。
4) 在校验方法中,可以通过addFieldError()方法来添加字段校验错误消息。
5) 当校验失败时,Struts框架会自动跳转到name为input的Result页面。在校验失败页面中,可以使用<s:fielderror/>来显示错误消息
6) 简单,灵活。但重用性不高
重写validate方法
1.我们编写的Action一般继承与ActionSupport,而ActionSupport不仅实现了Action接口,还实现了Validatable接口,提供了数据校验功能。在Validatable接口中定义一个validate方法,重写该方法,如果校验表单输入域出现错误,则将错误添加到ActionSupport类的fieldError域中,然后通过OGNL表达式输出。
下面是用户登录校验界面:
<body> <%--输出校验信息--%> <%--想要单个提示 <s:fielderror fieldName="uname"/>--%> <%--<s:property value=""/> --%><div style="color:red"><s:fielderror/></div> <s:form name="form1" namespace="/" method="post" action="LoginValidateAction"> <s:div>请输入用户名:<s:textfield name="user.uname" ></s:textfield></s:div> <s:div>请输入密码:<s:password name="user.upwd" ></s:password></s:div> <s:submit value="登录"></s:submit> </s:form> <%--debug --%> <s:debug></s:debug> </body>
用户输入数据后,提交到LoginValidateAction 中:
public class LoginValidateAction extends ActionSupport implements Action {
public User user;
public Map<String, Object> map;
//验证的方法,会对所有的Action起作用
@Override
public void validate() {
if(user.getUname().length()==0){
addFieldError("uname", "用户名不能为空!");
}
if(user.getUpwd().length()==0){
addFieldError("upwd", "密码不能为空!");
}
}
//处理业务的方法
public String execute() throws Exception {
System.out.println(user.getUname());
if(user.getUname().equals("admin")&&user.getUpwd().equals("admin")){
//让Struts2注入 map集合
map.put("uname", user.getUname());
//如果登录成功,返回“ success”
return SUCCESS;
}
else{
//登录失败,返回 error
return INPUT; //此处一定是 input
}
}
/**
* @return the user
*/
public User getUser() {
return user;
}
/**
* @param user the user to set
*/
public void setUser(User user) {
this.user = user;
}
上面的LoginValidateAction类重写了validate方法,该方法会在执行excute方法之前执行,如果执行该方法之后,Action类的filedError中包含了数据校验错误,请求将被转发到input逻辑视图。
struts.xml配置如下:
<!-- 数据校验 -->
<action name="LoginValidateAction" class="cn.struts2.action.LoginValidateAction">
<!-- 结果为“success”时,跳转至success.jsp页面 -->
<result name="success">success.jsp</result>
<!-- 结果为"error"时,跳转至fail.jsp页面 或 还在登录界面 login.jsp-->
<result name="input">LoginValidateAction.jsp</result>
<result name="login">fail.jsp</result>
<result name="error">fail.jsp</result>
</action>
在客户端的效果:

但是大家注意没有呢,当提示错误的时候不太是我们想要的的效果显示。

这个不是我们所想要的,那么我们怎么改呢?其实这主要显示的struts2主题样式导致的,
再来看看:

它自动给我们添加了样式。struts2提供了三种主题,ajax, simple, xhtml,它默认的是xhtml主题,当然你可以写任意个你自己的主题,我们称之为自定义主题。可以通过设置解决以上问题
有两种方法可以解决:
1.简单的方法(也很实用,针对所有struts2标签),在Struts.xml中,加上下一行代码就可以了。
<constant name="struts.ui.theme" value="simple" />
代表所有的页面采用的都是 simple主题了,这时它输出的页面,不回添加任何多余的代码,比如 table tr td 等,我们就可以像其他编辑页面的方式编辑页面的风格。
现在再来看看,错误的提示格式

我们可以通过设置这样一个标签:
<s:property value="errors.uname[0]"/>
把这个标签注释掉:
<div style="color:red"><s:fielderror/></div>
但我们设置成 这样时,会出现这样的效果。

这种效果就有点想我们平常输入错误时的那个提示了,还有其他属性值,这里就不用一一列举了。
使用Struts2的校验框架
XML配置方式校验。
在编码方式之前被执行。
1) 针对要校验的Action类,在同包下编写一个名为:Action类名-validation.xml校验规则文件。
2) 在校验规则文件中添加校验规则:具体的校验器名,参数可参看Struts2的reference或Struts2的API。
a) Field校验:针对Action类中每个非自定义类型的Field进行校验的规则。
<field name="要校验的Field名">
<field-validator type="校验规则器名" short-circuit="是否要短路径校验(默认是false)">
<param name="校验器要使用的参数名">值</param>
<message>校验失败时的提示消息</message>
</field-validator>
<!-- 还可添加其它的校验规则 -->
</field>
b) 非Field校验:针对Action类的某些Field使用OGNL表达进行组合校验。
<validator type="fieldexpression">
<param name="fieldName">pwd</param>
<param name="fieldName">pwd2</param>
<param name="expression"><![CDATA[pwd==pwd2]]></param><!-- OGNL表达式 -->
<message>确认密码和密码输入不一致</message>
</validator>
c) visitor校验:主要是用来校验Action类中的自定义类型Field。(针对使用模型驱动方式时)
i) 在Action类的的校验规则文件中针对自定义类型Field使用visitor校验规则。
<!-- 针对自定义Field使用visitor校验 -->
<field name="user">
<field-validator type="required" short-circuit="true">
<message>用户的信息必填</message><!-- 消息前缀 -->
</field-validator>
<field-validator type="visitor"><!-- 指定为visitor校验规则 -->
<param name="context">userContext</param><!-- 指定本visitor校验的上下文名 -->
<param name="appendPrefix">true</param><!-- 是否要添加校验失败消息的前缀 -->
<message>用户的</message><!-- 消息前缀 -->
</field-validator>
</field>
ii) 针对visitor的Field编写一个校验规则文件.文件名为: visitor字段类型名[-visitor校验的上下文名]-validation.xml. 例如: 本例中的文件名为User-userContext-validation.xml
注意: 此文件要存放到visitor字段类型所在的包下.
iii) 在visitor的Field校验规则文件中针对要校验的Field添加校验规则.
我们还可以不重写validate方法,而通过增加校验配置文件来进行数据校验。这个校验配置文件通过使用Struts2已有的校验器来完成对表单域的校验,下面以requiredstring校验器为例,这个校验器是一个必填校验器,指定某个表单域必须输入。
下面是这个校验配置文件LoginValidateAction-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="uname">
<field-validator type="requiredstring">
<message>用户名不能为空</message>
</field-validator>
</field>
<field name="upwd">
<field-validator type="requiredstring">
<message>密码不能为空</message>
</field-validator>
<field-validator type="stringlength">
<param name=</param>
<param name=</param>
<message>密码长度应该在${minLength}--${maxLength}位之间</message>
</field-validator>
</field>
</validators>
注意:这个校验配置文件必须遵守下面两个规则:
1、该文件命运格式必须是Action类名-validation.xml,例如本例中该文件名为:LoginValidateAction-validation.xml
2、该文件必须与Action类的class文件位于同一路径下,本例中文件位于

LoginValidateAction类的代码还是一样:
public class LoginValidateAction extends ActionSupport implements Action {
public User user;
public Map<String, Object> map;
//验证的方法,会对所有的Action起作用
@Override
public void validate() {
if(user.getUname().length()==0){
addFieldError("uname", "用户名不能为空!");
}
if(user.getUpwd().length()==0){
addFieldError("upwd", "密码不能为空!");
}
}
//处理业务的方法
public String execute() throws Exception {
System.out.println(user.getUname());
if(user.getUname().equals("admin")&&user.getUpwd().equals("admin")){
//让Struts2注入 map集合
map.put("uname", user.getUname());
//如果登录成功,返回“ success”
return SUCCESS;
}
else{
//登录失败,返回 error
return INPUT; //此处一定是 input
}
}
/**
* @return the user
*/
public User getUser() {
return user;
}
/**
* @param user the user to set
*/
public void setUser(User user) {
this.user = user;
}
这样就OK啦
Struts 2 数据校验要用到的类和两种校验方式以及一些校验问题的解决的更多相关文章
- Windows校验文件哈希hash的两种常用方式
大家经常都到哪儿去下载软件和应用程序呢?有没想过下载回来的软件.应用程序或资源是否安全呢?在 Windows 10 和 Office 2016 发布当初,很多没权限的朋友都使用第三方网站去下载安装映像 ...
- SpringMVC提供两种校验机制
本文不讲如何使用SpringMVC提供的两种校验机制,只是简单的说明一下其中的差别而已: 1.创建一个Bean,在Bean的属性中添加校验信息,通过配置LocalValidatorFactoryBea ...
- oracle删除表数据的两种的方式
转自:https://blog.csdn.net/qq_37840993/article/details/82490787 平时写sql中我们都会用到删除语句,而平时删除表数据的时候我们经常会用到两种 ...
- Repeater 控件 当数据源没有数据的时候显示 暂无数据 的两种方式
第一种:现在前台给Repeater控件外面的div加一个runat=”server” 然后在cs后台判断数据源是否为空, 是的话就修改这个前台div的InnerText或者是InnerHtml 即可 ...
- 1.11-1.12 Sqoop导入数据时两种增量方式导入及direct
一.增量数据的导入 1.两种方式 ## query 有一个唯一标识符,通常这个表都有一个字段,类似于插入时间createtime where createtime => 201509240000 ...
- highcharts.js两种数据绑定方式和异步加载数据的使用
一,我们先来看看异步加载数据的写法(这是使用MVC的例子) 1>js写法 <script src="~/Scripts/jquery-2.1.4.min.js"> ...
- mybatis 批量添加数据的两种实现方式
做开发的这几年期间经常遇到类似处理这种形式数据的问题,也遇到很多刚刚入行的新同学,发现他们做处理这块,经验不够,今天特地整理了一下,大家都会遇到的几种情况,代码也都粘贴出来了,拿去不谢,有时间大家还是 ...
- java 读取文件——按照行取出(使用BufferedReader和一次将数据保存到内存两种实现方式)
1.实现目标 读取文件,将文件中的数据一行行的取出. 2.代码实现 1).方式1: 通过BufferedReader的readLine()方法. /** * 功能:Java读取txt文件的内容 步骤: ...
- 日均数据量千万级,MySQL、TiDB两种存储方案的落地对比
http://mp.weixin.qq.com/s?__biz=MzIzNjUxMzk2NQ==&mid=2247484743&idx=1&sn=04337e020d268a9 ...
随机推荐
- 使用JavaScript为一张图片设置备选路径
在做网页开发的时候,有时候希望给图片设置一个备选路径,即,当src属性对应的主路径加载失败的时候,图片可以马上切换到备选路径.这样,即使主路径失效了,显示备用路径也不会影响网页的正常体验. 注意到网页 ...
- Register-SPWorkflowService 404
最近需要做一个SharePoint 2013工作流演示环境. 于是在自己的本子上安装了一个虚拟机. 虚拟机操作系统是Windows Server 2012 R2,计划把AD.SQL Server 20 ...
- ViewController respondsToSelector 错误的解决方法
原因解析:(来自别人博客分析)某个公共类或系统提供的控件,存在delegate方法,当创建此公共控件的容器类已经销毁,而这个控件对应的服务是在其它run loop中进行的,控件销毁或者需要进行状态通知 ...
- 解决:win10_x64 VMware Workstation and Hyper-V are not compatible. Remove the Hyper-V role from the system before running VMware Workstation
bcdedit /set hypervisorlaunchtype off A reboot of of the Windows OS is necessary 必须重启才能生效 To enab ...
- 【完全开源】知乎日报UWP版:增加Live磁贴、Badge、以及Toast通知
目录 说明 实现方法 APP生命期 后台任务 说明 之前网上有人建议增加磁贴(tile).徽章(badge)功能.利用周末的时间,将这两个功能添加上去了.如果将磁贴固定到开始屏幕,磁贴就会循环播放首页 ...
- Web API 入门指南 - 闲话安全
Web API入门指南有些朋友回复问了些安全方面的问题,安全方面可以写的东西实在太多了,这里尽量围绕着Web API的安全性来展开,介绍一些安全的基本概念,常见安全隐患.相关的防御技巧以及Web AP ...
- Repository 仓储,你的归宿究竟在哪?(三)-SELECT 某某某。。。
写在前面 首先,本篇博文主要包含两个主题: 领域服务中使用仓储 SELECT 某某某(有点晕?请看下面.) 上一篇:Repository 仓储,你的归宿究竟在哪?(二)-这样的应用层代码,你能接受吗? ...
- .NET中使用Redis
Redis是一个用的比较广泛的Key/Value的内存数据库,新浪微博.Github.StackOverflow 等大型应用中都用其作为缓存,Redis的官网为http://redis.io/. 最近 ...
- 你可能没注意的CSS单位
扶今追昔 CSS中的单位我们经常用到px.pt.em.百分比,px和pt不用多说 em em是相对单位,参考物是父元素的font-size,具有继承的特点 如果字体大小是16px(浏览器的默认值),那 ...
- 数据库中树形列表(以easyui的tree为例)
构造一棵easyui前台框架的一个树形列表为例后台框架是spring MVC+JPA. 先看一下数据库是怎么建的,怎么存放的数据 下面是实体类 /** * 部门类 用户所属部门(这里的部门是一个相对抽 ...