因为我们调用request.getParameter(“xx”)或request.getParameterValues(“xx”)来获取参数值,它们返回值类型是String和String[],可
能跟我们希望的类型不一致,这个时间就要完成类型转换。同时对象输出到html页面上时,也要完成对象转成String类型
struts2使用下面的XWorkBasicConverter类完成常见类型转换
package com.opensymphony.xwork2.conversion.impl;
import com.opensymphony.xwork2.XWorkConstants;
import com.opensymphony.xwork2.XWorkException;
import com.opensymphony.xwork2.conversion.TypeConverter;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.inject.Inject;
import java.lang.reflect.Member;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
public class XWorkBasicConverter extends DefaultTypeConverter {
private Container container;
@Inject
public void setContainer(Container container) {
this.container = container;
}
//该方法完成类型转换
@Override
public Object convertValue(Map<String, Object> context, Object o, Member member, String propertyName, Object value, Class toType) {
Object result = null;
if (value == null || toType.isAssignableFrom(value.getClass())) {
// no need to convert at all, right?
return value;
} i
f (toType == String.class) {
/* the code below has been disabled as it causes sideffects in Struts2 (XW-512)
// if input (value) is a number then use special conversion method (XW-490)
Class inputType = value.getClass();
if (Number.class.isAssignableFrom(inputType)) {
result = doConvertFromNumberToString(context, value, inputType);
if (result != null) {
return result;
}
}*/
// okay use default string conversion
result = doConvertToString(context, value);
} else if (toType == boolean.class) {
result = doConvertToBoolean(value);
} else if (toType == Boolean.class) {
result = doConvertToBoolean(value);
} else if (toType.isArray()) {
result = doConvertToArray(context, o, member, propertyName, value, toType);
} else if (Date.class.isAssignableFrom(toType)) {
result = doConvertToDate(context, value, toType);
} else if (Calendar.class.isAssignableFrom(toType)) {
result = doConvertToCalendar(context, value);
} else if (Collection.class.isAssignableFrom(toType)) {
result = doConvertToCollection(context, o, member, propertyName, value, toType);
} else if (toType == Character.class) {
result = doConvertToCharacter(value);
} else if (toType == char.class) {
result = doConvertToCharacter(value);
} else if (Number.class.isAssignableFrom(toType) || toType.isPrimitive()) {
result = doConvertToNumber(context, value, toType);
} else if (toType == Class.class) {
result = doConvertToClass(value);
} i
f (result == null) {
if (value instanceof Object[]) {
Object[] array = (Object[]) value;
if (array.length >= 1) {
value = array[0];
} else {
value = null;
} /
/ let's try to convert the first element only
result = convertValue(context, o, member, propertyName, value, toType);
} else if (!"".equals(value)) { // we've already tried the types we know
result = super.convertValue(context, value, toType);
} i
f (result == null && value != null && !"".equals(value)) {
throw new XWorkException("Cannot create type " + toType + " from value " + value);
}
} r
eturn result;
} .
............................
}
从
上面类中我们可以看到能完成的类型转换是:
String
boolean / Boolean
char / Character
int / Integer, float / Float, long / Long, double / Double
date - 使用当前请求绑定的 Locale相关的SHORT 日期格式
array - 假定每个字符串可以转换为数组指定的类型
collection - 如果不能确定集合中元素的类型, 那么被认为是 String并且创建一个ArrayList
Enumeration
BigDecimal和BigInteger
没有必要使用中间 String和原始类型. 相反, 框架读取和写入对象的属性 通过 OGNL表达式并执行适合的类型转换 .
下面是利用框架的类型转换能力提示:
比如我们在表单输入2,3,我们希望转换成一个Point对象
Point.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!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>Insert title here</title>
</head>
<body>
<s:form action="point">
<s:textfield name="p"></s:textfield>
<s:submit></s:submit>
</s:form>
</body>
</html>
package com.lgh.struts2maven.model;
import java.io.Serializable;
public class Point implements Serializable {
private static final long serialVersionUID = 1L;
private int x;
private int y;
public Point() {
// TODO Auto-generated constructor stub
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
package com.lgh.struts2maven.action;
import com.lgh.struts2maven.model.Point;
import com.opensymphony.xwork2.ActionSupport;
public class PointAction extends ActionSupport {
private Point p;
public PointAction() {
}
@Override
public String execute() throws Exception {
return SUCCESS;
}
public Point getP() {
return p;
}
public void setP(Point p) {
this.p = p;
}
}
<action name="point" class="com.lgh.struts2maven.action.PointAction"
method="execute">
<result name="success">/Point.jsp</result>
</action>
通过扩展StrutsTypeConverter类创建类型转换器. 转换器的作用是把一个 String转换为一个Object 并且把一个Object 转换为一个 String.
package com.lgh.struts2maven.converter;
import java.util.Map;
import org.apache.struts2.util.StrutsTypeConverter;
import com.lgh.struts2maven.model.Point;
public class PointConverter extends StrutsTypeConverter {
public PointConverter() {
// TODO Auto-generated constructor stub
}
/** * 客户端传递过来的值 转换成对象 * values 客户端传递过来的值 * */
@Override
public Object convertFromString(Map context, String[] values, Class toClass) {
String s = values[0];
String[] strs = s.split(",");
Point p = new Point();
p.setX(Integer.parseInt(strs[0]));
p.setY(Integer.parseInt(strs[1]));
return p;
}
// 把对象转换成字符串
@Override
public String convertToString(Map context, Object o) {
if(o instanceof Point){
Point point = (Point)o;
return "("+point.getX() +" , " + point.getY()+")";
}
return null;
}
}
创建一个名字为 ‘ActionClassName-conversion.properties’ 文件,并它放置到该Action类所在classpath路径中.
例如. 如果action类名字为MyAction, 那么action-层次的转换属性文件命名为’MyAction-conversion.properties’. 如果action的包为com.myapp.actions,那么转换文件应该放置在classpath 路径下的 /com/myapp/actions/.
PointAction-conversion.properties:
#p action类的属性名
p=com.lgh.struts2maven.converter.PointConverter
类型转换适合应用在你需要把一个 String 转换为一个复杂的对象. 因为web 是无类型(都是 string 在HTTP协议), Struts 2 的类型转换特性非常有用. 例如, 如果你提示用户输入一个坐标以 string形式 (例如 “3, 22”), 你可以让 Struts 2 做从 String 到 Point 和 从Point到String的转化.
使用该”point” 示例, 如果你的action (或另外一个符合对象中有一个point对象) 有一个相关联的 ClassName-conversion.properties文件, Struts 2 将使用该配置的转换器来 从和向 string转换. 因此 “3, 22” 转为一个 Point(3, 22) 仅仅添加如下的 ClassName-conversion.properties (注意PointConverter要实现TypeConverter 接口):
p=com.lgh.struts2maven.converter.PointConverter
你的类型转换器应该检查 需要转换的类型. 因为这需要在从和向string中使用, 你需要分割转换为两部分: 一部分把String转换为 Point, 而另外一部分把Point转换为String.
完成上述步骤后, 你可以引用point (使用在 JSP或 ${point}在FreeMarker) 并且它将输出 “3, 22” . 因而, 如果你把它传回到action, 它将再次被转为 Point.
某些情况下你可以希望在全局范围内使用该类型转换器 . 这可以通过在类路径的根目录中编辑 xwork-conversion.properties (通常在WEB-INF/classes) 并把你要转换类的名字写在左边而转换器类写在右边. 例如, 为所有Point 对象添加转换器 :
在src新建:xworker-coversion.properties文件
com.lgh.struts2maven.model.Point=com.lgh.struts2maven.converter.PointConverter
Null 属性处理将自动创建对象当遇到 null引用.
下面是用来处理 null引用的规则:
如果属性被声明为 Map, 那么将返回一个 HashMap 并它赋给 null引用的属性.
输入 null 属性是一个简单的bean 并且有一个无参的构造函数,仅仅使用 {@link ObjectFactory#buildBean(java.lang.Class, java.util.Map)} 方法来创建.
Collection和Map 支持提供了智能的 null 处理和类型转换对 Java 集合.
框架提供发现集合中元素类型的机制 . 该机制是通过一个 ObjectTypeDeterminer来完成. 框架提供了该接口的默认实现.在DefaultObjectTypeDeterminer类 Javadoc解释了Map和Collection 支持如何发现类型.
ObjectTypeDeterminer 查找 Class-conversion.properties 文件中表明在 Map和 Collection中存放的对象类型的条目. 对于Collection, 例如 List,使用模式 Element_xxx,来指定元素,其中 xxx是在你的 action 或对象中集合类型的属性的名字。 对于Map, key 和value都通过模式 Key_xxx 和 Element_xxx来分别指定.
通过传递某个给定元素的属性值来获取某个元素是可以的. 默认情况下, 集合元素属性由在 Class-conversion.properties文件使用 KeyProperty_xxx=yyy定义, 其中 xxx 是 bean 类 而 yyy 是我们需要建索引的集合元素.
Book
package com.lgh.struts2maven.model;
import java.io.Serializable;
public class Book implements Serializable {
private int id;
private String name;
private String ISBN;
public Book() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getISBN() {
return ISBN;
}
public void setISBN(String iSBN) {
ISBN = iSBN;
}
}
界面:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib uri="/struts-tags" prefix="s" %>
<!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>Insert title here</title>
</head>
<body>
<form action="addList.action">
<table>
<tr>
<td> name </td>
<td> ISBN</td>
</tr>
<tr>
<td><input type="text" name="books[0].name"></td>
<td><input type="text" name="books[0].ISBN"></td>
</tr>
<tr>
<td><input type="text" name="books[1].name"></td>
<td><input type="text" name="books[1].ISBN"></td>
</tr>
<tr>
<td><input type="text" name="books[2].name"></td>
<td><input type="text" name="books[2].ISBN"></td>
</tr>
<tr>
<td colspan="2"><input type="submit"></td>
</tr>
</table>
</form>
</body>
</html>
Action
package com.lgh.struts2maven.action;
import java.util.List;
import com.lgh.struts2maven.model.Book;
import com.opensymphony.xwork2.ActionSupport;
public class BookListAction extends ActionSupport {
private List books;
public List getBooks() {
return books;
}
public void setBooks(List books) {
this.books = books;
}
@Override
public String execute() throws Exception {
System.out.println(books);
return SUCCESS;
}
}
配置转换
在该项目中,如果我们的list集合指定了泛型,那么我们就不必在创建下面的配置文件了
在BookListAction-conversion.properties中配置:
Element_books=com.lgh.struts2maven.model.Book
映射
<action name="addList" class="com.lgh.struts2maven.action.BookListAction"
method="execute">
<result name="success">/showBookList.jsp</result>
</action>
showBookList.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!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>Insert title here</title>
</head>
<body>
<h2>hello struts2</h2>
<s:debug></s:debug>
<s:iterator value="books">
<s:property value="name"/> ------<s:property value="ISBN"/><br>
</s:iterator>
</body>
</html>
bookset.jsp
不像 Map 和 List 元素属性, 如果fooCollection(22) 不存在, 它将会被创建. 如果你需要创建, 请使用 fooCollection.makeNew[index]标记,其中index 是一个整数 0, 1等等. 因而, 参数值对 fooCollection.makeNew[0]=Phil 和 fooCollection.makeNew[1]=John 将添加两个新的 Foo 对象到fooCollection – 其中一个 name 属性值为Phil 而另外一个 name 属性值为 John. 然而, 在使用Set的情况下, equals 和 hashCode methods 需要重载以便它们不仅仅只包含 id 属性. 否则, one element of the null id properties Foos 将被从集合中删除.
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib uri="/struts-tags" prefix="s" %>
<!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>Insert title here</title>
</head>
<body>
<form action="addSet.action">
<table>
<tr>
<td> name </td>
<td> ISBN</td>
</tr>
<tr>
<td><input type="text" name="books.makeNew[0].name"></td>
<td><input type="text" name="books.makeNew[0].ISBN"></td>
</tr>
<tr>
<td><input type="text" name="books.makeNew[1].name"></td>
<td><input type="text" name="books.makeNew[1].ISBN"></td>
</tr>
<tr>
<td><input type="text" name="books.makeNew[2].name"></td>
<td><input type="text" name="books.makeNew[2].ISBN"></td>
</tr>
<tr>
<td colspan="2"><input type="submit"></td>
</tr>
</table>
</form>
</body>
</html>
BookSetAction.java
package com.lgh.struts2maven.action;
import java.util.HashSet;
import java.util.Set;
import com.lgh.struts2maven.model.Book;
import com.opensymphony.xwork2.ActionSupport;
public class BookSetAction extends ActionSupport {
private Set<Book> books = new HashSet<Book>();
//这里我手动new了一个set,我在测试时,发现没有手动创建set的话,
//在该版本中,struts2无法自动帮我们创建set对象
public Set<Book> getBooks() {
return books;
}
public void setBooks(Set<Book> books) {
this.books = books;
}
@Override
public String execute() throws Exception {
System.out.println(books);
return SUCCESS;
}
}
配置转换
对于set和map 即使使用了泛型,我们也要配置一下文件
在BookSetAction-conversion.properties中配置:
CreateIfNull_books=true
KeyProperty_books=id
Element_books=com.lgh.struts2maven.model.Book
映射
<action name="addSet" class="com.lgh.struts2maven.action.BookSetAction"
method="execute">
<result name="success">/showBookSet.jsp</result>
</action>
showBookSet.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!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>Insert title here</title>
</head>
<body>
<h2>hello struts2</h2>
<s:debug></s:debug>
<s:iterator value="books">
<s:property value="name"/> ------<s:property value="ISBN"/><br>
</s:iterator>
</body>
</html>
测试与list相同
界面:
bookmap.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib uri="/struts-tags" prefix="s" %>
<!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>Insert title here</title>
</head>
<body>
<form action="addMap.action">
<table>
<tr>
<td> name </td>
<td> ISBN</td>
</tr>
<tr>
<td><input type="text" name="books['b0'].name"></td>
<td><input type="text" name="books['b0'].ISBN"></td>
</tr>
<tr>
<td><input type="text" name="books['b1'].name"></td>
<td><input type="text" name="books['b1'].ISBN"></td>
</tr>
<tr>
<td><input type="text" name="books['b2'].name"></td>
<td><input type="text" name="books['b2'].ISBN"></td>
</tr>
<tr>
<td colspan="2"><input type="submit"></td>
</tr>
</table>
</form>
</body>
</html>
Action
package com.lgh.struts2maven.action;
import java.util.Map;
import com.lgh.struts2maven.model.Book;
import com.opensymphony.xwork2.ActionSupport;
public class BookMapAction extends ActionSupport {
private Map<String,Book> books ;
public Map<String, Book> getBooks() {
return books;
}
public void setBooks(Map<String, Book> books) {
this.books = books;
}
@Override
public String execute() throws Exception {
System.out.println(books);
return SUCCESS;
}
}
配置转换
BookMapAction-conversion.properties:
CreateIfNull_books=true
KeyProperty_books=id
Element_books=com.lgh.struts2maven.model.Book
映射
<action name="addMap" class="com.lgh.struts2maven.action.BookMapAction"
method="execute">
<result name="success">/showBookMap.jsp</result>
</action>
showBookMap.jsp
对于map遍历,每一项都是Entry类型
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!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>Insert title here</title>
</head>
<body>
<h2>hello struts2</h2>
<s:debug></s:debug>
<s:iterator value="books">
<s:property value="value.name"/> ------<s:property value="value.ISBN"/><br>
</s:iterator>
</body>
</html>
测试与list一样,这里就不写了
类型转换错误处理提供了一个简单的方式来区分 输入验证 问题和 输入 类型转换 问题.
任何类型转换错误可能或不希望报告 。例如, 报告输入 “abc” 不能够转换为数字 将是重要的.另一方面, 报告一个空字符串 “”,不能转换为一个数字将不重要 - 特别是在web环境,区分木有输入值和输入了空值是十分困难的.
默认情况下, 所有的转换错误使用i18n key xwork.default.invalid.fieldvalue来报告, 你可以在全局使用i18n文件中覆盖它 (默认的文字为 Invalid field value for field “xxx”, xxx 为字段的名字).
但是某些情况下, 你可能希望基于字段来覆盖该提示消息 . 你可以通过在跟你的action关联的 i18n 文件 (Action.properties) 文件中使用 invalid.fieldvalue.xxx, xxx 是字段名称.
注意任何一种错误并不是直接报告出来. 相反, 他们被添加到在ActionContext中一个名称为 conversionErrorsmap . 这里有几种方式可以访问该错误 t.
有两种产生错误报告的方法:
全局地, 使用转化错误拦截器
基于每字段的, 使用 转换验证器 validator
一些属性不能够赋值为null. 原始类型例如boolean和int不能够为 null. 如果你的 action需要或接受 null 或blank 值, 使用包装类 Boolean 和Integer. 同样, 空字符串 “” 不能为原始类型赋值. 在赋值的过程中, 空字符串也不能为BigDecimal或BigInteger赋值. 使用服务器端验证来避免使用无效数值为属性赋值 (或合理处理转换错误).