第十一部分_Struts2.1类型转换精析

首先,我们用第一种方式:继承ognl包下面的DefaultTypeConverter类,做一个类型转换:

新建一个input.jsp:

<%@ page language="java" import="java.util.*" pageEncoding="GBK"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    
    <title>My JSP 'input.jsp' starting page</title>
    
	<meta http-equiv="pragma" content="no-cache">
	<meta http-equiv="cache-control" content="no-cache">
	<meta http-equiv="expires" content="0">    
	<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
	<meta http-equiv="description" content="This is my page">
	<!--
	<link rel="stylesheet" type="text/css" href="styles.css">
	-->

  </head>
  
  <body>
    
    <h1>请输入一个点的坐标(使用逗号分隔)</h1>
    <form action="converterAction.action" method="post">
    	坐标:<input type="text" name="point" size="20"><br>
    	坐标2:<input type="text" name="point2" size="20"><br>
    	用户名:<input type="text" name="username" size="20"><br>
    	年龄:<input type="text" name="age" size="20"/><br/>
    	出生日期:<input type="text" name="birthday" size="20"/><br/>
    	<input type="submit" value="submit"/>"
    
    
    </form>
    
    
  </body>
</html>

接下来编写处理类,在com.test.action包下建立一个PointAction类:

package com.test.action;

import java.util.Date;

import com.opensymphony.xwork2.ActionSupport;
import com.test.bean.Point;

public class PointAction extends ActionSupport
{
	private Point point;
	
	private Point point2;
	
	private String username;
	
	private int age;
	
	private Date birthday;

	public Point getPoint2()
	{
		return point2;
	}

	public void setPoint2(Point point2)
	{
		this.point2 = point2;
	}

	public Point getPoint()
	{
		return point;
	}

	public void setPoint(Point point)
	{
		this.point = point;
	}

	public String getUsername()
	{
		return username;
	}

	public void setUsername(String username)
	{
		this.username = username;
	}

	public int getAge()
	{
		return age;
	}

	public void setAge(int age)
	{
		this.age = age;
	}

	public Date getBirthday()
	{
		return birthday;
	}

	public void setBirthday(Date brithday)
	{
		this.birthday = brithday;
	}
	
	public String execute() throws Exception
	{
		return "success";
	}
}

对于坐标的赋值,需要新建一个类,在com.test.bean包下新建一个类Point:

package com.test.bean;

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

然后再com.test.converter包下面建立一个点坐标的转换类PointConverter(该类需要继承ognl包下面的DefaultTypeConverter类):

package com.test.converter;

import java.util.Map;

import ognl.DefaultTypeConverter;

import com.test.bean.Point;

public class PointConverter extends DefaultTypeConverter
{
	@Override
	public Object convertValue(Map context, Object value, Class toType)
	{
		if(Point.class==toType)
		{
			String[] str = (String[])value;
			
			String firstValue = str[0];
			
			String[] resultValue = firstValue.split(",");
			
			Point point = new Point();
			point.setX(Integer.parseInt(resultValue[0]));
			point.setY(Integer.parseInt(resultValue[1]));
			
			return point;
		}
		else if(String.class == toType)
		{
			Point point = (Point)value;
			
			int x = point.getX();
			int y = point.getY();
			
			String result = "X: " + x + " Y: " + y;
			
			return result;
		}
		
		return null;
	}
}

此外,我们需要做一些相关的配置让struts2找到这个处理类,在com.test.action下建立一个文件:PointAction-conversion.properties,注意到这个文件在'-'后的字符都是固定的,只用前面是可以变化的,此外他必须和PointAction放在同一个包下面:

point=com.test.converter.PointConverter
point2=com.test.converter.PointConverter

然后配置struts.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">
	
	<struts>
		
		<package name="struts2" extends="struts-default">
		
			<action name="helloworld" class="com.test.action.HelloWorld">
				<result name="success">/helloworld.jsp</result>
			</action>
			
			<action name="login" class="com.test.action.LoginAction">
				<result name="success">/result.jsp</result>
			</action>
			
			<action name="converterAction" class="com.test.action.PointAction">
				<result name="success">/output.jsp</result>
			</action>
		</package>
	
	
	</struts>

