Struts2 类型转换和数据校验

学习内容

 Struts 2类型转换

 Struts 2数据校验

能力目标

 熟悉Struts 2自带类型转换器

 能自定义类型转换器

 自定义输入校验功能

 熟悉Struts 2内置校验器

本章简介

Struts 2提供了功能强大的类型转换器来处理表现层数据,开发者可以利用Struts 2的类型转换机制来完成任意的类型转换。在应用开发中,对用户的输入进行校验是经常遇到的业务,Struts 2提供了多种方式供开发者对客户输入的数据进行校验,非常得方便灵活。

本章将深入学习Struts 2的类型转换器和数据校验,并学习自定义类型转换器和数据校验的多种方式。

核心技能部分

8.1 Struts 2主题和模板

上一章我们学习了Struts 2中常用的标签,其实Struts 2的UI标签都是基于主题和模板的,模板是一个UI标签的外在表现形式。如果我们为所有的UI标签提供了样式和视觉效果相似的模板,那么这一系列的模板就形成了一个主题。

主题和模板是UI标签的核心,我们通过下面的例子来说明三者之间的关系。

下面是用Struts 2的表单标签组成的一个登录表单,代码如下所示:

<%@ page language="java"  pageEncoding="UTF-8"%>

<%@ taglib prefix="s" uri="/struts-tags" %>

<html>

<head>

<title>用户登录</title>

</head>

<body>

<h3>用户登录</h3>

<s:form action="checkLogin" namespace="/user">

<s:textfield name="loginname" label="登录名称"></s:textfield>

<s:password name="pwd" label="登录密码"></s:password>

<s:submit value="登录"></s:submit>

</s:form>

</body>

</html>

该页面的运行效果如图8.1.1所示。

 

图8.1.1 登录页面

现在打开本页面的源文件来看看由Struts 2表单标签生成的HTML代码:

<html>

<head>

<title>用户登录</title>

</head>

<body>

<h3>用户登录</h3>

<form id="checkLogin" name="checkLogin" οnsubmit="return true;"

action="/firstStruts 2/user/checkLogin.action" method="post">

<table class="wwFormTable">

<tr>

<td class="tdLabel">

<label for="checkLogin_loginname" class="label">登录名称:</label></td>

<td>

<input type="text" name="loginname" value=""

 id="checkLogin_loginname"/></td>

</tr>

<tr>

<td class="tdLabel">

<label for="checkLogin_pwd" class="label">登录密码:</label></td>

<td><input type="password" name="pwd" id="checkLogin_pwd"/></td>

</tr>

<tr>

<td colspan="2">

<div align="right"><input type="submit" id="checkLogin_0" value="登录"/>

</div></td>

</tr>

</table></form>

</body>

</html>

通过上述代码可以看到Struts 2的表单标签在生成HTML代码时额外多出来了很多其他的代码,我们在JSP页面中使用Struts 2表单标签时并没有使用table表格进行页面布局,但生成的HTML却自动使用table表格进行了布局,这就是模板在起作用。不同的模板会产生不同的表现形式,Struts2的UI标签默认采用table进行页面布局。

模板是UI标签的外在表现形式(也就是Struts2标签解释成HTML标签的方式),每个标签都有一个或多个模板,把样式和视觉效果相似的模板放在一起就组成了一个主题。

Struts 2默认提供了四种主题,分别是simple、xhtml、css_xhtml和Ajax。

Ø simple主题:这是最简单的主题,是底层的结构。使用该主题时,每个UI标签只生成一个HTML元素,不会额外生成其他的内容。

Ø xhtml主题:这是Struts 2的默认主题,它对simple主题进行了扩展,在simple主题的基础上增加了一些特性,该主题为UI标签使用标准的两列表格进行布局,并且能自动生成JavaScript客户端校验和自动输出校验错误提示信息。

Ø css_xhtml主题:该主题是对xhtml主题的扩展,在xhtml主题的基础上加入了CSS样式控制。

Ø Ajax主题:该主题是对xhtml主题的扩展,在xhtml主题的基础上为UI标签提供了额外的Ajax支持。例如,支持Ajax方式的客户端校验,支持表单异步提交等。

下面介绍如何使用这四种主题,设置主题是通过theme属性来实现的,主要有如下几种方式:

Ø 通过指定UI标签的theme属性来设置主题

Ø 通过取得request会话范围内的theme属性值来设置主题

Ø 通过取得session会话范围内的theme属性值来设置主题

Ø 通过取得application会话范围内的theme属性值来设置主题

Ø 通过在struts.properties或struts.xml文件中对struts.ui.theme进行指定来设置主题

值得注意的是,上述方式是有不同优先级的,排在最上面的方式会覆盖后面的方式。一旦我们指定了主题,Struts 2就会根据主题来加载模板并最终影响页面效果。一个页面一般使用一个主题或模板,所以使用theme属性设置页面主题通常放在<s:head/>标签中。

