struts2之token,类型转换和数据校验
1 Token防重
使用token防止重复提交
1.1 token内部原理
防止重复提交的方式常见的有两种:使用重定向和使用token
令牌完成
在struts2
框架中使用令牌基本上就是两步:
- 在
jsp
页面中使用<s:token></s:token>
标签,可以放在表单中任何位置,这个标签的作用就是在页面中产生一个token id
,可以通过查看源文件
的形式看到。为什么要放在表单中呢?因为这个是要提交到服务器的,要不然服务器怎么知道id是多少 - 在
struts2
核心配置文件中为token
拦截器添加参数,来指明需要拦截哪些方法
例如:<interceptor-ref name="token"><param name="includeMethods">save</param></interceptor-ref>
,指明拦截save
方法。当然也可以用excludeMethods
来声明不拦截哪些方法。
如果某个jsp
页面中有token
标签,那么无论是请求这个界面还是内部转发到这个界面,我们统一说成是渲染界面
的时候,都会造成token id
的产生或者更新。
1.2 实现步骤
1.2.1 在页面中添加<s:token/>标签
<form action="tokenAction.action" method="post">
<s:token></s:token>
用户名:<input type="text" name="user.userName"/><br>
密码:<input type="text" name="user.userPass"/><br>
<input type="submit" value="注册"/>
</form>
1.2.2 配置strtus.xml配置
在struts.xml
中配置token
拦截器和默认拦截器栈及验证失败的结果视图(invalid.token)
<action name="tokenAction" class="cn.test.action.TokenAction">
<result>/index.jsp</result>
<result name="invalid.token">/error.jsp</result>
<!-- 引入token拦截器 -->
<interceptor-ref name="token"></interceptor-ref>
<!-- 引入默认拦截器栈 -->
<interceptor-ref name="defaultStack"></interceptor-ref>
</action>
2 类型转换器
HTTP
参数都是字符串类型。 保存的数据可能是字符串、数字、布尔、日期时间等或者JavaBean
类型。 手工的类型转换,比如将字符串转换为日期,通过: 通过request.getParameter
方法获取字符串; 检查是否为空; 通过DateFormat.parse
方法将字符串转换为Date对象
2.1 Struts2类型转换
Struts2
内置的类型转换 :
String
和boolean
完成字符串与布尔值之间的转换String
和char
完成字符串与字符之间的转换String
和int
、Integer
完成字符串与整型之间的转换String
和Long
完成字符串与长整型值之间的转换String
和double
、Double
完成字符串与双精度浮点值的转换String
和Float
完成字符串和单精度浮点之间的转换String
和Date
完成字符串和日期类型之间的转换,日期格式使用格式用户请求所在Locale
的SHORT
格式String
和数组
在默认的情况,数组元素是字符串,如果用户定义类型转换器,也可以是其它复合数据类型
在访问struts2
中某个action
之后或者之前,会自动调用的类,就是struts2
中的拦截器,具有的最大特点就是实现了AOP
(面向切面编程),可插拔式的,也就是说它可以在需要使用的时候通过配置xml
文件来实现,而在不使用的时候又不会影响整个框架的效果,这让struts2
的拦截器具有非常好的扩展性
2.2 Struts2自定义类型转化器
需求:用户输入20160520
日期,如果Action
类的属性为Date
类型,则它不能够正确接收到这个时间值。
这时候需要自定义类型转化。
实现步骤
2.2.1 新建注册页面
<form action="studentAction.action" method="post">
姓名:<input type="text" name="student.studentName"><br>
性别:<input type="radio" name="student.studentSex" value="1">男<input type="radio" name="student.studentSex" value="0">女<br>
地址:<input type="text" name="student.studentAddress"><br>
生日:<input type="text" name="student.birthday">(yyyy/MM/dd)<br>
<input type="submit" value="注册"/>
</form>
2.2.2 编写自定义类型转换器
编写自定义类型转换器用于转换日期和业务逻辑Action
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import org.apache.struts2.util.StrutsTypeConverter;
public class DateConverter extends StrutsTypeConverter {
/**
* 将字符串类型转为目标类型
* 第一个参数:context代表上下文
* 第二个参数:params:用户提交的参数值-->request.getParameterValues()
* 第三个参数:toType要转换成的目标类型
*/
@Override
public Object convertFromString(Map context, String[] params, Class toType) {
String value = params[0];//获取输入的日期 1990/01/01
Date date=null;
if(toType==Date.class){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
try {
date = sdf.parse(value);
} catch (ParseException e) {
e.printStackTrace();
}
}
return date;
}
/**
* 将目标类型转换为字符串
*/
@Override
public String convertToString(Map arg0, Object arg1) {
// TODO Auto-generated method stub
return null;
}
}
2.2.3 业务逻辑action
import com.opensymphony.xwork2.ActionSupport;
/**
* 一旦出现跳转input结果视图,将不执行action中方法
* 导致出现input结果视图的原因有两个
* 1.类型转换失败
* 2.验证失败
*
*/
public class StudentAction extends ActionSupport {
private Student student;
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
@Override
public String execute() throws Exception {
System.out.println("新增了:"+student);
return this.SUCCESS;
}
}
2.2.4 配置自定义类型转换器
局部的类型转换器和全局的类型转换器
局部类型转换器
:只针对当前的action
中的属性进行转换,在action
同包下创建名称与action
同名的文件,命名方式为:actionClassName-conversion.properties
属性名称=类型转换器的全限定类名
student.birthday=cn.test.conversion.DateConverter全局类型转换器
:针对所有的action
中的指定类型进行转换,在src
下新建名称为xwork-conversion.properties
,其内容为
待转换的类型全限定类名=类型转换器的全限定类名
java.util.Date=cn.test.conversion.DateConverter
3 数据校验
3.1 使用硬编码校验
使用硬编码的方式实现数据校验(通过重写validate()
方法或validateXxx()
方法来实现)
3.1.1 业务逻辑Action
业务逻辑Action
需要继承ActionSupport
.重写validate()
方法:会针对Action
中所有的方法进行校验;validateXxx()
方法:Xxx
代表需要校验的方法名,只针对于Xxx
方法进行数据校验,在校验方法validate()
获取validateXxx()
中,判断校验规则,如果违反规则使用addFiledError
方法添加错误消息
import com.opensymphony.xwork2.ActionSupport;
public class UserAction extends ActionSupport {
private String userName;
private String userPass;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPass() {
return userPass;
}
public void setUserPass(String userPass) {
this.userPass = userPass;
}
/**
* 登录
* @return
* @throws Exception
*/
public String login() throws Exception {
System.out.println("执行了login方法....");
if("admin".equals(userName)&&"admin".equals(userPass)){
return this.SUCCESS;
}
return this.LOGIN;
}
/**
* 注册
* @return
* @throws Exception
*/
public String add() throws Exception {
System.out.println("执行了add方法....");
return this.SUCCESS;
}
/**
* 签名相同的方法:两个方法定义除方法名不同外,其他都相同。
* 重写ActionSupport中的validate()方法,
* 会针对action中所有的与execute具有相同签名的方法进行校验
*/
// @Override
// public void validate() {
// //用户名为空或用户名为空字符串
// if(userName==null||userName.trim().equals("")){
// this.addFieldError("userName", "用户名不能为空!");
// }
// if(userPass==null||userPass.trim().equals("")){
// this.addFieldError("userPass", "密码不能为空!");
// }
// }
/**
* validateXxx()方法:只针对Xxx方法进行校验,Xxx代表需要校验的方法名称(方法名的首字母需要大写)
*/
public void validateAdd() {
if(userName==null||userName.trim().equals("")){
this.addFieldError("userName", "用户名不能为空!");
}
if(userPass==null||userPass.trim().equals("")){
this.addFieldError("userPass", "密码不能为空!");
}
}
}
3.1.2 struts.xml
在struts.xml
中配置input
结果视图:无法通过校验规则时会跳转到input结果视图
<struts>
<package name="validation" extends="struts-default">
<global-allowed-methods>regex:.*</global-allowed-methods>
<action name="user-*-*" class="cn.test.action.UserAction" method="{1}">
<result name="success">/index.jsp</result>
<result name="input">/{2}.jsp</result>
</action>
</package>
</struts>
3.1.3 页面部分
在页面上使用<s:fielderror>
获取错误消息
Login.jsp
<body>
<s:fielderror></s:fielderror>
<form action="user-login-login.action" method="post">
用户名:<input type="text" name="userName"/><br>
密码:<input type="text" name="userPass"/><br>
<input type="submit" value="登录"/>
</form>
</body>
Add.jsp
<s:fielderror></s:fielderror>
<form action="user-add-add.action" method="post">
用户名:<input type="text" name="userName"/><br>
密码:<input type="text" name="userPass"/><br>
<input type="submit" value="注册"/>
</form>
导致Input结果视图出现的原因主要有两个
- 类型转换失败
- 数据校验失败
3.2 使用基于XML配置的方式完成数据校验
3.2.1 常用校验器
required
:必填校验器
<!-- Field Validator Syntax -->
<field name="username">
<field-validator type="required">
<message>username must not be null</message>
</field-validator>
</field>
requiredstring
:必填字符串校验器
常用属性:trim
类似于string
方法中trim()
可以去掉前后空格
<!-- Field-Validator Syntax -->
<field name="username">
<field-validator type="requiredstring">
<param name="trim">true</param>
<message>username is required</message>
</field-validator>
</field>
int
:整型校验器
常用属性:min
最小值,max
最大值
<field name="age">
<field-validator type="int">
<param name="min">20</param>
<param name="max">50</param>
<message>Age needs to be between ${min} and ${max}</message>
</field-validator>
</field>
double
:双精度浮点类型校验器
stringlength
:字符串长度校验器
常用属性:maxLength
最大长的 minLength
最小长度
<field name="myPurchaseCode">
<field-validator type="stringlength">
<param name="minLength">10</param>
<param name="maxLength">10</param>
<param name="trim">true</param>
<message>Your purchase code needs to be 10 characters long</message>
</field-validator>
</field>
email
校验器:电子邮件格式校验器
<field name="myEmail">
<field-validator type="email">
<message>Must provide a valid email</message>
</field-validator>
</field>
url
校验器:对网站进行格式校验
<!-- Field Validator Syntax -->
<field name="myHomepage">
<field-validator type="url">
<message>Invalid homepage url</message>
</field-validator>
</field>
regex
:正则校验器,支持正则表达式
常见的属性:regex
<!-- Field Validator Syntax -->
<field name="myStrangePostcode">
<field-validator type="regex">
<param name="regex"><![CDATA[([aAbBcCdD][123][eEfFgG][456])]]></param>
</field-validator>
</field>
3.2.2 action使用
在action
同包(同一级目录)下新建校验规则定义文件,其命名: ActionClassName-validation.xml
(action
中所有的方法都将采用其中定义的校验规则)或者ActionClass-ActionAliasName-validation.xml
UserAction-validation.xml
--->校验UserAction
中所有的方法
UserAction-user-doAdd-validation.xml
: 校验UserAciton
中doAdd
方法
<validators>
<field name="userName">
<!-- requiredstring:字符串必填校验器 -->
<field-validator type="requiredstring">
<!-- 错误提示信息 -->
<message>用户名不能为空!</message>
</field-validator>
<field-validator type="regex">
<param name="regex"><![CDATA[\w{8,}]]></param>
<message>用户名不合法!</message>
</field-validator>
</field>
<field name="userPass">
<!-- requiredstring:字符串必填校验器 -->
<field-validator type="requiredstring">
<!-- 错误提示信息 -->
<message>密码不能为空!</message>
</field-validator>
<field-validator type="regex">
<param name="regex"><![CDATA[\d{6}]]></param>
<message>密码不合法!</message>
</field-validator>
</field>
</validators>
3.2.3 页面部分
在页面上使用<s:fielderror>
获取验证提示信息
<html>
<head>
<base href="<%=basePath%>">
<title>注册登陆</title>
</head>
<body>
<s:fielderror></s:fielderror>
<form action="user2-doLogin.action" method="post">
用户名:<input type="text" name="userName"/><br>
密码:<input type="text" name="userPass"/><br>
<input type="submit" value="登陆">
</form>
</body>
</html>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了