一、概述
-
从一个 HTML 表单到一个 Action 对象,类型转换是从字符串到非字符串。
HTTP 没有 “类型” 的概念。每一项表单输入只可能是一个字符串或一个字符串数组。 在服务器端, 必须把 String 转换为特定的数据类型。 -
在 struts2 中,把请求参数映射到action属性的工作由Parameters拦截器负责,它是默认的defaultStack拦截器中的一员。 Parameters 拦截器可以自动完成字符串和基本数据类型之间转换。
二、类型转换错误
- 如果类型转换失败:
(1)若 Action 类没有实现 ValidationAware 接口: Struts 在遇到类型转换错误时仍会继续调用其 Action 方法,就好像什么都没发生一样。
(2)若 Action 类实现 ValidationAware 接口: Struts 在遇到类型转换错误时将不会继续调用其 Action 方法: Struts 将检查相关 action 元素的声明是否包含着一个 name=input 的 result。 如果有,Struts 将把控制权转交给那个 result 元素;若没有 input 结果,Struts 将抛出一个异常。
三、类型转换错误消息的定制
-
作为默认的 default 拦截器的一员, ConversionError 拦截器负责添加与类型转换有关的出错消息(前提: Action 类必须实现了 ValidationAware 接口)和保存各请求参数的原始值.
-
若字段标签使用的不是 simple 主题, 则非法输入字段将导致一条有着以下格式的出错消息:
Invalid field value for field "fieldName"
-
覆盖默认的出错消息
(1)在对应的 Action 类所在的包中新建 ActionClassName.properties 文件, ClassName 即为包含着输入字段的 Action 类的类名
Conversion类的实现:
package com.haiyang.struts2.app;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.DefaultActionInvocation;
import java.util.Date;
/**
* @author thy
* @create 2021-10-04 9:00
*/
public class ConversionAction extends ActionSupport {
private int age;
private Date birth;
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public String execute(){
System.out.println("age=" + age);
System.out.println("birth=" + birth);
return "success";
}
}
(2)在属性文件中添加如下键值对:
invalid.fieldvalue.age=年龄格式错误
- 定制出错消息的样式:
每一条出错消息都被打包在一个 HTML span 元素里, 可以通过覆盖其行标为 errorMessage 的那个 css 样式来改变出错消息的格式. - 显示错误消息: 如果是 simple 主题, 可以通过
<s:fielderror fieldName=“filedname”></s:fielderror>
标签显示错误消息
四、定制类型转换器
自定义类型转换器必须实现 ongl.TypeConverter 接口或对这个接口的某种具体实现做扩展
代码实现:
package com.haiyang.struts2.app.converters;
import org.apache.struts2.util.StrutsTypeConverter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
/**
* @author thy
* @create 2021-10-04 9:26
*/
public class DateConverter extends StrutsTypeConverter {
private DateFormat dateFormat;
public DateConverter(){
System.out.println("DateConverter's constructor...");
dateFormat = new SimpleDateFormat("yy-MM-dd hh:mm:ss");
}
@Override
public Object convertFromString(Map map, String[] strings, Class aClass) {
System.out.println("convertFromString");
if(aClass == Date.class){
if(strings != null && strings.length > 0){
String value = strings[0];
try {
return dateFormat.parseObject(value);
} catch (Exception e) {
e.printStackTrace();
}
}
}
//若没有转换成功, 则返回 values
return strings;
}
@Override
public String convertToString(Map map, Object o) {
System.out.println("convertToString");
if(o instanceof Date){
Date date = (Date) o;
return dateFormat.format(date);
}
//若转换失败返回 null
return null;
}
}
1、配置自定义的类型转换器
- 在应用程序里使用一个自定义的类型转换器之前, 必须先对它进行配置. 这种配置既可以基于字段, 也可以基于类型:
(1)基于字段配置: 可以为某个 Model(该 Model 类也可能是 Action) 的各个属性分别配置一个自定义的转换器.
1. 创建一个属性文件: ModelClassName-conversion.properties, 该文件需和相对应的 Model 类放在同一个目录下
2. 编辑属性文件:
field=转换器全类名
配置内容:
birth=com.haiyang.struts2.app.converters.DateConverter
扩展:
1.转换器类ConversionAction实现ModelDriven接口
package com.haiyang.struts2.app;
import com.haiyang.struts2.model.Customer;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.DefaultActionInvocation;
import com.opensymphony.xwork2.ModelDriven;
import java.util.Date;
/**
* @author thy
* @create 2021-10-04 9:00
*/
public class ConversionAction extends ActionSupport implements ModelDriven<Customer> {
public String execute(){
System.out.println("model: " + model);
return "success";
}
private Customer model;
@Override
public Customer getModel() {
model = new Customer();
return model;
}
}
2、Customer类的实现:
package com.haiyang.struts2.model;
import java.util.Date;
/**
* @author thy
* @create 2021-10-04 9:48
*/
public class Customer {
private int age;
private Date birth;
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "Customer{" +
"age=" + age +
", birth=" + birth +
'}';
}
}
3.在Customer类的同目录下创建配置文件:
配置文件内容:
birth=com.haiyang.struts2.app.converters.DateConverter
注:类型转换器是单实例的。
(2)基于类型配置:
1.在src 目录下创建 xwork-conversion.properties 文件。
2.在 xwork-conversion.properties 文件里把每一个需要进行类型转换的类与一个类型转换器关联起来。
java.util.Date=com.haiyang.struts2.app.converters.DateConverter
注:此方法在Struts2应用被加载前创建实例。
2、实现自定义的时间类型转换器:
(1)时间 pattern 需要以 web 应用的初始化参数配置在 web.xml 中 。
<context-param>
<param-name>pattern</param-name>
<param-value>yyyy-MM-dd hh:mm:ss</param-value>
</context-param>
(2)在转换器类中获取初始化参数。
package com.haiyang.struts2.app.converters;
import com.opensymphony.xwork2.ActionContext;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.util.StrutsTypeConverter;
import javax.servlet.ServletContext;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
/**
* @author thy
* @create 2021-10-04 9:26
*/
public class DateConverter extends StrutsTypeConverter {
private DateFormat dateFormat;
public DateConverter(){
System.out.println("DateConverter's constructor...");
}
public DateFormat getDateFormat(){
if(dateFormat == null){
//获取当前 WEB 应用的初始化参数 pattern
ServletContext servletContext = ServletActionContext.getServletContext();
System.out.println(servletContext);
String pattern = servletContext.getInitParameter("pattern");
dateFormat = new SimpleDateFormat(pattern);
}
return dateFormat;
}
@Override
public Object convertFromString(Map map, String[] strings, Class aClass) {
System.out.println("convertFromString");
if(aClass == Date.class){
if(strings != null && strings.length > 0){
String value = strings[0];
try {
return getDateFormat().parseObject(value);
} catch (Exception e) {
e.printStackTrace();
}
}
}
//若没有转换成功, 则返回 values
return strings;
}
@Override
public String convertToString(Map map, Object o) {
System.out.println("convertToString");
if(o instanceof Date){
Date date = (Date) o;
return getDateFormat().format(date);
}
//若转换失败返回 null
return null;
}
}
3、类型转换与复杂对象配合使用
form 标签的 name 属性可以被映射到一个属性的属性。
4、Struts 允许填充 Collection 里的对象, 常见于快速录入批量数据的场合
<%--
Created by IntelliJ IDEA.
User: haiyang
Date: 2021/10/4
Time: 16:04
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="<%=request.getScheme()
+ "://"
+ request.getServerName()
+ ":"
+ request.getServerPort()
+ request.getContextPath()
%>/scripts/jquery-1.4.2.js"></script>
<script type="text/javascript">
$(function(){
var count = 0;
$("#add").click(function(){
count++;
$("#button").before("<tr><td>Mgrs[" + count + "].Name:</td><td><input name='mgrs[" + count + "].name'/></td></tr>")
.before("<tr><td>Mgrs[" + count + "].Birth:</td><td><input name='mgrs[" + count + "].birth'/></td></tr>");
return false;
});
$("#remove").click(function(){
count--;
$("#button").prev("tr").remove();
$("#button").prev("tr").remove();
return false;
});
});
</script>
</head>
<body>
<form action="testConversion2.action">
<table>
<tbody>
<tr>
<td>Mgrs[0].Name:</td>
<td><input name="mgrs[0].name"/></td>
</tr>
<tr>
<td>Mgrs[0].Birth:</td>
<td><input name="mgrs[0].birth"/></td>
</tr>
<tr id="button">
<td><button id="add">新加一个</button></td>
<td><button id="remove">删除一个</button></td>
</tr>
<tr>
<td colspan="2" align="right">
<input type="submit" value="Submit"/>
</td>
</tr>
</tbody>
</table>
</form>
</body>
</html>
package com.haiyang.struts2.app;
import com.haiyang.struts2.model.Manager;
import com.opensymphony.xwork2.ActionSupport;
import java.util.Collection;
/**
* @author thy
* @create 2021-10-04 16:00
*/
public class TestCollectionAction extends ActionSupport {
private static final long serialVersionUID = 1L;
private Collection<Manager> mgrs = null;
public Collection<Manager> getMgrs() {
return mgrs;
}
public void setMgrs(Collection<Manager> mgrs) {
this.mgrs = mgrs;
}
public String execute() throws Exception {
System.out.println(mgrs);
return SUCCESS;
}
}