8.2 类型转换器

在基于HTTP协议的Web应用程序中,用户在客户端浏览器输入的数据都被当作字符串来接收和传递,例如表单中的姓名、生日、年龄等。当数据被传递到服务器端时就需要经过类型转换才能使用。例如表单中的年龄数据,这个数据被当作字符串传递到了服务器端,服务器端程序需要把这个数据转换成整数类型后才能使用。

而在传统的JSP+Servlet+JavaBean模型中,为了进行类型转换,开发者需要反复编写内容类似的代码。

String name=request.getParameter("name");

Date birthday=Date.valueOf(request.getParameter("birthday"));

int height=Integer.parseInt(request.getParameter("height"));

int weight=Integer.parseInt(request.getParameter("weight"));

幸运的是,Struts 2作为一个完善的、优秀的MVC框架,提供了丰富的类型转换功能,它本身内置的类型转换器可以自动完成数据类型转换,开发者一般不需要实现自定义的类型转换器。

8.2.1 Struts 2内置类型转换器

Struts 2内置了一下常用的类型转换器:

Ø 简单类型,例如int、boolean、double等,即Struts 2可以把客户端的字符串数据自动转换成int、boolean、double等数据格式。

Ø 日期类型,Struts 2会采用当前区域(Locale)的短日期格式来转换客户端的字符串格式的日期数据。

Ø 集合类型,例如Collection、List、Set等,Struts 2会将客户端的字符串数据,request.getParameterValues()方法返回的字符串数据转换成集合。

对于内置的类型转换器,我们在前面的案例中已经在使用了,这里不再多述。在实际应用中,业务千变万化,有的情况下Struts 2的内置类型转换器依然不能满足开发者的需求,但是Struts 2充分考虑到了扩展性,开发者完全可以自定义类型转换器。

8.2.2 自定义类型转换器

Struts 2中自定义的类型转换器必须实现ognl.TypeConverter接口,但是为了开发方便,可以直接继承org.apache.Struts2.util.StrutsTypeConverter抽象类,并且实现该类中的两个方法。

Ø public Object convertFromString(Map context, String[] values, Class toClass)

Ø public String convertToString(Map context,Object obj)

当需要将字符串转换成复合类型时,调用convertFromString方法;当需要将复合类型转换成字符串时,会调用convertToString方法。

下面是这两个方法的参数介绍。表8-1-1是convertFromString方法的参数介绍,表8-1-2是convertToString方法的参数介绍。

表8-1-1 convertFromString方法的参数介绍

参数

说明

Map  context

类型转换器环境的上下文

String[]  values

需要转换的请求参数字符串数组

Class  toClass

转换后的目标类型

 

表8-1-2convertToString方法的参数介绍

参数

说明

Map  context

类型转换器环境的上下文

Object obj

需要转换成字符串的实例对象

示例8.1

下面我们给出一个案例介绍自定义类型转换器的使用步骤,用户在表单中输入生日,而服务器端在接受的时候需要转换成Date类型,这个时候经常会出席类型转换异常,为了解决这个问题,我们自定义一个类型转换器。

(1)创建名字为DateConverter.java的类型转换器,继承StrutsTypeConverter类,参考代码如下所示。

public class DateConverter extends StrutsTypeConverter {

private  final DateFormat[] dfs = {  // 支持转换多种日期格式

new SimpleDateFormat("yyyy-MM-dd"),

new SimpleDateFormat("yyyy/MM/dd")

};

// 将指定格式字符串转换为日期类型

public Object convertFromString(Map context, String[] values, Class toType) {

String dateStr = values[0];// 获取日期的字符串

// 遍历日期支持格式,进行转换

for (int i=0;i<dfs.length;i++) {

try {

return dfs[i].parse(dateStr);   //类型转换

} catch (Exception e) {

continue;

}

}

//如果遍历完毕后仍没有转换成功,抛出转换异常。

throw new TypeConversionException();

}

//将日期转换为指定格式字符串

public String convertToString(Map context, Object object) {

Date date = (Date) object;

// 输出的格式是yyyy-MM-dd

return new SimpleDateFormat("yyyy-MM-dd").format(date);

}

}

在上述代码中我们重写了convertFromString和convertToString方法,本案例主要使用convertFromString方法,在该方法中实现了把客户端传过来的字符串类型的日期转换成Date类型。

(2)注册自定义类型转换器

创建好自定义类型转换器后,只有将它注册在Web应用中,Struts 2框架才能正常使用该类型转换器。方法是首先在Web工程的src根目录下创建名字为xwork-conversion.properties的文件,然后在文件中编写“目标数据类型=自定义类型转换器”代码,如下所示。

java.util.Date=com.zy.DateConverter

(3) 创建Action来测试自定义的类型转换器,代码如下所示。

public class DateAction extends ActionSupport {

private Date birthday;

public String execute() {

System.out.print(birthday);

return null;

}

public Date getBirthday() {

return birthday;

}

public void setBirthday(Date birthday) {

this.birthday = birthday;

}

}

