1. 程式人生 > >Struts2中的型別轉換

Struts2中的型別轉換

一、在 struts2中,對常用的資料型別已經自動進行了型別轉換工作。

DefaultTypeConverter裡面已經處理了String向其他基本型別的轉化工作。

/**
 * Default type conversion. Converts among numeric types and also strings.  Contains the basic 
 * type mapping code from OGNL.
 * 
 * @author Luke Blanshard ([email protected])
 * @author Drew Davidson ([email protected]
) */ public abstract class DefaultTypeConverter implements TypeConverter { protected static String MILLISECOND_FORMAT = ".SSS"; private static final String NULL_STRING = "null"; private static final Map<Class, Object> primitiveDefaults; private Container container; static { Map<Class, Object> map = new HashMap<>(); map.put(Boolean.TYPE, Boolean.FALSE); map.put(Byte.TYPE, Byte.valueOf((byte) 0)); map.put(Short.TYPE, Short.valueOf((short) 0)); map.put(Character.TYPE, new Character((char) 0)); map.put(Integer.TYPE, Integer.valueOf(0)); map.put(Long.TYPE, Long.valueOf(0L)); map.put(Float.TYPE, new Float(0.0f)); map.put(Double.TYPE, new Double(0.0)); map.put(BigInteger.class, new BigInteger("0")); map.put(BigDecimal.class, new BigDecimal(0.0)); primitiveDefaults = Collections.unmodifiableMap(map); } @Inject public void setContainer(Container container) { this.container = container; } public Object convertValue(Map<String, Object> context, Object value, Class toType) { return convertValue(value, toType); } public Object convertValue(Map<String, Object> context, Object target, Member member, String propertyName, Object value, Class toType) { return convertValue(context, value, toType); } public TypeConverter getTypeConverter( Map<String, Object> context ) { Object obj = context.get(TypeConverter.TYPE_CONVERTER_CONTEXT_KEY); if (obj instanceof TypeConverter) { return (TypeConverter) obj; // for backwards-compatibility } else if (obj instanceof ognl.TypeConverter) { return new XWorkTypeConverterWrapper((ognl.TypeConverter) obj); } return null; } /** * Returns the value converted numerically to the given class type * * This method also detects when arrays are being converted and converts the * components of one array to the type of the other. * * @param value * an object to be converted to the given type * @param toType * class type to be converted to * @return converted value of the type given, or value if the value cannot * be converted to the given type. */ public Object convertValue(Object value, Class toType) { Object result = null; if (value != null) { /* If array -> array then convert components of array individually */ if (value.getClass().isArray() && toType.isArray()) { Class componentType = toType.getComponentType(); result = Array.newInstance(componentType, Array .getLength(value)); for (int i = 0, icount = Array.getLength(value); i < icount; i++) { Array.set(result, i, convertValue(Array.get(value, i), componentType)); } } else { if ((toType == Integer.class) || (toType == Integer.TYPE)) result = (int) longValue(value); if ((toType == Double.class) || (toType == Double.TYPE)) result = doubleValue(value); if ((toType == Boolean.class) || (toType == Boolean.TYPE)) result = booleanValue(value) ? Boolean.TRUE : Boolean.FALSE; if ((toType == Byte.class) || (toType == Byte.TYPE)) result = (byte) longValue(value); if ((toType == Character.class) || (toType == Character.TYPE)) result = (char) longValue(value); if ((toType == Short.class) || (toType == Short.TYPE)) result = (short) longValue(value); if ((toType == Long.class) || (toType == Long.TYPE)) result = longValue(value); if ((toType == Float.class) || (toType == Float.TYPE)) result = new Float(doubleValue(value)); if (toType == BigInteger.class) result = bigIntValue(value); if (toType == BigDecimal.class) result = bigDecValue(value); if (toType == String.class) result = stringValue(value); if (Enum.class.isAssignableFrom(toType)) result = enumValue(toType, value); } } else { if (toType.isPrimitive()) { result = primitiveDefaults.get(toType); } } return result; } /** * Evaluates the given object as a boolean: if it is a Boolean object, it's * easy; if it's a Number or a Character, returns true for non-zero objects; * and otherwise returns true for non-null objects. * * @param value * an object to interpret as a boolean * @return the boolean value implied by the given object */ public static boolean booleanValue(Object value) { if (value == null) return false; Class c = value.getClass(); if (c == Boolean.class) return (Boolean) value; // if ( c == String.class ) // return ((String)value).length() > 0; if (c == Character.class) return (Character) value != 0; if (value instanceof Number) return ((Number) value).doubleValue() != 0; return true; // non-null } public Enum<?> enumValue(Class toClass, Object o) { Enum<?> result = null; if (o == null) { result = null; } else if (o instanceof String[]) { result = Enum.valueOf(toClass, ((String[]) o)[0]); } else if (o instanceof String) { result = Enum.valueOf(toClass, (String) o); } return result; } /** * Evaluates the given object as a long integer. * * @param value * an object to interpret as a long integer * @return the long integer value implied by the given object * @throws NumberFormatException * if the given object can't be understood as a long integer */ public static long longValue(Object value) throws NumberFormatException { if (value == null) return 0L; Class c = value.getClass(); if (c.getSuperclass() == Number.class) return ((Number) value).longValue(); if (c == Boolean.class) return (Boolean) value ? 1 : 0; if (c == Character.class) return (Character) value; return Long.parseLong(stringValue(value, true)); } /** * Evaluates the given object as a double-precision floating-point number. * * @param value * an object to interpret as a double * @return the double value implied by the given object * @throws NumberFormatException * if the given object can't be understood as a double */ public static double doubleValue(Object value) throws NumberFormatException { if (value == null) return 0.0; Class c = value.getClass(); if (c.getSuperclass() == Number.class) return ((Number) value).doubleValue(); if (c == Boolean.class) return (Boolean) value ? 1 : 0; if (c == Character.class) return (Character) value; String s = stringValue(value, true); return (s.length() == 0) ? 0.0 : Double.parseDouble(s); /* * For 1.1 parseDouble() is not available */ // return Double.valueOf( value.toString() ).doubleValue(); } /** * Evaluates the given object as a BigInteger. * * @param value * an object to interpret as a BigInteger * @return the BigInteger value implied by the given object * @throws NumberFormatException * if the given object can't be understood as a BigInteger */ public static BigInteger bigIntValue(Object value) throws NumberFormatException { if (value == null) return BigInteger.valueOf(0L); Class c = value.getClass(); if (c == BigInteger.class) return (BigInteger) value; if (c == BigDecimal.class) return ((BigDecimal) value).toBigInteger(); if (c.getSuperclass() == Number.class) return BigInteger.valueOf(((Number) value).longValue()); if (c == Boolean.class) return BigInteger.valueOf((Boolean) value ? 1 : 0); if (c == Character.class) return BigInteger.valueOf(((Character) value).charValue()); return new BigInteger(stringValue(value, true)); } /** * Evaluates the given object as a BigDecimal. * * @param value * an object to interpret as a BigDecimal * @return the BigDecimal value implied by the given object * @throws NumberFormatException * if the given object can't be understood as a BigDecimal */ public static BigDecimal bigDecValue(Object value) throws NumberFormatException { if (value == null) return BigDecimal.valueOf(0L); Class c = value.getClass(); if (c == BigDecimal.class) return (BigDecimal) value; if (c == BigInteger.class) return new BigDecimal((BigInteger) value); if (c.getSuperclass() == Number.class) return new BigDecimal(((Number) value).doubleValue()); if (c == Boolean.class) return BigDecimal.valueOf((Boolean) value ? 1 : 0); if (c == Character.class) return BigDecimal.valueOf(((Character) value).charValue()); return new BigDecimal(stringValue(value, true)); } /** * Evaluates the given object as a String and trims it if the trim flag is * true. * * @param value * an object to interpret as a String * @param trim * trims the result if true * @return the String value implied by the given object as returned by the * toString() method, or "null" if the object is null. */ public static String stringValue(Object value, boolean trim) { String result; if (value == null) { result = NULL_STRING; } else { result = value.toString(); if (trim) { result = result.trim(); } } return result; } /** * Evaluates the given object as a String. * * @param value * an object to interpret as a String * @return the String value implied by the given object as returned by the * toString() method, or "null" if the object is null. */ public static String stringValue(Object value) { return stringValue(value, false); } protected Locale getLocale(Map<String, Object> context) { Locale locale = null; if (context != null) { locale = (Locale) context.get(ActionContext.LOCALE); } if (locale == null) { LocaleProviderFactory localeProviderFactory = container.getInstance(LocaleProviderFactory.class); locale = localeProviderFactory.createLocaleProvider().getLocale(); } return locale; } }

 但是我們還可以生成更加複雜的物件,比如Collection或者Map的例項。

input.jsp

<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<%@taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title>直接封裝成Map</title>
</head>
<body>
<h3>直接封裝成Map</h3>
<s:form action="login">
	<s:textfield name="users['one'].name" label="第one個使用者名稱"/>
	<s:textfield name="users['one'].pass" label="第one個密碼"/>
	<s:textfield name="users['two'].name" label="第two個使用者名稱"/>
	<s:textfield name="users['two'].pass" label="第two個密碼"/>
	<tr>
		<td colspan="2"><s:submit value="轉換" theme="simple"/>
		<s:reset value="重填" theme="simple"/></td>
	</tr>
</s:form>
</body>
</html>

welcome.jsp

<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<%@taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title>轉換結果</title>
</head>
<body>
	<s:actionmessage/>
	key為one的使用者名稱為:<s:property value="users['one'].name"/><br/>
	key為one的密碼為:<s:property value="users['one'].pass"/><br/>
	key為two的使用者名稱為:<s:property value="users['two'].name"/><br/>
	key為two的密碼為:<s:property value="users['two'].pass"/><br/>
</body>
</html>

struts.xml 

<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
	"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<!-- 亂碼解決    預設utf-8 是i18n(1 2 3 的1 internationalization中間18個單詞)  不是il8n -->
	<constant name="struts.i18n.encoding" value="GBK"></constant>
	<package name="lee" extends="struts-default">
		<action name="login" class="org.crazyit.app.action.LoginAction">
			<result>/WEB-INF/content/welcome.jsp</result>
			<result name="error">/WEB-INF/content/welcome.jsp</result>
		</action>
		<action name="*">
			<result>/WEB-INF/content/{1}.jsp</result>		
		</action>
	</package>
</struts>

 Action處理類


import com.opensymphony.xwork2.ActionSupport;
import java.util.Map;
import org.crazyit.app.domain.*;
public class LoginAction extends ActionSupport{
	// Action類裡包含一個Map型別的成員變數
	// Map的value型別為User型別
	private Map<String , User> users;

	// users的setter和getter方法
	public void setUsers(Map<String , User> users){
		this.users = users;
	}
	public Map<String , User> getUsers(){
		return this.users;
	}

	public String execute() throws Exception{
		// 在控制檯輸出Struts 2封裝產生的Map物件
		System.out.println(getUsers());
		// 根據Map集合中key為one的User例項來決定控制邏輯
		if (getUsers().get("one").getName().equals("張三")
			&& getUsers().get("one").getPass().equals("123456") )
		{
			addActionMessage("登入成功!");
			return SUCCESS;
		}
		addActionMessage("登入失敗!!");
		return ERROR;
	}
}
public class User{
	private String name;
	private String pass;

	// name的setter和getter方法
	public void setName(String name){
		this.name = name;
	}
	public String getName(){
		return this.name;
	}

	// pass的setter和getter方法
	public void setPass(String pass){
		this.pass = pass;
	}
	public String getPass(){
		return this.pass;
	}
	@Override
	public String toString() {
		return "User [name=" + name + ", pass=" + pass + "]";
	}
}

上面生成了一個Map物件,程式必須使用泛型,同樣的如果想把Map改成List<User>,只需要把上面的users['one'].name改成users[下標].name 即可。

如果我不用泛型要怎麼辦,這個時候就可以指定集合元素型別

只需要一個區域性型別轉換檔案即可,下面用List來演示。

區域性型別轉換檔案:

命名:ActionName-conversion.properties  ActionName時需要Action的類名,後面的固定。

位置:和Action類檔案相同的位置。

 配置檔案寫法:

Element_<ListPropName>=<ElementType>    <ListPropName>替換成Listj集合屬性的名稱,<ElementType> 替換成集合元素型別。

LoginAction-conversion.properties

Element_users=org.crazyit.app.domain.User

Map集合需要寫兩個:

1)指定key

Key_<MapPropName>=<keyType>     <MapPropName>時Map型別的屬性,<keyType>Map key值的全限定類名。

2)指定value

Element_<MapPropName>=<ValueType>   <MapPropName>時Map型別的屬性,<ValueType>Map ValueType值的全限定類名。

比如

Key_users=java.lang.String
Element_users=org.crazyit.app.domain.User

 

 

 

struts.xml

<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
	"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<!-- 亂碼解決    預設utf-8 是i18n(1 2 3 的1 internationalization中間18個單詞)  不是il8n -->
	<constant name="struts.i18n.encoding" value="GBK"></constant>
	<package name="lee" extends="struts-default">
		<action name="login" class="org.crazyit.app.action.LoginAction">
			<result>/WEB-INF/content/welcome.jsp</result>
			<result name="error">/WEB-INF/content/welcome.jsp</result>
		</action>
		<action name="*">
			<result>/WEB-INF/content/{1}.jsp</result>		
		</action>
	</package>
</struts>

Action類

import com.opensymphony.xwork2.ActionSupport;
import java.util.List;

import org.crazyit.app.domain.*;
public class LoginAction extends ActionSupport{
	// Action類裡包含一個不帶泛型的List型別的成員變數
	private List users;

	// users的setter和getter方法
	public void setUsers(List users){
		this.users = users;
	}
	public List getUsers(){
		return this.users;
	}

	public String execute() throws Exception{
		// 在控制檯輸出Struts 2封裝產生的List物件
		System.out.println(getUsers());
		// 因為沒有使用泛型,所以要進行強制型別轉換
		User firstUser = (User)getUsers().get(0);
		// users屬性的第一個User例項來決定控制邏輯
		if (firstUser.getName().equals("張三")
			&& firstUser.getPass().equals("123456") )
		{
			addActionMessage("登入成功!");
			return SUCCESS;
		}
		addActionMessage("登入失敗!!");
		return ERROR;
	}
}
public class User{
	private String name;
	private String pass;

	//name屬性的setter和getter方法
	public void setName(String name){
		this.name = name;
	}
	public String getName(){
		return this.name;
	}

	//pass屬性的setter和getter方法
	public void setPass(String pass){
		this.pass = pass;
	}
	public String getPass(){
		return this.pass;
	}
	@Override
	public String toString() {
		return "User [name=" + name + ", pass=" + pass + "]";
	}
	
}

input.jsp 

<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<%@taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title>直接封裝成List</title>
</head>
<body>
<h3>直接封裝成List</h3>
<s:form action="login">
	<s:textfield name="users[0].name" label="第一個使用者名稱"/>
	<s:textfield name="users[0].pass" label="第一個密碼"/>
	<s:textfield name="users[1].name" label="第二個使用者名稱"/>
	<s:textfield name="users[1].pass" label="第二個密碼"/>
	<tr>
		<td colspan="2"><s:submit value="轉換" theme="simple"/>
		<s:reset value="重填" theme="simple"/></td>
	</tr>
</s:form>
</body>
</html>

welcome.jsp 

<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<%@taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title>轉換結果</title>
</head>
<body>
	<s:actionmessage/>
第一個User例項的使用者名稱為:<s:property value="users[0].name"/><br/>
第一個User例項的密碼為:<s:property value="users[0].pass"/><br/>
第二個User例項的使用者名稱為:<s:property value="users[1].name"/><br/>
第二個User例項的密碼為:<s:property value="users[1].pass"/><br/>
</body>
</html>

甚至可以處理Set集合,但是需要注意的是Set集合裡的元素必須有一個唯一標識

 Action類

import com.opensymphony.xwork2.*;
import java.util.Date;
import java.util.Set;
public class LoginAction extends ActionSupport{
	private Set users;
	private Date birth;
	// users的setter和getter方法
	public void setUsers(Set users){
		this.users = users;
	}
	public Set getUsers(){
		return this.users;
	}
	// birth的setter和getter方法
	public void setBirth(Date birth){
		this.birth = birth;
	}
	public Date getBirth(){
		return this.birth;
	}
	// 沒有提供execute()方法,
	// 將直接使用ActionSupport的execute()方法
}

 型別轉換器

import java.util.*;
import org.apache.struts2.util.StrutsTypeConverter;

import org.crazyit.app.domain.*;
public class UserConverter extends StrutsTypeConverter{
	public Object convertFromString(Map context, String[] values, Class toClass){
		Set result = new HashSet();
		for (int i = 0; i < values.length ; i++ ){
			// 建立一個User例項
			User user = new User();
			// 只處理請求引數陣列第一個陣列元素,
			// 並將該字串以英文逗號分割成兩個字串
			String[] userValues = values[i].split(",");
			// 為User例項的屬性賦值
			user.setName(userValues[0]);
			user.setPass(userValues[1]);
			// 將User例項新增到Set集合中
			result.add(user);
		}
		return result;
	}
	public String convertToString(Map context, Object o){
		// 如果待轉換物件的型別是Set
		if (o.getClass() == Set.class){
			Set users = (Set)o;
			String result = "[";
			for (Object obj : users ){
				User user = (User)obj;
				result += "<" + user.getName()
					+ "," + user.getPass() + ">";
			}
			return result + "]";
		}else{
			return "";
		}
	}
}

 上面程式碼實現了字串陣列和List結合的轉換處理,還需要讓struts2明白Set集合元素的標識屬性,指定Struts2根據該標識屬性來存取Set集合元素。

User類:

public class User{
	private String name;
	private String pass;

	// name的setter和getter方法
	public void setName(String name){
		this.name = name;
	}
	public String getName()
	{
		return this.name;
	}

	// pass的setter和getter方法
	public void setPass(String pass){
		this.pass = pass;
	}
	public String getPass(){
		return this.pass;
	}

	public boolean equals(Object obj){
		// 如果待比較的兩個物件是同一個物件,直接返回true
		if(this == obj){
			return true;
		}
		// 只有當obj是User物件
		if (obj != null && obj.getClass() == User.class){
			User user = (User)obj;
			// 兩個物件的name屬性相等即認為二者相等
			return this.getName().equals(user.getName());
		}
		return false;
	}
	// 根據name計算hashCode
	public int hashCode(){
		return name.hashCode();
	}
}

該User重寫了 equals 和 hashCode,該User類的標識屬性是name,當兩個User的name相同時認為它們相同。

使用區域性型別轉換檔案來指定Set元素的標識屬性

寫法:

KeyProperty_<SetPropName>=<KeyPropName>   SetPropName替換成屬性名   KeyPropName替換成元素的標識屬性。

#指定users屬性的型別轉換器是UserConverter
users= org.crazyit.app.converter.UserConverter
# 指定users集合屬性裡集合元素的索引屬性是name
KeyProperty_users=name

 在jsp頁面直接通過索引來訪問Set元素

welcome.jsp

<%@ page language="java" contentType="text/html; charset=GBK"%>
<%@taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
	<title>轉換結果</title>
</head>
<body>
	<s:actionmessage/>
	<s:property value="users"/>
<!-- 訪問users集合屬性裡索引屬性值為crazyit.org的元素的name屬性-->
使用者crazyit.org的使用者名稱為:<s:property value="users('crazyit.org').name"/><br/>
<!-- 訪問users集合屬性裡索引屬性值為crazyit.org的元素的pass屬性-->
使用者crazyit.org的密碼為:<s:property value="users('crazyit.org').pass"/><br/>
<!-- 訪問users集合屬性裡索引屬性值為fkit的元素的name屬性-->
使用者fkit的使用者名稱為:<s:property value="users('fkit').name"/><br/>
<!-- 訪問users集合屬性裡索引屬性值為fkit的元素的pass屬性-->
使用者fkit的密碼為:<s:property value="users('fkit').pass"/><br/>
生日為:<s:property value="birth"/><br/>
</body>
</html>

訪問Set元素用的是圓括號,而不是方括號。對於陣列,List和Map屬性,則通過方括號來訪問指定集合元素。 

 input.jsp

<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<%@taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title>Set屬性的型別轉換</title>
</head>
<body>
<h3>Set屬性的型別轉換</h3>
<s:form action="login">
	<s:textfield name="users" label="第一個使用者資訊"/>
	<s:textfield name="users" label="第二個使用者資訊"/>
	<s:textfield name="birth" label="使用者生日"/>
	<tr>
		<td colspan="2"><s:submit value="轉換" theme="simple"/>
		<s:reset value="重填" theme="simple"/></td>
	</tr>
</s:form>
</body>
</html>

 struts.xml

<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
	"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<constant name="struts.i18n.encoding" value="gbk"></constant>
	<!-- 配置國際化資原始檔 -->
	<constant name="struts.custom.i18n.resources" value="GBK"/>
	<package name="lee" extends="struts-default">
		<!-- 定義處理使用者請求的Action -->
		<action name="login" class="org.crazyit.app.action.LoginAction">
			<!-- 配置名為input的邏輯檢視,當轉換失敗後轉入該邏輯檢視 -->
			<result name="input">/WEB-INF/content/input.jsp</result>
			<!-- 配置名為success的邏輯檢視 -->
			<result>/WEB-INF/content/welcome.jsp</result> 
			<result name="error">/WEB-INF/content/welcome.jsp</result> 
		</action>

		<action name="*">
			<result>/WEB-INF/content/{1}.jsp</result>
		</action>
	</package>
</struts>

 

二、但是對於自定義型別struts2沒法去做型別轉換工作。需要自定義型別轉換器來實現型別的轉換。

我想要實現一個點的輸入比如(1,2)

輸入頁面

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<form action="add.action" method="post">
		座標點::<input type="text" name="point">
		<input type="submit" value="提交">
	</form> 
</body>
</html>

point類

public class Point {
	private int x;
	private int y;
	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;
	}

	@Override
	public String toString() {
		
		return "toString方法:   toString("+this.x+","+this.y+")";
	}

}