最后写一个output.jsp,输出有几种选择:JSP脚本;EL;Struts2的标签库。这里我们使用后者:

<%@ page language="java" import="java.util.*" pageEncoding="GBK"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    
    <title>My JSP 'output.jsp' starting page</title>
    
	<meta http-equiv="pragma" content="no-cache">
	<meta http-equiv="cache-control" content="no-cache">
	<meta http-equiv="expires" content="0">    
	<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
	<meta http-equiv="description" content="This is my page">
	<!--
	<link rel="stylesheet" type="text/css" href="styles.css">
	-->

  </head>
  
  <body> 
  	坐标:<s:property value="point"/><br/>
  	坐标2:<s:property value="point2"/><br/>
  	用户名:<s:property value="username"/><br>
  	年龄:<s:property value="age"/><br>
  	出生日期:<s:property value="birthday"/>

  </body>
</html>

下面是运行结果的一个截图:

其次,我们用Struts2提供的StrutsTypeConverter(它也继承了ognl包下面的DefaultTypeConverter类,如何在MyEclipse中查看其源代码?MyEclipse中找到struts2-core-2.1.6.jar,展开,找到org.apach.struts2.util,找到旗下的Struts TypeConverter.class,打开,点击Attach Source->External Folder,找到struts-2.1.6的解压缩目录,找到目录下的src,在src下面展开core,展开main,main下面有一个java,选择java,确定,这样就把硬盘上的源码和MyEclipse关联起来了)抽象类:

在com.test.converter包下面新建一个类PointConverter2:

package com.test.converter;

import java.util.Map;

import org.apache.struts2.util.StrutsTypeConverter;

import com.test.bean.Point;

public class PointConverter2 extends StrutsTypeConverter
{

	@Override
	public Object convertFromString(Map context, String[] values, Class toClass)
	{
		Point point = new Point();
		
		String value = values[0];
		
		String[] result = value.split(",");
		
		point.setX(Integer.parseInt(result[0]));
		point.setY(Integer.parseInt(result[1]));
		
		return point;
	}

	@Override
	public String convertToString(Map context, Object o)
	{
		Point point = (Point)o;
		
		int x =point.getX();
		int y = point.getY();
		
		String result = "x: " + x + " y: " + y;
		
		return result;
	}

}

修改PointAction-conversion.properties:

point=com.test.converter.PointConverter2
point2=com.test.converter.PointConverter2

浏览器访问http://localhost:8080/struts2/input.jsp,运行结果和用第一种方式实现的结果一样。

一个问题:如何进行批量处理(假如有100个point,难道要从point1定义到point100)?

我们假设有三个坐标表示"很多个坐标",在input.jsp中,注意到这些点的name属性都是相同的:

<form action="converterAction.action" method="post">
    	坐标:<input type="text" name="point" size="20"><br>
    	坐标2:<input type="text" name="point" size="20"><br>
    	坐标3:<input type="text" name="point" size="20"><br>
    	用户名:<input type="text" name="username" size="20"><br>
    	年龄:<input type="text" name="age" size="20"/><br/>
    	出生日期:<input type="text" name="birthday" size="20"/><br/>
    	<input type="submit" value="submit"/>"
    
    
    </form>

修改PointAction类:

package com.test.action;

import java.util.Date;
import java.util.List;

import com.opensymphony.xwork2.ActionSupport;
import com.test.bean.Point;

public class PointAction extends ActionSupport
{
	/*private Point point;
	
	private Point point2;*/
	
	private List<Point> point;
	
	private String username;
	
	

	private int age;
	
	private Date birthday;
	
	public List<Point> getPoint()
	{
		return point;
	}

	public void setPoint(List<Point> point)
	{
		this.point = point;
	}
	/*public Point getPoint2()
	{
		return point2;
	}

	public void setPoint2(Point point2)
	{
		this.point2 = point2;
	}

	public Point getPoint()
	{
		return point;
	}

	public void setPoint(Point point)
	{
		this.point = point;
	}*/

