struts2学习笔记(3)

来源:互联网 发布:华为 端口开启acl 编辑:程序博客网 时间:2024/06/09 19:10
 
第三讲 类型转换
在网页上传输的数据均是以String类型来传输的,而当我们对这些数据进行处理的时候。不可能都是使用String,这就需要用到类型转换,struts2提供了非常强大的类型机制,首先,对于将String转换为int等简单类型,struts2已经提供,不需要我们再作任何的考虑了。struts2甚至提供了从String转换到Date这样的对象类型的类型转换。而如果我们有一些自己定义的对象,期望我们的数据能由String转换到这些数据类型,那么,我们也可以自己定义如何从String转换到我们的自定义数据类型,下面我们就通过一个例子,来说明如何利用struts2来完成从String到我们自己定义的数据类型的转换。
在这里,我们的自定义类叫Point,它就是一个包括一个点的x和y坐标的类(其实没什么实际意义,只是用于演示如何完成将网页的String类型转换为一个自定义的类型)。另外,我们还会同时演示一下,struts2能自动将String转换为int类型,自动将String类型转换为Date类型。
我们继续使用在前两讲使用的工程,只是新建一些网页,添加配置信息而已。
第一步,我们新建一个网页,这个网页叫做input.jsp,里面的代码如下:
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!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>JSP Page</title>
    </head>
    <body>
        <s:form action="pointConverter">
            <s:textfield name="point" label="点坐标" />
            <s:textfield name="age" label="年龄" />
            <s:textfield name="username" label="姓名" />
            <s:textfield name="birthday" label="日期" />
            <s:submit value="提交" />
        </s:form>
    </body>
</html>
从上面的代码我们可以看出,我们仍然使用了struts2的标签。这里一共有四个文本框:
<s:textfield name="point" label="点坐标" />
<s:textfield name="age" label="年龄" />
<s:textfield name="username" label="姓名" />
<s:textfield name="date" label="日期" />
第一个文本框叫point,它将对应我们的Point类(如何对应?别着急,耐心往下看),第二个叫age,它将对应一个int类型,第三个文本框叫username,它对应String类型,当然,这个文本框是不需要类型转换的。第四个叫date,它对应java.util.Date类型。
而表单的action属性赋值为pointConverter,也在说明,我们将在struts2.xml文件中添加一个新的<action>标记,而这个<action>标记的name属性将为pointConverter(注意大小写)。
我们先放一放struts2.xml,先说说神秘的类型转换如何进行?别着急,我们还没有写我们的Point类呢。所以,第二步,我们在src目录中新建一个包(右击src目录,选择new-package),包名叫com.speakmore.struts2test.bean,然后在这个包里new一个class (右击刚刚新建的包,选择new-class),它的名字就叫Point,下面是它的代码:
package com.speakmore.struts2test.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() {
        return "[x="+x+",y="+y+"]";
    }
   
}
大家可以看到,这个Point有两个私有属性x和y,有二个set方法,还有二个get方法。另外还写了一个toString方法,里面只是返回一个字符串,没什么特别的意义。这个方法将会在我们后面的代码中用到,到时我再做详细的说明。
第三步,完成struts2.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="login" class="com.speakmore.struts2test.action.LoginAction">
            <result name="input">/login2.jsp</result>
            <result name="success">/result.jsp</result>
            <result name="failer">/login2.jsp</result>
        </action>
        <action name="pointConverter" class="com.speakmore.struts2test.action.PointAction">
            <result name="success">/output.jsp</result>
        </action>
    </package>
</struts>
这里我还是写出了全部代码,重要的是下面一段:
        <action name="pointConverter" class="com.speakmore.struts2test.action.PointAction">
            <result name="success">/output.jsp</result>
        </action>
这是新添加的<action>标签,如上面已经提到过的,它的name属性赋值为pointConverter,与input.jsp里的表单action属性对应,class属性说明我们的input.jsp里的数据将提交给com.speakmore.struts2test.action.PointAction类的一个对象,当这个对象处理完数据之后,如果返回success,则由<result>标记说明把页面转到output.jsp。
好的,下面我们接着来新建类PointAction。
由于com.speakmore.struts2test.action包我们在前二讲中已经建好,所以,直接右击这个包,然后选择new-class,填上类名:PointAction即可。它的代码如下:
package com.speakmore.struts2test.action;
 
import com.opensymphony.xwork2.ActionSupport;
import com.speakmore.struts2test.bean.Point;
import java.util.Date;
 
/**
 *
 * @author mouyong
 */
public class PointAction extends ActionSupport {
    private Point point;
    private int age;
    private String username;
    private Date birthday;
 
    public Point getPoint() {
        return point;
    }
 