Action處理類

import com.opensymphony.xwork2.Action;
import cn.sxt.vo.Point;
public class PointAction {
	private Point point;
	public Point getPoint() {
		return point;
	}
	public void setPoint(Point point) {
		this.point = point;
	}
	//獲取頁面提交的座標點
	public String execute() {
		System.out.println("x="+point.getX()+"\ty="+point.getY());
		return Action.SUCCESS;
	}
}

struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
	<package name="default" extends="struts-default" namespace="/">
		<action name="add" class="cn.sxt.action.PointAction">
			<result >/sucess.jsp</result>
		</action>
	</package>
</struts>

就這樣去輸入提交的話會報錯的(空指標異常),應為struts2無法處理。

 

自定義型別轉換器就是解決這種問題的。

2、型別轉換的實現步驟

a)新建一個型別轉換器類繼承 StrutsTypeconverter類(實現兩個抽象方法),繼承DefaultTypeConverter也可以(只需要實現一個抽象方法)

import java.util.Map;

import org.apache.struts2.util.StrutsTypeConverter;

import cn.sxt.vo.Point;
/**
 * 之定義型別轉換器
 * @author yuanyu
 *
 */
/*
 * 使用型別轉換的步驟: 
	a) 編寫型別轉換器--繼承 StrutsTypeConverter 類
 	b) 編寫 xwork-conversion.properties 的配置檔案,放於 src 下;內容為 要轉換的型別=型別轉換器 
*/
//DefaultTypeConverter
//static {
//    Map<Class, Object> map = new HashMap<>();
//    map.put(Boolean.TYPE, Boolean.FALSE);
//    map.put(Byte.TYPE, Byte.valueOf((byte) 0));
//    map.put(Short.TYPE, Short.valueOf((short) 0));
//    map.put(Character.TYPE, new Character((char) 0));
//    map.put(Integer.TYPE, Integer.valueOf(0));
//    map.put(Long.TYPE, Long.valueOf(0L));
//    map.put(Float.TYPE, new Float(0.0f));
//    map.put(Double.TYPE, new Double(0.0));
//    map.put(BigInteger.class, new BigInteger("0"));
//    map.put(BigDecimal.class, new BigDecimal(0.0));
//    primitiveDefaults = Collections.unmodifiableMap(map);
//}


