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内置的类型转换 :

  • Stringboolean 完成字符串与布尔值之间的转换
  • Stringchar 完成字符串与字符之间的转换
  • StringintInteger 完成字符串与整型之间的转换
  • StringLong 完成字符串与长整型值之间的转换
  • StringdoubleDouble 完成字符串与双精度浮点值的转换
  • StringFloat 完成字符串和单精度浮点之间的转换
  • StringDate 完成字符串和日期类型之间的转换,日期格式使用格式用户请求所在LocaleSHORT格式
  • 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: 校验UserAcitondoAdd方法

<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>
posted @ 2021-09-25 21:52  上善若泪  阅读(152)  评论(0编辑  收藏  举报