进行数据验证前,我们先解决一个一直没有影响我们编码,但可能却影响心情的小问题。
即没有引用servlet而引发的错误警告:
![https://box.kancloud.cn/2b1e3c5689812d4b0fde5e7948da1294_1148x202.png](https://box.kancloud.cn/2b1e3c5689812d4b0fde5e7948da1294_1148x202.png)
该类为tomcat为我们提供的类,修复步骤如下:
bulidpath -> config buildpath -> Libraries -> add Library... -> Server Runtime -> Apache Tomcat v7.0 -> finish -> ok。
这时候, 红色的小叉叉应该没有了。
<hr />
下面,我们正式加入验证信息。
流程图如下:
![https://box.kancloud.cn/1702cc12ea19dbdc7877c15d7e87e0c4_690x1214.png](https://box.kancloud.cn/1702cc12ea19dbdc7877c15d7e87e0c4_690x1214.png)
## 定义出错后的操作界面error
jsp/teacher/error.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>
<h2>验证错误</h2>
</body>
</html>
```
## 配置路由
假设我们为新增数据的保存操作进行验证,则我们配置保存操作的路由:
struts.xml
```
<!-- 保存数据 -->
<action name="save" class="com.mengyunzhi.javaee.action.teacher.Save">
<!-- 设置V层,相对于WebContent的绝对路径 -->
<result name="success">/jsp/success.jsp</result>
<result name="error">/jsp/error.jsp</result>
<result name="input">/jsp/teacher/error.jsp</result>
</action>
```
> 有人问为什么要使用input,而不用其它的呢。原因是因为大家都用input,所以我们也用input能够更好的和其它软件工程师交流。
## 测试路由与V层
打开保存的类,然后注释掉原返回值,新增返回input
com.mengyunzhi.javaee.action.teacher SaveAction
我们对用户名的长度进行规定,并在V层输出我们返回的错误信息。
```
...
// 错误信息
private String error;
public String getError() {
return error;
}
public String execute() {
if (this.username.length() < 4) {
error = "用户名长度过短";
return input;
}
if (this.name.length() < 3) {
error = "姓名长度过短";
return input;
}
......
```
### V层显示
```
<h2>验证错误</h2>
<h3><s:property value="error" /></h3>
```
> V层只所以可以使用`error`这个变量,这由于在Action中,存在getError()方法.
### 测试:
![https://box.kancloud.cn/6d3afc94fe7944c8f031a27563ddd5fe_748x322.png](https://box.kancloud.cn/6d3afc94fe7944c8f031a27563ddd5fe_748x322.png)
## 增加多个验证,并一次性输出
流程图如下:
![https://box.kancloud.cn/decfc0b2137185515cdfa7caef5f312b_364x624.png](https://box.kancloud.cn/decfc0b2137185515cdfa7caef5f312b_364x624.png)
### 触发器
```
...
public class SaveAction extends TeacherAction {
...
if (username.length() < 4) {
addActionError("用户名长度过短");
}
if (this.name.length() < 3) {
addActionError("姓名长度过短");
}
...
// 存在错误,则返回input
if (hasActionErrors()) {
return INPUT;
} else {
return SUCCESS;
}
...
```
> 我们间接的继承了`ActionSupport`,而`addActionError`等函数,则正是`ActionSupport`中的方法。
### V层
```
<h2>验证错误</h2>
<ul>
<s:iterator value="actionErrors" var="actionError" status="status">
<li><s:property value="#actionError" /></li>
</s:iterator>
</ul>
```
### 测试
![https://box.kancloud.cn/a567b03ea8db1982b6769d082e8a6a1d_852x346.png](https://box.kancloud.cn/a567b03ea8db1982b6769d082e8a6a1d_852x346.png)
总结:我们可以在继承ActionSupport后,很简单的实现了字段的验证,这在实际的开发中,也是必要的。
示例代码如下:
```
package com.mengyunzhi.javaee.action.teacher;
import java.util.Collection;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
public class SaveAction extends TeacherAction {
/**
* 创建时间:2017.1.16
*/
private static final long serialVersionUID = 1L;
private String username;
private String password;
private String sex;
private String name;
private String email;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
// 该execute方法将被自动调用, 方法的返回类型必须为String
public String execute() {
if (username.length() < 4) {
addActionError("用户名长度过短");
}
if (this.name.length() < 3) {
addActionError("姓名长度过短");
}
// 实例化并加载数据库配置文件
Configuration configuration = new Configuration().configure();
// 构造服务注册对象
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
.applySettings(configuration.getProperties())
.buildServiceRegistry();
// 创建会话工厂(session factory))
SessionFactory sessionFactory = configuration
.buildSessionFactory(serviceRegistry);
// 创建会话(这里的session也是会话的意思,我们以前接触的http中的session,处理的是用户与服务器的对话)
Session session = sessionFactory.getCurrentSession();
// 开启事务(使用缓冲池进行数据库的连接)
Transaction transaction = session.beginTransaction();
// 在这里,必须使用try catch finally语句。来确定会话正常关闭.
// 否则,当操作数据库产生错误时,你可能需要重启mysql服务
try {
// 初例化 赋值
com.mengyunzhi.javaee.entity.Teacher teacher = new com.mengyunzhi.javaee.entity.Teacher();
teacher.setName(name);
teacher.setUsername(username);
teacher.setEmail(email);
teacher.setPassword(password);
// 由于sex的类型是String对象,所以需要使用equals()来判等
if (sex.equals("0")) {
teacher.setSex(false);
} else {
teacher.setSex(true);
}
session.save(teacher);
// 提交事务
transaction.commit();
// 捕获异常
} catch (HibernateException e) {
} finally {
// 如果session处于开启状态,则关闭session
if (session.isOpen()) {
// 关闭会话
session.close();
}
}
// 存在错误,则返回input
if (hasActionErrors()) {
return INPUT;
} else {
return SUCCESS;
}
}
}
```
> 注意:上述代码未重构,直接在C层调用实体层,是错误的做法。我们将在下一个班级管理中,对该方法进行重构.
<hr />
下面,我们共同看看Struts使用注解进行验证的方法。
我们在前面学过了,数据由用户发送的时候,直接调用了action类的setXXX方法,来进行赋值。Struts的验证也是利用了这一点,在进行赋值时,进行验证。如果正确的则正确执行,如果错误,则返回"input".
流程图如下:
![https://box.kancloud.cn/9aa4c2d12384f92a242887264c9f935d_882x1516.png](https://box.kancloud.cn/9aa4c2d12384f92a242887264c9f935d_882x1516.png)
# 内置验证
首先,我们删除在execute中用于验证的代码,并直接返回SUCCESS.
然后,我们在setName()、setUsername()方法上添加注解,来实现验证.
```
...
@RequiredStringValidator(
message="用户名不能为空")
@StringLengthFieldValidator(
minLength="4",
maxLength="8",
trim=true,
message="用户名必须介于4-8之间")
public void setUsername(String username) {
this.username = username;
}
...
@RequiredStringValidator(
message="姓名不能为空")
@StringLengthFieldValidator(
minLength="2",
trim=true,
message="姓名不能少于2位")
public void setName(String name) {
this.name = name;
}
```
## V层显示错误信息
验证字段产生的错误将自动存储在`fieldErrors`中,该字段同样位于`ActionSupport`中,同时为我们提供了`getFieldErrors`供我们在前台调用。
```
<ul>
<!-- 循环输出字段验证发生的错误 -->
<s:iterator value="fieldErrors" var="fieldError">
<li><s:property /></li>
</s:iterator>
</ul>
```
![https://box.kancloud.cn/d6b30601c55ce08e2bca1a4dc1750cf2_722x348.png](https://box.kancloud.cn/d6b30601c55ce08e2bca1a4dc1750cf2_722x348.png)
不止如此,我们还可以使用struts的内置标签来快捷的输出错误:
```
<body>
<h2>验证错误</h2>
<ul>
<!-- 循环输出字段验证发生的错误 -->
<s:iterator value="fieldErrors" var="fieldError">
<li><s:property /></li>
</s:iterator>
</ul>
<!-- 使用struts内置标题输出字段,将自动带入出错信息 -->
<s:textfield label="姓名:" name="name" />
<br />
<s:textfield label="用户名:" name="username" />
</body>
```
![https://box.kancloud.cn/d63c34721992d581b49e4562e9c44e2c_814x476.png](https://box.kancloud.cn/d63c34721992d581b49e4562e9c44e2c_814x476.png)
好像,如果出现错误的话,应该再显示add界面,并在add界面显示错误吧。
<hr />
没错,的确是这样,现在,让我们重构V层。
1. 修改路由
```
<!-- 保存数据 -->
<action name="save" class="com.mengyunzhi.javaee.action.teacher.Save">
<!-- 设置V层,相对于WebContent的绝对路径 -->
<result name="success">/jsp/success.jsp</result>
<result name="error">/jsp/error.jsp</result>
<result name="input">/jsp/teacher/add.jsp</result>
</action>
```
2. 重构add.jsp
```
<form action="save" method="post">
<s:textfield label="姓名:" name="name" />
<br />
<s:textfield label="用户名:" name="username" />
<br /> 性别:<select name="sex">
<option value="0">男</option>
<option value="1">女</option>
</select> <br /> 邮箱:<input type="text" name="email" /><br /> 密码:<input
type="password" name="password" /><br />
<button type="submit">submit</button>
</form>
```
3. 删除jsp/teacher/error.jsp
![https://box.kancloud.cn/d63c34721992d581b49e4562e9c44e2c_814x476.png](https://box.kancloud.cn/d63c34721992d581b49e4562e9c44e2c_814x476.png)
作业:验证其它3个字段;增加udpate的验证。
> 官方文档:[http://127.0.0.1:8081/docs/validation.html](http://127.0.0.1:8081/docs/validation.html), [http://127.0.0.1:8081/docs/validation-annotation.html](http://127.0.0.1:8081/docs/validation-annotation.html)
- README
- 第一章:准备
- 第二章:Hello World!
- 第一节:查看工程文件
- 第二节:JDK、JRE与环境变量
- 第三节:index.jsp
- 第三章:Hello Struts
- 第一节:Web.xml
- 第二节:单入口
- 第三节:Hello Struts
- 第四节:触发C层
- 第四章:建立数据表
- 第一节:建立实体类
- 第二节:测试一
- 第三节:测试二
- 第四节:引入Hibernate
- 第五节:配置Hibernate
- 第六节:建立连接
- 第七节:实体类映射数据表
- 第八节:完善数据表
- 第五章:教师管理
- 第一节:增加数据--add
- 第二节:增加数据--save
- 1 获取传入数据数据
- 2 数据写入测试
- 3 对接C层
- 第三节:数据列表
- 1 获取数据
- 2 重构代码
- 3 C层对接--初始化
- 4 C层添加数据
- 5 V层显示数据
- 6 获取数据库中数据
- 7 显示性别
- 8 分页
- 9 条件查询
- 第四节:修改数据
- 1 edit
- 2 update
- 第五节:删除数据
- 第六节:总结
- 第六章:重构C层
- 第一节:继承ActionSupport类
- 第二节:数据验证
- 第七章:前台分离(前台)
- 第一节:环境搭建
- 第二节:运行环境
- 第三节:共享开发环境
- 第四节:生产环境
- 第八章:前台开发(前台)
- 第一节:本地化
- 第二节:教师列表
- 1 引入M层
- 2 模拟后台返回数据
- 3 C与M对接
- 4 C与V对接
- 第九章:前后台对接(前后台)
- 第一节:后台输出json(后台)
- 第二节:对接前台(全栈)
- 第二节:对接API(前台)
- 第二节:跨域请求(后台)
- 第三节:重构代码(前台)
- 第十章:重构后台M层
- 第一节:数据访问DAO层
- 第二节:项目整体重构
- 第十一章:用户登陆(前后台)
- 第一节:制定规范
- 第二节:定制测试用例
- 第三节:后台输入测试代码(后台)
- 第四节:postman(后台)
- 第五节:新建用户登陆模块(前台)
- 第六节:代码重构(前台)
- 第十二章:班级管理(前后台)
- 第一节:班级列表
- 1 原型开发
- 2 制定规范
- 3 后台对接开发
- 4 前台对接开发
- 第二节:Add
- 1 原型开发
- 2 制定规范
- 3 后台对接开发
- 4 前台对接开发
- 第三节:Save
- 1 制定规范
- 2 后台对接开发
- 3 前台对接开发
- 第四节:Edit
- 1 原型开发
- 2 制定规范
- 3 后台对接开发
- 4 前台对接开发
- 第五节:Update
- 1 制定规范
- 2 后台对接开发
- 3 前台对接开发
- 第六节:Delete
- 1 制定规范
- 2 后台对接开发
- 3 前台对接开发
- 第七节:小结
- 第十三章:班级管理(API)
- 第一节:ER图
- 第二节:create
- 1 实体层
- 2 dao层
- 3 service(server)层
- 4 action层
- 第三节:ManyToOne
- 第四节:Read
- 1 service(server)层
- 2 action层
- 第五节:update
- 1 service(server)层
- 2 action层
- 第六节:update
- 第十四章:重构服务层