//
//public abstract class StrutsTypeConverter extends DefaultTypeConverter {
//    public Object convertValue(Map context, Object o, Class toClass) {
//        if (toClass.equals(String.class)) {
//            return convertToString(context, o);//物件轉換為String
//        } else if (o instanceof String[]) {
//            return convertFromString(context, (String[]) o, toClass);  //string 轉換為物件
//        } else if (o instanceof String) {
//            return convertFromString(context, new String[]{(String) o}, toClass);
//        } else {
//            return performFallbackConversion(context, o, toClass);
//        }
//    }
public class PointConverter extends StrutsTypeConverter /**繼承DefaultTypeConverter(預設型別轉換器),也可以*/ {
	 /**
	  * 表達提交的資料在這個方法中被轉換  將String 轉換為指定的型別
     * Converts one or more String values to the specified class.
     *
     * @param context the action context
     * @param values  the String values to be converted, such as those submitted from an HTML form 從表達上提交的字串
     * @param toClass the class to convert to  轉換為這種型別
     * @return the converted object
     */
	@Override
	public Object convertFromString(Map context, String[] values, Class toClass) {
		System.out.println("PointConverter.convertFromString()");
		String value = values[0];
		Point point = new Point();
		point.setX(Integer.parseInt(value.substring(1, value.indexOf(","))));//(1,2)
		point.setY(Integer.parseInt(value.substring(value.indexOf(",")+1, value.lastIndexOf(")"))));
		return point;
	}