(4) 创建JSP视图页面让用户输入自己的生日,参考代码如下所示。

<body>

<s:form action="test.action" name="f" method="post">

<s:textfield label="请输入生日" name="birthday"/>

(yyyy-mm-dd或yyyy/mm/dd)

<br/>

<s:submit value="提交"/>

</s:form>

</body>

运行效果如图8.1.2所示。

 

图8.1.2 运行效果

单击【提交】按钮后会在控制台看到如图8.1.3所示的结果。

 

图8.1.3 运行结果

8.2.3 开发集合属性的自定义类型拦截器

在实际应用开发中,经常会出现需要批量操作对象的情况。例如,产品信息的批量增加如图8.1.4所示。

 

图8.1.4产品信息的批量增加

在图8.1.4中,可以再输入产品信息后单击“增加”按钮来动态添加产品输入项,如图8.1.5所示.。

 

图8.1.5动态添加产品输入项

在图8.1.5中,用户只需要输入多个以字符串表示的产品集合,然后单击“批量增加“按钮,就可以实现产品的批量增加。与前面示例的不同在于,此处转换类型的时候不再转换一个实例,而是转换的集合。为了实现这种功能,必须开发集合属性的自定义类型转化器,实现产品批量增加的功能,步骤如下:

(1) 创建用于描述产品信息的实体类,命名为“product.java”。

public class Product {

private String id;//产品编号

private String name;//产品名称

private double price;//产品价格

public String getId() {

return id;

}

public void setId(String id) {

this.id = id;

}//getter setter方法省略。。。

 

 

(2) 创建自定义类型转换器,命名为“productConvert.java“,该类继承自StrutsTypeConverter抽象类。

//基于StrutsTypeConverter接口的类型转换器

public class ProductConvert extends StrutsTypeConverter {

//实现将字符串转换成复合类型的方法

@Override

public Object convertFromString(Map arg0, String[] arg1, Class arg2) {

List<Product> products = new ArrayList<Product>();

//循环arg1中的每个元素,每个元素代表用户输入的一个产品项

for (int i = 0; i < arg1.length; i++) {

//从arg1数组中获取用户输入的产品信息并使用逗号就行分割

String[] productValues = arg1[i].split(",");

//从分割后的数组中获取id的值

String id= productValues[0];

//从分割后的数组中获取name的值

String name = productValues[1];

//从分割后的数组中获取price的值

double price = Double.parseDouble(productValues[2]);

//创建Product实例

Product product = new Product();

//设置属性

product.setId(id);

product.setName(name);

product.setPrice(price);

//添加至集合中

products.add(product);

}

//返回列表

return products;

}

 

//实现将复合类型转换为字符串的方法

public String convertToString(Map arg0, Object arg1) {

// TODO Auto-generated method stub

return null;

}

 

}

(3) 注册ProcductConvert自定义类型转换器。在xwork-conversion.properties文件中加入用于注册ProcductConvert全局类型转换器的代码。

java.util.List=com.zzzy.web.struts.convert.ProductConvert

(4) 创建action业务控制器,命名为“ProductAction.java”,用于测试ProcductConvert类型转换器。

public class ProductAction extends ActionSupport {

//定义用于封装请求参数的Product集合实例

private List<Product> products;

public String execute()throws Exception {

//获取输出对象

PrintWriter out = ServletActionContext.getResponse().getWriter();

//获取使用productConvert类型转化器转换后的products列表对象

out.println("<h2>已成功转换,正在插入下列产品......</h2>");

out.println("编号         名称 单价</br>");

for (int i = 0; i < products.size(); i++) {

//获取id

String id = products.get(i).getId();

//获取name

String name = products.get(i).getName();

//获取价格

double price = products.get(i).getPrice();

out.println(id+"  "+name+"   "+price+"</br>");

}

return null;

}

public List<Product> getProducts() {

return products;

}

public void setProducts(List<Product> products) {

this.products = products;

}

}

(5) 创建jsp页面,命名为“product.jsp”,用于提供用户批量增加产品的界面。

<script type="text/javascript">

//动态创建表格行和文本框

function insertRow(){

//获取表格对象

var myTab = document.getElementById("tab");

//创建表格行

var newRow = myTab.insertRow(myTab.rows.length-1);

//为新增的表格动态生成文本框

newRow.insertCell().innerHTML="<input type='text' name='products'/>";

}

</script>

  </head>

  

  <body>

    <form action="productaction.action" method="post">

    <table id="tab">

    <tr>

    <td align="center" bgcolor="#FFFF66">增加产品信息</td>

    </tr>

    <tr>

    <td>

    <input type="text" name="products"/>

    <input type="button" value="增加 " οnclick="insertRow();">

   

    </td>

    </tr>

    <tr>

    <td bgcolor="#FFFF66">

    <input type="submit" value="批量添加">