    public void setPoint(Point point) {
        this.point = point;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
 
    public String getUsername() {
        return username;
    }
 
    public void setUsername(String username) {
        this.username = username;
    }
 
    public Date getBirthday() {
        return birthday;
    }
 
    public void setBirthday(Date birthday) {
        this.birthday = date;
    }
 
    @Override
    public String execute() throws Exception {
        return this.SUCCESS;
    }
   
}
在代码中,我们可以看到,这个类导入了两个类,一个是前面已经提到过的com.opensymphony.xwork2.ActionSupport,另一个就是我们刚刚建立的com.speakmore.struts2test.bean.Point。ActionSupport类是struts2提供的一个用于定义action处理的类,我们继承了它,这样可以获得Struts2所提供的功能(比如一会儿就要讲到的类型转换)。而Point类就是我们刚刚写的那个Point类,它用来存放我们将在文本框中输入的x和y坐标。
第四步,我们要写一个类:PointConverter。这个类的作用就是用来完成String到Point的转换,还有Point到String的转换。代码如下:
package com.speakmore.struts2test.converter;
 
import java.util.Map;
 
import com.speakmore.struts2.bean.Point;
 
import ognl.DefaultTypeConverter;
 
public class PointConverter extends DefaultTypeConverter {
 
         @Override
         public Object convertValue(Map context, Object value, Class toType) {
                   if(Point.class==toType){
                            //如果toType不是String,那就说明数据是从客户端送到服务器端。
                            Point p=new Point();
                            //由于value是通过request.getParameterValues()方法获得的,所以它是一个数组
String[] str=(String[])value;
                            String[] valueParam=str[0].split(",");
                           
                            p.setX(Integer.parseInt(valueParam[0]));
                            p.setY(Integer.parseInt(valueParam[0]));
                           
                            return p;
                   }
                  
                   if(String.class==toType){
                            //如果toType是String,则说明数据是从服务器端到客户端
                            Point p=(Point)value;//此时的value一定是我们需要的对象
                            return p.toString();
                   }
                   return null;
         }
}
这里作点解释。首先,PointConverter类继承了DefaultTypeConverter:
public class PointConverter extends DefaultTypeConverter
DefaultTypeConverter也就是struts2规定的一个默认类型转换器,如果我们要做一些特别的类型转换,那么我们就要写一个继承自DefaultTypeConverter的类。
它有一个方法:convertValue是需要我们重写的,里面的代码就是完成从String到自定义类型的转换以及从自定义类型到String的转换(这是因为在我们的网络上,由客户端传过来的数据都是String类型的,而服务器如果要做一些运算,就需要其它的类型(如int,float等基本类型或者别的引用类型),所以,归纳之后,当客户端的数据送来时,我们需要的转换就是String到其他类型,而如果是服务器向客户端发送数据时,我们需要的转换就是其他类型到String)。
@Override
         public Object convertValue(Map context, Object value, Class toType) {
                   if(Point.class==toType){
                            //如果toType不是String,那就说明数据是从客户端送到服务器端。
                            Point p=new Point();
                            //由于value是通过request.getParameterValues()方法获得的,所以它是一个数组
String[] str=(String[])value;
                            String[] valueParam=str[0].split(",");
                           
                            p.setX(Integer.parseInt(valueParam[0]));
                            p.setY(Integer.parseInt(valueParam[0]));
                           
                            return p;
                   }
                  
                   if(String.class==toType){
                            //如果toType是String,则说明数据是从服务器端到客户端
                            Point p=(Point)value;//此时的value一定是我们需要的对象
                            return p.toString();
                   }
                   return null;
         }
关于convertValue方法的参数,第一个不作说明了(目前我也不知道它有什么用),第三个参数是说明我们需要转换的类型是什么,第二个参数是Object,它是将被转换的数据。之所以定为Object,是由于被转换的数据与第三个参数密切相关。如果第三个参数不是String,那说明数据是从客户端送到服务器端,此时第二个参数就是一个通过request.getParameterValues()方法获得的String数组。所以有了我们的第一个if语句:
if(Point.class==toType){
                            //如果toType不是String,那就说明数据是从客户端送到服务器端。
                            Point p=new Point();
                            //由于value是通过request.getParameterValues()方法获得的,所以它是一个数组
String[] str=(String[])value;
//str的第一个值就是我们需要转换的点坐标值
                            String[] valueParam=str[0].split(",");
                           
                            p.setX(Integer.parseInt(valueParam[0]));
                            p.setY(Integer.parseInt(valueParam[1]));
                           
                            return p;
                   }
如果第三个参数是String,那说明我们的第二个参数是一个需要转换为String的对象。它是要发送到客户端去进行显示的。于是就有了我们的第二个if语句:
if(String.class==toType){
                            //如果toType是String,则说明数据是从服务器端到客户端
                            Point p=(Point)value;//此时的value一定是我们需要的对象
                            return p.toString();
                  }
在这里大家看到了p.toString(),这是我们常常采用的解决方案:如果一个对象需要转换成String,那就重写这个对象的toString()方法,在toString()方法中定义一个适当的,能表达此对象的String(怎么定?想怎么定就怎么定,决定权在于你自己!)。
接着我们来完成第五步:在PointAcion类所在的包下面写一个属性文件(右击com.speakmor.struts2test.converter包,新建一个file,取名叫PointAction-conversion.properties),由它来说明我们的PointAction类中的哪个属性需要进行转换,由谁进行转换。下面是它的代码:
#属性文件名说明:
#PointAction部分就是需要类型转换的Action类的类名。
#对哪个类里的属性要进行类型转换就用哪个类的类名作为属性文件的开头
#-conversion.properties是固定不变的
 
#属性写法说明
#等号左边说明要对哪个属性进行类型转换
#等号右边说明用哪个类进行类型转换
point=com.speakmore. struts2test.converter.PointConverter
OK!我们还差最后一个文件:output.jsp。全部代码如下:
<%@ page language="java" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
 <head>
   