	/**
	 *將指定的型別轉換為Strig
	 *使用ognl表示式獲取值時會呼叫該方法  EL表示式獲取的時候不會呼叫
     * Converts the specified object to a String.
     *
     * @param context the action context
     * @param o       the object to be converted
     * @return the converted String
     */
	@Override
	public String convertToString(Map context, Object o) {
		System.out.println("PointConverter.convertToString()");
		Point p = (Point)o;
		return "("+p.getX()+","+p.getY()+")";
	}
}

 b)在src下建立xwork-conversion.properties配置檔案(全域性型別轉換器  用什麼型別轉換器去轉換它)。當預設的型別轉換器沒有時它會去找自己定義的型別轉換器。

#be converted type=converter
cn.sxt.vo.Point=cn.sxt.converter.PointConverter

顯示頁面 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>(${point.x},${point.y})</h1>
<h1>EL表示式獲取:${point}</h1>
<h1>ognl表示式或:<s:property value="point"/></h1>
</body>

 

需要重新point的toStrin()方法,不然後面打印出來的是地址。

使用ognl表示式獲取值時才會呼叫convertToString()方法,資料的賦值就是通過ognl表示式和型別轉換器,由於資料被放在了請求域裡面,我可以直接用el表示式去獲取,el表示式是不會用convertToString()方法的,struts2是推薦用ognl表示式獲取值的。