    </td>

    </tr>

   

    </table>

   

    </form>

  </body>

</html>

运行product.jsp页面,输入产品数据,图8.1.5所示,单击“批量增加”按钮,运行结果如图8.1.6所示。

 

图8.1.6批量增加产品的运行结果

8.3 输入校验

由于Web应用的开放性,所有的浏览者都可以自由的访问,输入的数据可能是五花八门,所以输入校验就成了所有Web应用必须面对的问题。对于异常的输入,轻则导致系统暂时中断,重则导致系统崩溃。因此只有进行严格输入校验,才能提高系统的健壮性,保证其正常运行。通常情况下,Web应用的输入校验有两种,一种是客户端的校验,主要通过JavaScript实现,另一种是服务器端的校验,本小节将介绍通过Struts 2进行服务器端校验。

8.3.1 手工完成数据校验

1. 重写ActionSupport.validate()方法

根据前面的案例,我们会发现包含有用户输入数据的请求最终会转交给Action进行处理,那么在execute方法中就可以对转交过来的数据进行校验,例如下面实现登录的代码。

public class LoginAction extends ActionSupport {

private int id;

private String name;

private String pwd;

public String execute() {

if(name==null||name.equals(“”)||pwd==null||pwd.equals(“”))

return INPUT;

else

{

AdminDao ad=new AdminDao();

if(ad.checkLogin(name, pwd))

{

ActionContext ac=ActionContext.getContext();

Map session=ac.getSession();

session.put("logname", name);

return SUCCESS;

}

else

return ERROR;

}

}

//省略getter和setter方法

}

我们在LoginAction类的execute方法中首先对封装在name、pwd属性中的数据进行了非空校验,校验通过后才执行下面的代码。类似的,我们可以在Action类中的任何业务方法中进行数据校验,但是在大多情况下我们并不这样做,而是让Action中的业务方法专司其职:调用业务组件、返回逻辑视图。因为在设计程序时,每个方法应该尽量完成单一的任务,而不推荐两个或两个以上的功能在同一个方法中实现,否则就违反了“高内聚,低耦合”的设计原则,这样会给系统的开发与维护带来很大的麻烦,尤其一个大型系统更是如此。

ActionSupport类的validate()方法专门用来实现数据校验,所以我们创建的Action通常继承该类,同时重写validate()方法来实现数据校验。Struts 2框架会在调用Action的业务方法之前调用validate()完成数据校验。

示例8.2

下面我们改进一下登录案例,使用ActionSupport类的validate()方法实现登录校验。

public class LoginAction extends ActionSupport{

private String name;

private String pwd;

public void validate()

{

if(name==null||name.equals(""))

this.addFieldError("name", "登录名称必须填写!");

if(pwd==null||pwd.equals(""))

this.addFieldError("pwd", "登录密码必须填写!");

}

public String checkLogin()

{

return "success";

}

//省略getter和setter方法

}

我们在Action中重写了ActionSupport类的validate()方法,在该方法中对登录名称(name)和登录密码(pwd)进行了非空校验,并使用ActionSupport类的addFieldError方法设置了提示信息。该方法有两个参数,第一个参数表示被校验的属性名,第二个参数是自定义提示信息,该提示信息会在JSP页面中自动显示。一旦调用了addFieldError()方法,则说明校验失败,Action就不会继续执行业务方法。

当Struts 2在执行Action中的业务方法之前会先执行validate方法,如果没有通过数据校验,就会把错误提示信息记录下来并返回“input”结果;如果通过校验就会继续执行Action中的业务方法。

下面是login.jsp页面的参考代码。

<body>

<s:form action="login.action" method="post" >

<h3>管理员登录</h3>

<s:textfield name="name" label="登录名称"/>

<s:password name="pwd" label="登录密码"/>

<s:submit value="提交"/>

</s:form>

</body>

下面是struts.xml配置文件的参考代码。

<struts>

<package name="admin" extends="struts-default">

<action name="login" class="com.zy.LoginAction" method="checkLogin">

<result name="success">/succ.jsp</result>

<result name="input">/login.jsp</result>

</action>

</package>

</struts>

当我们没有输入登录名称和登录密码时,addFieldError方法中的提示信息就会自动在login.jsp页面中显示出来,如图8.1.7所示。

 

图8.1.7 登录校验

2. 使用validateXxx()方法

Struts 2的Action里可以包含多个业务处理方法,每个方法处理的业务各不相同,所以校验的数据也会各不相同,这时它们就无法共用一个validate()方法。

Struts 2框架允许在Action中提供一个validateXxx方法来专门校验xxx这个业务处理方法,xxx是业务方法的名字,在validateXxx方法中业务方法名字的首字母变大写。例如,在一个Action中有一个业务方法为regist,我们就可以使用validateRegist方法来校验regist业务方法所需要的数据。

示例8.3

下面我们使用这种方式修改登录案例,只需要修改一下Action的代码即可。

public class LoginAction extends ActionSupport{

private String name;

private String pwd;

public void validateCheckLogin()

{

if(name==null||name.equals(""))

this.addFieldError("name", "登录名称必须填写!");

if(pwd==null||pwd.equals(""))

this.addFieldError("pwd", "登录密码必须填写!");

}

public String checkLogin()

{

return "success";

}

public void validateReg(){

//代码省略

}

public String reg(){

//代码省略

}

//省略getter和setter方法

}

修改过之后的运行效果和图8.1.7一样。

3. Struts 2的校验顺序

通过上面的介绍我们可以了解到,在Struts 2框架下可以使用多种方式进行输入校验,这些校验并不是无序的,而是按照一定的顺序来执行的,顺序如下:

(1)客户端校验,如果有的话。

(2)对请求的字符串参数进行类型转换,并设置为对应的Action属性值。

(4)调用Action中的validateXxx方法进行校验。

(5)调用Action的validate方法进行校验。

(6)完成上面的步骤之后,Struts 2框架开始检查在以上过程中有没有通过输入校验,如果没有,则返回“input”逻辑视图,如果通过,则执行Action中的业务方法。

(7)系统根据上一步骤返回的逻辑视图名,跳转到相对应的视图页面。

8.3.2 Struts 2内置校验器

1. 校验配置文件

我们前面学习了几种进行输入验证的方式,例如重写validate方法、使用validateXxx方法等,虽然这些方式都能完成数据校验,但是缺点也非常明显。首先,如果验证规则多且复杂,那就需要编写繁琐的验证代码,直接导致Action类的臃肿。其次,实现验证规则的代码无法有效重用,例如很多数据都需要进行非空验证,但是我们每次都有重复编写类似的验证代码。

鉴于数据验证的普遍性和重复性,Struts 2内置了很多校验器,平时常用的验证规则都已在这些内置校验器中实现,例如非空验证、长度验证、电子邮箱验证等。我们只需在外部配置文件中为某个属性设置相应的校验器即可。

下面我们使用内置校验器优化登录案例,验证的内容包括登录名和登录密码非空,登录密码的长度必须大于等于6。

在使用Struts2内置校验器时,Action中就无需任何校验代码了,所以像validate、validateXxx方法就不再需要了,其他代码保持不变,只需额外增加一个校验配置文件即可。校验配置文件必须和需要验证的Action放在同一个包中,并且采用“Action的类名—validation.xml”方式命名,下面是我们为LoginAction.java所编写的校验配置文件LoginAction—validation.xml,代码如下所示。

<?xml version="1.0" encoding="utf-8"?>

<!DOCTYPE validators PUBLIC

"-//OpenSymphony Group//XWork Validator 1.0.2//EN"

"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">

<validators>

<field name="name">

<field-validator type="requiredstring">

<message>登录不能为空!</message>

</field-validator>

</field>

<field name="pwd">

<field-validator type="requiredstring">

<message>登录密码不能为空!</message>

</field-validator>

<field-validator type="stringlength">

<param name="minLength">6</param>

<message>密码长度必须大于等于${minLength}</message>

</field-validator>

</field>

</validators>

运行效果与图8.1.7一样,下面我们重点介绍一下校验配置文件。

Ø <validators>是根元素,所有的校验配置代码都必须写在该元素内。

Ø <field>元素对应Action中需要校验的属性,name属性值必须和Actin中的属性名一致。

Ø <field-validator>元素用来设置使用哪个内置校验器,上述代码中的“requiredstring”和“stringlength”就是Struts 2内置校验器的名字,“requiredstring”用来实现非空校验,“stringlength”用来实现长度校验。

Ø <message>元素用来设置自定义提示信息。

2. 内置校验器的使用

在xwork-core-2.2.1.jar中可以找到一个名字是default.xml的文件,Struts 2内置的校验器都来自这里,代码如下所示。

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE validators PUBLIC

