数据效验
1)数据效验2种方式
前台校验
也称之为客户端校验,主要是通过JavaScript编程的方式进行表单数据的验
证。
特点:数据效验在客户端浏览器完成,效率高!不安全!
后台校验
也称之为服务器端校验,这里指的是使用Struts2通过XML配置的方式进行表
单数据的验证。 通过java代码进行的效验!
特点:数据效验在服务器后台完成,安全!效率低!
1. 前台 + 后台效验,安全性最高!
2. 只用前台效验
2)Struts提供了数据效验 后台效验!
3)数据效验流程
拦截器调用指定的方法:validate()方法;
然后判断保存错误的map集合是否为空,为null,才执行action的execute()方法!
如果不为null, 说明验证有错误,就不放行!
1.1 数据效验原理
public synchronized void addFieldError(String fieldName, String errorMessage) {
// 保存所有的错误信息的map集合
// 同一个key,可以对应多个值
final Map> errors = internalGetFieldErrors();
// 先根据当前错误的key,去错误的map集合中查找,看是否已经存在!
List thisFieldErrors = errors.get(fieldName);
// 当前错误的key,在map集合不存在
if (thisFieldErrors == null) {
thisFieldErrors = new ArrayList();
errors.put(fieldName, thisFieldErrors);
}
// 设置错误信息!
thisFieldErrors.add(errorMessage);
}
1.2 错误处理
验证失败:
JSP报错:
HTTP Status 404 - No result defined for action cn.itcast.a_validation.RegisterAction and result input
后台异常:
No result defined for action cn.itcast.a_validation.RegisterAction and result input
解决:
1) 配置错误视图标记input,对应的jsp页面!
2) 出现错误,跳转到”register.jsp”
- 合理显示错误信息!
Struts.xml
/register.jsp
ul{
display: inline;
}
ul li{
display: inline;
}
用户名:
密码:
修改s:fielderror标签的默认样式,方式2:
template.simple/fielderror.ftl (删除ul/li内容!)
把上面修改好的文件放到src下,这样就会覆盖struts核心包中默认的标签定义!
总结:验证Action类中的方法! 验证的是所有方法!
1.3 【代码方式验证】
1) 验证Action类中所有的方法:
- 重写validate()方法名即可!
2) 验证Action类中指定的方法
- validate方法名() 方法名第一个字母大写
举例: validateRegister()
表示验证当前Action类的register方法!
总结:
手写代码验证,
# 代码重复较多,比较麻烦!
# 可以实现任何验证逻辑,验证比较灵活!
常用的验证,
非空,长度, email, 日期, 整数验证…..
都是常用验证,如果要优化,可以先实现这些验证,验证器!
XML验证
1.4 【XML验证】
Struts对常用的验证逻辑,提供了相应的验证器!
如非空,非空验证器(类)
长度, 长度验证器(类)
Email, 邮箱验证器
………
如果是对上面常用的数据进行验证,可以使用XML配置的方式实现!
XML验证
验证指定Action中所有的方法:
1) XML命名
语法: ActionClassName-validation.xml
举例: RegisterAction_xml-validation.xml
要求:
当前XML要与验证文件XML在同一个包下!
2)XML 内容
参考:xwork-core-2.3.4.1.jar\xwork-validator-1.0.3.dtd 这个dtd约束!
验证指定Action中指定的方法:
文件名命名规则:ActionClassName -ActionName-validation.xml
如: RegisterAction_xml-user_register-validation.xml
第一部分是Action类名称
第二部分是Action的访问名称
1.5 验证总结
1) 代码方式,验证Action中所有方法:
方法名:validate();
1) 代码方式,验证Action中指定方法:
方法名:validate方法名();
2) XML验证,所有方法
文件名:ActionClassName-validation.xml
2) XMl验证,指定的方法
文件名:ActionClassName-actionName-validation.xml
什么时候用代码方式验证?
* 验证字段较少
* 验证逻辑比较负责!
XML
* 验证字段较多,且有较多重复验证逻辑!
如果代码、XML一起用?
代码验证会优先!
2.国际化
回顾javaweb国际化
1. 写国际化资源文件
命名规则:基础名_语言简称_国家简称.properties
举例:
message_zh_CN.properties 存储中文字符串文件
message.properties 存储默认的语言字符串(中文)
message_en_US.properties 美国
2. 加载资源文件
代码:
ResourceBundle 类
JSP:
Jstl标签!
Struts中国际化
Struts中提供了更加方便的加载资源文件的方式!
1. 通过常量加载资源文件!
2. struts提供了国际化的标签
通过text标签,可以显示国际化字符串
name 值资源文件中配置的key
另外,
加载资源文件可以使用常量,也可以在jsp页面通过标签:
3.类型转换
Struts如何封装请求数据?
两种方式!
封装过程中,涉及类型转换:
1. 基本数据类型,struts会自动转换!
会把表达提交的String转换为属性对应的类型!
2. 日期类型呢?能否自动转换? 支持的格式?
日期类型,也会自动转换!
默认支持: yyyy-MM-dd格式
3. 如果日期是其他格式:
yyyy-MM-dd
yyyyMMdd
yyyy/MM/dd
yyyy年MM月dd日
如果日期是其他格式,strtus默认就不支持,需要“自定义类型转换器”
类型转换器Api
自定义类型转换器设计Api:
|-- interface TypeConverter
|-- class Default TypeConverter struts默认支持的类型转换器
|-- abstract class Struts TypeConverter 自定义类型转换器,继承这个类即可!
自定义类型转换器, 步骤:
1. 写一个转换器类: 继承Struts TypeConverter
2. 转换器文件
* 局部类型转换器 【给一个Action用】
文件名: ActionClassName-convertion.properties
注意:
Action名称与文件名称在同一个包下!
* 全局类型转换器 【所有的Action都可以用】
文件名: xwork-conversion.properties
注意:
src/ xwork-conversion.properties
局部类型转换器
1. MyDataConvert.java 转换器类
2. RegisterAction.java Action动作类
3. 在Action同包目录下,新建properties文件
文件名: RegisterAction-convertion.properties
public class RegisterAction extends ActionSupport {
// 封装请求数据
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String register() throws Exception {
System.out.println("user = " + user);
return super.execute();
}
}
public class MyDataConvert extends StrutsTypeConverter{
private DateFormat[] formats = {
new SimpleDateFormat("yyyy-MM-dd"),
new SimpleDateFormat("yyyyMMdd"),
new SimpleDateFormat("yyyy/MM/dd"),
new SimpleDateFormat("yyyy年MM月dd日")
};
public Object convertFromString(Map context, String[] values, Class toClass) {
// 判断: 数组如果为null,直接返回null
if (values == null || values.length == 0){
return null; // 不需要转换了
}
// 判断:提交的属性类型,如果不是日期类型,不需要转换
if (Date.class != toClass) {
return null;
}
// 循环
for (int i=0; i
try {
// 格式转换,转换成功,就直接返回!
Date birth = formats[i].parse(values[0]); // 字符串转换为日期
return birth;
} catch (ParseException e) {
continue;
}
}
return null;
}
@Override
public String convertToString(Map context, Object o) {
return null;
}
}
配置: RegisterAction-convertion.properties
内容:user.birth=cn.itcast.c_convert.MyDataConvert
全局类型转换器
修改文件名:
src/xwork-conversion.properties 所有的Action都会应用!
内容:
java.util.Date=cn.itcast.c_convert.MyDataConvert
思考:
Class Address{
String province;
String city;
}
如果jsp页面输入的地址格式是“广东,广州”, 需要转换为address对象,
例如转换器实现?
(加载局部、全局类型转换器:XworkConverter类中完成!)
4.跳转几种写法?
常用的跳转类型:
dispatcher 默认跳转类型是转发
chain 转发到Action (不能带参数!)
redirect 重定向
redirectAction 重定向到Action
类似于,
dispatcher:
request.getRequestDispatcher(“/index.jsp”).forward(request,response); 转发到页面
chain:
request.getRequestDispatcher(“/index.action”).forward(request,response);转发到action
redirect
response.sendRedirect( “/day30/index.jsp” ); 重定向到页面
redirectAction
response.sendRedirect( “/day30/index.action” ); 重定向到action
/index.jsp
5.模型驱动
ModelDriven
模型驱动的实现,用到模型驱动拦截器:
name="modelDriven"
class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"
/>
作用:
把请求表单的元素数据,自动填充到Action中的对象中!
使用步骤:
1. jsp页面
2. Action类,一定要实现ModelDriven接口!
用户名: 不用写对象属性名称了
密码:
生日:
public class UserAction extends ActionSupport implements ModelDriven{
private User user = new User();
// public void setUser(User user) { // 可以不用写set方法
// this.user = user;
// }
public User getUser() {
return user;
}
@Override
public User getModel() {
return user;
}
public String execute() throws Exception {
System.out.println("user " + user);
return "success";
}
}
模型驱动原理:查看ModelDrivenInterceptor模型驱动拦截器!
@Override
public String intercept(ActionInvocation invocation) throws Exception {
Object action = invocation.getAction();
if (action instanceof ModelDriven) {
ModelDriven modelDriven = (ModelDriven) action;
ValueStack stack = invocation.getStack();
Object model = modelDriven.getModel();
if (model != null) {
stack.push(model);
}
if (refreshModelBeforeResult) {
invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model));
}
}
return invocation.invoke();
}