	public String getUsername()
	{
		return username;
	}

	public void setUsername(String username)
	{
		this.username = username;
	}

	public int getAge()
	{
		return age;
	}

	public void setAge(int age)
	{
		this.age = age;
	}

	public Date getBirthday()
	{
		return birthday;
	}

	public void setBirthday(Date brithday)
	{
		this.birthday = brithday;
	}
	
	public String execute() throws Exception
	{
		return "success";
	}
}

然后编写转换类PointConverter3:

package com.test.converter;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.struts2.util.StrutsTypeConverter;

import com.test.bean.Point;

public class PointConverter3 extends StrutsTypeConverter
{

	@Override
	public Object convertFromString(Map context, String[] values, Class toClass)
	{
		List<Point> list = new ArrayList<Point>();
		
		for(String value : values)
		{
			String[] result = value.split(",");
			Point point = new Point();
			
			point.setX(Integer.parseInt(result[0]));
			point.setY(Integer.parseInt(result[1]));
			
			list.add(point);
		}
		
		return list;
	}

	@Override
	@SuppressWarnings("unchecked")
	public String convertToString(Map context, Object o)
	{
		List<Point> list = (List<Point>)o;
		
		StringBuffer sb = new StringBuffer();
		
		int number = 0;
		
		for(Point point : list)
		{
			number++;
			
			int x = point.getX();
			int y = point.getY();
			
			// 这里不要使用以前PointConverter里那种直接拼接的方式,字符串太多,效率太低
			sb.append(number).append(".x=").append(x).append(" y=").append(y).append(" ");
			
			
		}
		
		return sb.toString();
	}

}

更改配置文件PointAction-conversion.properties:

#point=com.test.converter.PointConverter2
#point2=com.test.converter.PointConverter2
point=com.test.converter.PointConverter3

最后更改output.jsp:

 <body> 
  	坐标:<s:property value="point"/><br/>
  	用户名:<s:property value="username"/><br>
  	年龄:<s:property value="age"/><br>
  	出生日期:<s:property value="birthday"/>

  </body>

下面是运行结果的一个截图:

  

 此外,还用一种类型转换的方式(要求用户输入坐标分别在两个输入框中):

修改input.jsp:

<body>
    
    <h1>请输入一个点的坐标(使用逗号分隔)</h1>
    <form action="converterAction.action" method="post">
    <!-- 
    	坐标:<input type="text" name="point" size="20"><br>
    	坐标2:<input type="text" name="point" size="20"><br>
    	坐标3:<input type="text" name="point" size="20"><br>
     -->
     	x:<input type="text" name="point.x" size="20"/><br/>
     	y:<input type="text" name="point.y" size="20"/><br/>
    	用户名:<input type="text" name="username" size="20"><br>
    	年龄:<input type="text" name="age" size="20"/><br/>
    	出生日期:<input type="text" name="birthday" size="20"/><br/>
    	<input type="submit" value="submit"/>"
    
    
    </form>

PointAction类内容如下:

package com.test.action;

import java.util.Date;
import java.util.List;

import com.opensymphony.xwork2.ActionSupport;
import com.test.bean.Point;

public class PointAction extends ActionSupport
{
	private Point point;
	
	private String username;

	private int age;
	
	private Date birthday;

	public Point getPoint()
	{
		return point;
	}

	public void setPoint(Point point)
	{
		this.point = point;
	}

	public String getUsername()
	{
		return username;
	}

	public void setUsername(String username)
	{
		this.username = username;
	}

	public int getAge()
	{
		return age;
	}

	public void setAge(int age)
	{
		this.age = age;
	}

	public Date getBirthday()
	{
		return birthday;
	}

	public void setBirthday(Date brithday)
	{
		this.birthday = brithday;
	}
	
	public String execute() throws Exception
	{                
                // 两行测试语句,输出到控制台
		System.out.println("X: " + point.getX());
		System.out.println("Y: " + point.getY());


		return "success";
	}
}

更改Point类,重写其toString方法:

package com.test.bean;

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()
	{
		String result = "x: " + x + " y: " + y;
		return result;
	
	}
}

注释掉PointAction-conversion.properties:

#point=com.test.converter.PointConverter2
#point2=com.test.converter.PointConverter2
#point=com.test.converter.PointConverter3

output.jsp如下:

<body> 
  	坐标:<s:property value="point"/><br/>
  	用户名:<s:property value="username"/><br>
  	年龄:<s:property value="age"/><br>
  	出生日期:<s:property value="birthday"/>

  </body>

浏览器运行结果:

坐标:x: 1 y: 2
用户名:name
年龄:20
出生日期:93-3-30

 

此外,附送一个小知识点:如果我们的Action有多个,比如增删查改,那么类就有点多了,我们可以用同一个action来处理多个业务需求,如下修改PointAction(增加了一个test方法,struts2要求这个方法除了方法名和execute不同外,其他签名包括public修饰符、抛出异常等必须完全一致):

package com.test.action;

import java.util.Date;
import java.util.List;

import com.opensymphony.xwork2.ActionSupport;
import com.test.bean.Point;

public class PointAction extends ActionSupport
{
	private Point point;
	
	private String username;

	private int age;
	
	private Date birthday;

	public Point getPoint()
	{
		return point;
	}

	public void setPoint(Point point)
	{
		this.point = point;
	}

	public String getUsername()
	{
		return username;
	}

	public void setUsername(String username)
	{
		this.username = username;
	}

	public int getAge()
	{
		return age;
	}

	public void setAge(int age)
	{
		this.age = age;
	}

	public Date getBirthday()
	{
		return birthday;
	}

	public void setBirthday(Date brithday)
	{
		this.birthday = brithday;
	}
	
	public String test() throws Exception
	{
		System.out.println("test invoked");
		
		System.out.println("X: " + point.getX());
		System.out.println("Y: " + point.getY());
		
		return SUCCESS; // 读过Action的源代码,就知道它定义了一个叫做SUCCESS的常量,其值就是“success”,因此这里的效果和 return "success"相同
	}
	
	public String execute() throws Exception
	{
		System.out.println("X: " + point.getX());
		System.out.println("Y: " + point.getY());
		return "success";
	}
}

那么如何让我们的程序不执行默认的execute而是执行test方法呢?方法就是修改对应的struts.xml文件:

<action name="converterAction" class="com.test.action.PointAction" method="test">
				<result name="success">/output.jsp</result>
			</action>

可以看到在原有的基础上我们为其增加了一个method属性,并将其赋值为test,这样浏览器中访问http://localhost:8080/struts2/input.jsp,输出依旧,回到控制台可以看到test invoked,说明我们的做法成功了。

补充:注意到上面程序中我给return SUCCESS语句添加了注释,提到了Action源码,其源码不在Struts2中,需要根据版本单独下载,比如我们这里是xwork-2.1.2,下载XWork源代码,找到对应的目录,比如我下载完成后,解压放到了struts2下面的D:\ProgramFiles\struts-2.1.6\xwork-2.1.2\src\java。MyEclipse中关联起来即可。

我们怎么知道这个类的呢?

因为我们的PointAction继承了ActionSupport,而ActionSupport实现了Action。

再补充:如果我们要转换的Point在除了PointAction中还有其他的Action类需要对同样地Point转换,我们是不是针对每一个Action都得在它对应的包下面写一个同样的配置文件呢?答案是不需要,struts考虑到这点,给我们提供了一个全局转换的功能,在src(不要定义在某个包里,否则这个全局转换就失效了)下面新建一个文件命名为xwork-conversion.properties,注意到这里每个字符都是固定的。内容如下:

#要转换的对象的类的全名=右边是转换器的名字
com.test.bean.Point=com.test.converter.PointConverter2

将input.jsp的坐标部分更改为:坐标:<input type="text" name="point" size="20"/><br/> 

注释掉PointAction-conversion.properties,浏览器访问,输出结果正常,说明我们的配置是正确的。

posted @ 2015-07-20 14:58  Code_Rush  阅读(223)  评论(0编辑  收藏  举报