        "-//OpenSymphony Group//XWork Validator Config 1.0//EN"

"http://www.opensymphony.com/xwork/xwork-validator-config-1.0.dtd">

<validators>

<validator

name="required" class="com.opensymphony.xwork2.validator.validators.

RequiredFieldValidator"/>

<validator name="requiredstring"

class="com.opensymphony.xwork2.validator.validators.

RequiredStringValidator"/>

<validator name="int"

class="com.opensymphony.xwork2.validator.validators.

IntRangeFieldValidator"/>

<validator name="long"

 class="com.opensymphony.xwork2.validator.validators.

LongRangeFieldValidator"/>

<validator name="short"

class="com.opensymphony.xwork2.validator.validators.

ShortRangeFieldValidator"/>

<validator name="double"

class="com.opensymphony.xwork2.validator.validators.

DoubleRangeFieldValidator"/>

<validator name="date"

class="com.opensymphony.xwork2.validator.validators.

DateRangeFieldValidator"/>

<validator name="expression"

class="com.opensymphony.xwork2.validator.validators.

ExpressionValidator"/>

<validator name="fieldexpression"

class="com.opensymphony.xwork2.validator.validators.

FieldExpressionValidator"/>

<validator name="email"

class="com.opensymphony.xwork2.validator.validators.

EmailValidator"/>

<validator name="url"

class="com.opensymphony.xwork2.validator.validators.URLValidator"/>

<validator name="visitor"

class="com.opensymphony.xwork2.validator.validators.

VisitorFieldValidator"/>

<validator name="conversion"

class="com.opensymphony.xwork2.validator.validators.

ConversionErrorFieldValidator"/>

<validator name="stringlength"

class="com.opensymphony.xwork2.validator.validators.

StringLengthFieldValidator"/>

<validator name="regex"

class="com.opensymphony.xwork2.validator.validators.

RegexFieldValidator"/>

<validator name="conditionalvisitor"

class="com.opensymphony.xwork2.validator.validators.

ConditionalVisitorFieldValidator"/>

</validators>

一个<validator>元素配置一个校验器,name属性设置校验器的名字,class属性设置校验器的实现类。下面我们列举一些常用内置校验器的例子。

3. 非空校验器

Struts 2内置了两个非空校验器:required和requiredstring,required用来校验数据是否为null,可以校验任何对象,而requiredstring只针对字符串类型的数据,可以参看上面的示例。

4. 长度校验器

长度校验器的名字为stringlength,它要求被校验的字段必须满足指定的长度范围,否则就会校验失败,此校验器常用的参数如下所示:

Ø maxLength:此参数指定字符串的最大长度,这是一个可选的参数,如果不指定这个参数,表示字符串的最大长度不限。

Ø minLength:此参数用来指定字符串的最小长度,这也是一个可选的参数,如果不指定,则表示最小长度不限。

Ø trim:如果其值为true,表示在校验此字符串之前截掉字符串的前后空格,这也是一个可选的参数,并且默认值为true。

<validators>

<field name="pass">

<field-validator type="stringlength">

<param name="maxLength">10</param>

<param name="minLength">6</param>

<message>密码长度应${minLength}到${maxLength}!</message>

</field-validator>

</field>

</validators>

<param>元素用来设置参数,同时我们可以使用OGNL取出参数的值。

5. 整数校验器

整数校验器的名字为int。此校验器要求被校验的整数在指定的整数范围内,否则校验失败。此校验器常用的参数如下所示:

Ø max:此参数指定最大整数值,这是一个可选的参数,如果不指定这个参数,表示最大整数值不限。

Ø min:此参数用来指定被校验整数的最小值,这也是一个可选的参数,如果不指定,则表示最小值不限。

<field name="age">

<field-validator type="int">

<param name="min">18</param>

<param name="max">50</param>

<message>年龄必须为${min}到${max}的整数</message>

</field-validator>

</field>

6. 日期校验器

日期校验器的名字为date,此校验器要求被校验的日期值必须在指定的范围内,否则校验失败。此校验器常用的参数如下所示:

Ø max:此参数指定最大日期值,这是一个可选的参数,如果不指定这个参数,表示最大日期值不限。

Ø min:此参数用来指定被校验日期的最小值,这也是一个可选的参数,如果不指定,则表示最小值不限。

<field name="birthday">

<field-validator type="date">

<param name="max">2000-01-01</param>

<param name="min">1900-01-01</param>

<message>生日必须为${min}到${max}</message>

</field-validator>

</field>

7. 表达式校验器

表达式校验器的名字为fieldexpression,它要求指定的字段必须满足一个逻辑表达式,此校验器常用的参数如下所示:

Ø expression:此参数指定一个逻辑表达式,最后返回一个Boolean值,当返回为true时校验通过,否则校验失败。

<field name="pass">

<field-validator type="requiredstring">

<message>密码不能为空!</message>

</field-validator>

<field name="rpass">

<field-validator type="fieldexpression">

<param name="expression"><![CDATA[(pass==rpass)]]></param>

<message>两次输入的密码必须一致!</message>

</field-validator>

</field>

8. 邮箱地址校验器

邮箱地址校验器的名字为email,它要求指定的字段必须满足邮箱地址的规则。使用该校验器时不需要设置任何参数。

<validators>

<field name="youxiang">

<field-validator type="email">

<message>电子邮箱格式不正确!</message>

</field-validator>

</field>

</validators>

Struts 2内置的校验器不止这么多,大家有兴趣可以查阅相关资料。另外需要注意的是:在使用内置校验器时,我们自定义的Action必须继承ActionSupport类。

下面通过一个注册案例,综合演示一下内置校验器的应用。

示例8.4

(1) 创建reg.jsp;

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>

<%@ taglib  uri="/struts-tags" prefix="s"%>

<%

String path = request.getContextPath();

String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";

%>

 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

