Struts2学习(七)—类型转化

为什么要转换

因为我们调用request.getParameter(“xx”)或request.getParameterValues(“xx”)来获取参数值,它们返回值类型是String和String[],可
能跟我们希望的类型不一致,这个时间就要完成类型转换。同时对象输出到html页面上时,也要完成对象转成String类型

Struts2能自动完成的类型转换

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表达式并执行适合的类型转换 .

下面是利用框架的类型转换能力提示:

  • 使用OGNL表达式 - 框架将自动负责为你 创建真正对象.
  • 使用JavaBean! 框架只能创建 遵守JavaBean规范的对象, 提供无参构造函数并包含 getter和setter .
  • 记住 person.name 将调用getPerson().setName(). 如果框架帮你创建Person对象, 记住 setPerson 方法必须提供.
  • 框架将不再为你实例化对象如果对象已经存在 .PrepareInterceptor 或action的构造函数可以用来创建目标对象在类型转换前 .
  • 对于 list和map, 使用索引标记 , 例如people[0].name 或friends[‘patrick’].name. 通常这些表单元素嵌套在循环中 . 对于JSP标签, 使用迭代标签的 status属性. 对于 FreeMarker标签, 访问该属性使用${foo_index}[].
  • 对于多选框 , 不可能使用索引标记来命名每项 . 相反,使用 people.name命名并且 框架理解需要为每个选中的项创建一个Person对象 并赋值.

自定义类型转换器

需求

比如我们在表单输入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>

编写Javabean接受输入

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;
    }

}

编写PointAction

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;
    }

}

应用转换器到一个Action

创建一个名字为 ‘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引用.
下面是用来处理 null引用的规则:

  • 如果属性被声明为 Collection或List, 那么将返回一个 ArrayList 并它赋给 null引用的属性.
  • 如果属性被声明为 Map, 那么将返回一个 HashMap 并它赋给 null引用的属性.

  • 输入 null 属性是一个简单的bean 并且有一个无参的构造函数,仅仅使用 {@link ObjectFactory#buildBean(java.lang.Class, java.util.Map)} 方法来创建.

Collection 和 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 是我们需要建索引的集合元素.

List类型转换

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>

测试:
Struts2学习(七)—类型转化_第1张图片
Struts2学习(七)—类型转化_第2张图片

set类型

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相同

map类型转换

界面:
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 和 “空”值

一些属性不能够赋值为null. 原始类型例如boolean和int不能够为 null. 如果你的 action需要或接受 null 或blank 值, 使用包装类 Boolean 和Integer. 同样, 空字符串 “” 不能为原始类型赋值. 在赋值的过程中, 空字符串也不能为BigDecimal或BigInteger赋值. 使用服务器端验证来避免使用无效数值为属性赋值 (或合理处理转换错误).

你可能感兴趣的:(struts2.0)