 </head>
 
 <body>
    点坐标:<s:property value="point"/><!-- value就是action里定义的属性,与get方法或set方法匹配 -->
    年 龄:<s:property value="age"/>
    姓 名:<s:property value="username"/>
    生 日:<s:property value="birthday"/>
 </body>
</html>
这段代码并不是很复杂,我暂时不做很多解释了。
现在大家可以尝试运行一下这个程序,在input.jsp页面的“点坐标”文本框中填入20,30(注意中间是一个逗号,这样才能和我们的PointConverter类中的str[0].split(,)匹配!),其它文本框按正常的输入方式进行输入(注意只能输正确的值哦!)看一看类型转换是否可以成功?
好的,如果你调试总是不成功,你可以和我联系(QQ或者是留),记得收集你的错误信息,以便我能判断你错在哪里(记得看医生是要带病历的哦,你都不告诉医生你的症状,只说你病了,医生是不可能知道你得了什么病的)。
在本讲的最后一部分,我给大家说一说整个程序运行的流程(如果有说错的地方,希望大家批评指正!):
首先我们看到的页面应该是input.jsp,它有四个文本框,分别是point,age,username,date代码如下:
<s:form action="pointConverter">
            <s:textfield name="point" label="点坐标" />
            <s:textfield name="age" label="年龄" />
            <s:textfield name="username" label="姓名" />
            <s:textfield name="birthday" label="日期" />
            <s:submit value="提交" />
        </s:form>
现在我们在第一个文本框(point)中填入“20,30”,第二个文本框(age)中填入“30”,第三个文本框(username)中填入“张三”,第四个文本框(birthday)中填入“1973-9-1”之后,点击“提交”按钮时,struts2会根据struts.xml中的定义:
<action name="pointConverter" class="com.speakmore.struts2test.action.PointAction">
            <result name="success">/output.jsp</result>
        </action>
将input.jsp中的表单数据提交给PointAction类。其中point(字符串“20,30”)调用setPoint()方法,将数据交给Point类型的对象point,这时问题来了,在PointAction中的point是一个Point类型的,如何将字符串“20,30”交给Point呢?这时我们的属性文件(PointAction-conversion.properties)起作用了,它说明了有一个叫做PointConverter的类可以完成String到Point的转换。于是struts2启动了PointConverter类,调用了它的一个方法convertValue()。这个方法如下:
public Object convertValue(Map context, Object value, Class toType) {
此时,第三个参数toType是Point,而第二个参数是由request.getParameterValues(“point”)获得的一个数组。于是,我们知道,这个方法中的第一个if语句将起作用:
if(Point.class==toType){
于是,我们做的第一件事情就是new一个Point类:
Point p=new Point();
再之后,我们将第二个参数还原为String数组:
String[] str=(String[])value;
我们定义的Point类其实就是一个存坐标的类,它有两个属性,一个是x,另一个是y,而我们填在“point”文本框中的值是“20,30”,注意我们使用了逗号进行分隔。于是就有了以下几句代码:
String[] valueParam=str[0].split(",");
                           
                            p.setX(Integer.parseInt(valueParam[0]));
                            p.setY(Integer.parseInt(valueParam[1]));
其中str[0]的意思就是“取出第一个point文本框的值:字符串’20,30’(其实这里就只有一个,但struts2使用了数组,所以我们必须使用下标0来取出第一个)”,split(“,”)的意思就是“以逗号作为分隔符,将point文本框的值分成多个字符串”(这里是两个字符串,一个是20,另一个是30)。之后的两句就是对这两个字符串进行转换,调用setX()和setY()方法,将20存入x中,30存入y中。
最后,返回p:
return p;
这个p就会传给PointAction的setPoint方法,作为它的参数。于是,字符串“20,30”就成功转换成了Point类型(其实就是分隔字符串,把20给x坐标,30给y坐标,把它们都封装在Point里面)。
第二个文本框(age)的值是字符串“30”,它会调用PointAction类的setAge()方法,这时问题又来了,setAge()方法的参数是一个int,如何完成类型转换呢?别着急,struts2会自动完成这个类型转换不用我们插手的。
第三个文本框(username)的值是字符串“张三”,它会调用setUsername()方法,这个方法的参数就是字符串,所以struts2直接将值就给它了,并不进行转换。
第四个文本框(birthday)的值是字符串“1973-9-1”,它会调用setBirthday()方法,这个方法的参数是java.util.Date,同样,struts2也能自动完成字符串到Date类型的转换,不需要我们操心的。
当四个文本框填充完成之后,struts2调用了PointAction类的execute()方法,如下:
public String execute() throws Exception {
        return this.SUCCESS;
    }
这个方法没做什么事情,只是返回了一个常量:SUCCESS,这个常量其实就是字符串“success”,于是struts2又根据struts.xml文件中的以下代码:
<result name="success">/output.jsp</result>
将页面转到了output.jsp。关键代码如下:
点坐标:<s:property value="point"/>
    年 龄:<s:property value="age"/>
    姓 名:<s:property value="username"/>
    生 日:<s:property value="birthday"/>
这里我们首先看到的是:
<s:property value="point"/>
这一句代码的意思其实就是“从PointAction中将point送到客户端显示”,于是struts2就调用了PointAction的getPoint()方法,获得了Point类型的值。可是客户端要的是一个字符串,并不是Point。不要紧,struts2再次根据属性文件(PointAction-conversion.properties)的说明,调用了PointConverter类的convertValue()方法。这一次struts2赋给convertValue()的第三个参数将会是String(客户端需要String),而赋给convertValue()方法第二个参数将是getPoint()方法返回的Point对象。于是convertValue()方法的第二个if语句起作用了:
if(String.class==toType)
我们做的第一件事,就是把第二个参数(value)转换为Point
Point p=(Point)value;
然后返回p的字符串形式。
return p.toString();
这里就会返回字符串“[x=20,y=30]”。这个字符串将在客户端的页面上看到。
output.jsp的第二句是:
<s:property value="age"/>
struts2自动调用了PointAction的getAge()方法,获得int类型的数据,并自动转换为字符串“30”,在客户端显示出来。
第三句是:
<s:property value="username"/>
struts2自动调用了PointAction的getUsername(),获得String类型的数据“张三”,直接送往客户端显示。
最后一句是:
<s:property value="birthday"/>
struts2自动调用了PointAction的getDate(),获得了Date类型的数据,经过自动类型转换为字符串“73-9-1”在客户端显示出来。
综上所述,struts2可以帮助我们完成绝大多数的类型转换,并不需要我们操太多的心(当然,我们输入的数据格式必须符合相关规定)。如果我们需要进行一些特定的类型转换,我们只需要写一个继承自DefaultTypeConverter的类,重写convertValue()方法,定义如何完成从特定类型转换到字符串的过程以及如何从数字串转换到特定类型的过程(两个if语句),之后再写了一个叫做XXXAction-conversion.properties的文件,在里面说明谁要进行类型转换,谁来完成这个完换。然后把它与XXXAction类文件放在一起就可以了。

这样写代码,的确比struts1要简单得多,也方便得多。怎么样?不知道大家看懂没有?如果看不太明白,记得联系我哦。 

您好:
    当您在阅读和使用我所提供的各种内容的时候,我非常感谢,您的阅读已是对我最大的支持。
    我更希望您能给予我更多的支持。
    1.希望您帮助我宣传我的博客,让更多的人知道它,从中获益。
    2.希望您能多提出宝贵意见,包括我所提供的内容中的错误,建设性的意见,更希望获得哪些方面的帮助,您的经验之谈等等。
    3.更希望能得到您经济上的支持。
   
    我博客上面的内容均属于个人的经验,所有的内容均为开源内容,允许您用于任何非商业用途,并不以付费为前提,如果您觉得在阅读和使用我所提供的各种内容的过程中,您得到了帮助,并能在经济上给予我支持,我将感激不尽。
   
    您可以通过银行转帐付款给我(5元10元的,随意):
    招商银行一卡通:
    卡号:6225888712586894
    姓名:牟勇
   
    您也可以通过汇款的方式(5元10元的,随意):
    通讯地址:云南省昆明市女子(28)中学人民中路如意巷1号
    收信人:陈谦转牟勇收
    邮编:650021
   
    无论您给予我怎么样的支持,我都衷心的再次感谢。
    欢迎光临我的博客,欢迎宣传我的博客
    http://hi.csdn.net/mouyong
    http://blog.csdn.net/mouyong
    http://blog.sina.com.cn/mouyong
    EMail:mouyong@yeah.net