  <head>

    <base href="<%=basePath%>">

    

    <title>My JSP 'reg.jsp' starting page</title>

    

<meta http-equiv="pragma" content="no-cache">

<meta http-equiv="cache-control" content="no-cache">

<meta http-equiv="expires" content="0">    

<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">

<meta http-equiv="description" content="This is my page">

<!--

<link rel="stylesheet" type="text/css" href="styles.css">

-->

 

  </head>

  

  <body>

    <s:form action="useraction.action" >

    <s:textfield label="用户名" name="name" />

    <s:password name="pwd" label="密码"/>

    <s:password name="rpwd" label="确认密码"/>

    <s:textfield label="邮箱" name="email"/>

    <s:textfield label="年龄" name="age"/>

    <s:textfield label="生日" name="birthday"/>

    <s:submit value="注册"/>

    </s:form>

  </body>

</html>

(2) 创建UserAction.java。

public class UserAction extends ActionSupport {

 

private String name;

private String pwd;

private String rpwd;

private String email;

private int age;

private Date birthday;

public String execute() {

//代码省略......

return SUCCESS;

}

//getter setter方法省略

}

(3) 在struts.xml中 配置action

<action name="useraction" class="com.zzzy.action.UserAction">

 <!-- 注意添加input配置 -->

  <result name="input">/reg.jsp</result>

  <result >/ssuc.jsp</result>

  </action>

(4) 在src目录下创建UserAction-validation.xml校验文件

 

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE validators PUBLIC

   "-//OpenSymphony Group//XWork Validator 1.0.2//EN"

   "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">

<validators>

  <field name="name">

    <field-validator type="requiredstring">

      <message>用户名不能为空!</message>

    </field-validator>

  </field>

  <field name="pwd">

    <field-validator type="requiredstring">

      <message>密码不能为空!</message>

    </field-validator>

   <field-validator type="stringlength">

<param name="maxLength">10</param>

<param name="minLength">6</param>

<message>密码长度应${minLength}到${maxLength}!</message>

</field-validator>

 

  </field>

  

  <field name="rpwd">

<field-validator type="fieldexpression">

<param name="expression"><![CDATA[(pwd==rpwd)]]></param>

<message>两次输入的密码必须一致!</message>

</field-validator>

</field>

  

  <field name="age">

<field-validator type="int">

<param name="min">18</param>

<param name="max">50</param>

<message>年龄必须为${min}到${max}的整数</message>

</field-validator>

</field>

  

  <field name="birthday">

<field-validator type="date">

<param name="max">2000-01-01</param>

<param name="min">1900-01-01</param>

<message>生日必须为${min}到${max}</message>

</field-validator>

</field>

 

  <field name="email">

<field-validator type="email">

<message>电子邮箱格式不正确!</message>

</field-validator>

</field>

  

</validators>

(5) 运行reg.jsp 提交后,内置校验器如果校验失败,则转向input,显示出错误消息。结果如图8.1.8所示。

 

图8.1.8 校验失败


本章总结

Ø Struts 2主题和模板,Struts 2的UI标签都是基于主题和模板的,模板是一个UI标签的外在表现形式。如果我们为所有的UI标签提供了样式和视觉效果相似的模板,那么这一系列的模板就形成了一个主题。

(1)Struts 2默认提供了四种主题,分别是simple、xhtml、css_xhtml和Ajax。

(2)设置主题是通过theme属性来实现的,可以通过指定UI标签的theme属性、取得request会话范围内的theme属性值、取得session会话范围内的theme属性值、取得application会话范围内的theme属性值、在struts.properties或struts.xml文件中对struts.ui.theme进行指定来设置主题。

Ø 自定义类型转换器

(1)Struts 2中自定义的类型转换器必须实现ognl.TypeConverter接口,但是为了开发方便,可以直接继承org.apache.Struts2.util.StrutsTypeConverter抽象类,并且实现该类中的两个方法。

(2)注册自定义类型转换器,在Web工程的src根目录下创建名字为xwork-conversion.properties的文件,然后在文件中编写“目标数据类型=自定义类型转换器”。

Ø 输入校验

(1)手工完成数据校验。

(2)Struts 2内置校验器。


任务实训部分

1:添加管理员的输入验证

训练技能点

Ø 重写validate方法

需求说明

前面我们实现了添加管理员的案例,现在要求在添加管理员时进行输入验证,登录名称和登录密码要求非空,登录密码的长度要求必须在6-10之间,两次输入的密码必须相同,请通过重写validate方法实现。

实现步骤

(1) 把原来的登录表单使用Struts 2标签进行替换。

(2) 在原Action中重写validate方法,参考代码如下所示。

public void validate()

{

if(logName==null||logName.equals(""))

this.addFieldError("logName", "登录名称必须填写");

if(logPwd1==null||logPwd1.equals(""))

this.addFieldError("logPwd1", "登录密码必须填写");

if(logPwd1.length()<6||logPwd2.length()>10)

this.addFieldError("logPwd1", "密码长度必须在6~10之间");

if(!logPwd1.equals(logPwd2))

this.addFieldError("logPwd2", "两次输入的密码必须相同");

}

(3) 在struts中增加input结果。

2:添加学生的输入验证

训练技能点

Ø 使用Struts 2内置校验器

需求说明

实现添加学生的案例,并要求在添加学生时对输入进行验证,学生姓名、学生生日非空,学生身高必须在120到200之间。

3:简易计算器

训练技能点

Ø 自定义类型转换器

需求说明

前面我们实现了一个计算器案例,但是现在我们要求页面中只出现一个文本框,用户可以在这个文本框中输入两个数字进行运算,两个数字之间用逗号隔开,如图8.3.1所示。要求使用自定义类型转换器实现。

实现步骤

(1) 创建一个名字是Digit的类用来描述用逗号隔开的两个数字,参考代码如下所示。

public class Digit {

private double num1;  //表示逗号前的数字

private double num2;  //表示逗号后的数字

//省略getter和setter方法

}

(2) 创建Action类,参考代码如下所示。

public class CalculatorAction {

private Digit num;  //文本框中的数据要转换成Digit类型

private double result;

public String jia()

{

result=num.getNum1()+num.getNum2();

return "result";

}

public String jian()

{

result=num.getNum1()-num.getNum2();

return "result";

}

public String cheng()

{

result=num.getNum1()*num.getNum2();

return "result";

}

public String chu()

{

result=num.getNum1()/num.getNum2();

return "result";

}

//省略getter和setter方法

}

(3) 下面是JSP页面的参考代码。

<body>

<form name="frm" method="post">

<table width="298" border="0" align="center">

<tr>

<td colspan="2" align="center">简易计算器</td>

</tr>

<tr>

<td width="76" align="center">请输入两个数</td>

<td width="206"><input type="text" name="num"

 value="${num.num1},${num.num2}">中间用逗号隔开</td>

</tr>

<tr>

<td colspan="2" align="center">

<input type="button"  value="+" οnclick="submitForm('jia')">

<input type="button"  value="-" οnclick="submitForm('jian')">

<input type="button"  value="*" οnclick="submitForm('cheng')">

<input type="button"  value="/" οnclick="submitForm('chu')"></td>

</tr>

<tr>

<td align="center">结果</td>

<td><input type="text" name="result" readonly value="${result}"></td>

</tr>

</table>

</form>

</body>

<script>

function submitForm(op)

{

frm.action="cal_"+op+".action";

frm.submit();

}

</script>

(4) 创建自定义类型转换器,实现文本框中的字符串转换成Digit类型,参考代码如下所示。

public class CalculatorConverter extends StrutsTypeConverter {

public Object convertFromString(Map context, String[] values, Class toClass) {

String[] nums=values[0].split(",");

Digit d=new Digit();

d.setNum1(Double.parseDouble(nums[0]));

d.setNum2(Double.parseDouble(nums[1]));

return d;

}

public String convertToString(Map context, Object o) {

return null;

}

}

 

图8.3.1 运行效果

4:生日类型转换器

训练技能点

Ø 自定义类型转换器

需求说明

上面的实训任务包含了一个生日文本框,现在要求该生日文本框支持用户输入“yyyy-mm-dd”和“yyyy/mm/dd”两种格式,请使用自定义类型转换器完成对生日的类型转换。

巩固练习

一、选择题

1. 自定义的类型转换器必须实现的接口是()。

A. StrutsConvert

B. StrutsTypeConvert

C. TypeConvert

D. Convert

2. 下面关于Struts 2主题说法错误的是()。

A. Struts 2可以通过主题影响页面效果

E. Struts 2的默认主题是simple

F. theme属性可以设置主题

G. 主题只对Struts 2标签起作用

3. 下面关于Struts 2类型转换器说法错误的是()。

A. Struts 2内置了一些类型转换器

B. Struts 2不支持自定义类型转换器

C. 自定义的类型转换器必须实现ognl.TypeConverter接口

D. 自定义的类型转换器必须添加xwork-conversion.properties文件

4. 下面关于Struts 2输入校验说法错误的是()。

A. WEB应用通常需要服务器端校验,根本不需要客户端校验

B. Struts 2内置了很多校验器

C. 使用内置校验器需要添加校验配置文件

D. Struts 2具备自动生成客户端校验的功能

5. 下面关于Struts 2输入校验说法正确的是()。

A. Struts2校验文件中不能使用正则表达式。

B. requiredstring用来实现非空校验。

C. requiredString用来实现非空校验。

D. 校验文件的命名是随意的。

 

 

二、上机练习

自己实现一个注册功能,要求用户填写昵称、登录密码和电子邮件并对这些输入进行验证,登录密码长度必须大于等于8,电子邮件必须符合规定,请使用Struts 2内置校验器实现。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

teayear

读后有收获可以支付宝请作者喝咖

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值