Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 331|回复: 0

[struts学习]学习Struts 2.0系列(5)

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-10-10 23:53:27 | 显示全部楼层 |阅读模式
    来自:http://www.blogjava.net/max/arcHive/2006/11/07/79602.HTML

    在我已往的Struts 1.x项目经验中,有个问题不时的出现――在创建FormBean时,对于某个属性到底应该用String还是其它类型? 开发Web应用程序与开发传统桌面应用程序不同,Web应用程序实际上是分布个不同的主机(当然也可以同一个主机,不过比较少见)上的两个进程之间互交。这种互交建立在HTTP之上,它们互相传递是都是字符串。换句话说, 服务器可以的接收到的来自用户的数据只能是字符串或字符数组,而在服务器上的对象中,这些数据往往有多种不同的类型,如日期(Date),整数(int),浮点数(float)或自定义类型(UDT)等,如图1所示。因此,我们需要服务器端将字符串转换为适合的类型。




    图1 UI与服务器对象关系
    同样的问题也发生在使用UI展示服务器数据的情况。HTML的Form控件不同于桌面应用程序可以表示对象,其值只能为字符串类型,所以我们需要通过某种方式将特定对象转换成字符串。 要实现上述转换,Struts 2.0中有位魔术师可以帮到你――Converter。有了它,你不用一遍又一遍的重复编写诸如此类代码: Date birthday = DateFormat.getInstance(DateFormat.SHORT).parse(strDate);
    <input type="text" value="<%= DateFormat.getInstance(DateFormat.SHORT).format(birthday) %>" /> 好了,现在让我们来看一个例子。 转换器――Hello World 在我的上一篇文章《在Struts 2.0中国际化(i18n)您的应用程序》的最后我举了一个可以让用户方便地切换语言的例子,下面例子与其相似,但实现方法不同。 首先,如《在Struts 2.0中国际化(i18n)您的应用程序》的第一个例子一样,创建和配置默认的资源文件; 接着,新建源代码文件夹下的tutorial包创建HelloWorld.java文件,代码如下:
      


    package
    tutorial;


    import
    java.util.Locale;


    import
    com.opensymphony.xwork2.ActionSupport;

    import
    com.opensymphony.xwork2.util.LocalizedTextUtil;


    public

    class
    HelloWorld
    extends
    ActionSupport

    {
         private String msg;
         private Locale loc = Locale.US;
       
         public String getMsg() {
             return msg;        
        }
       
         public Locale getLoc() {
             return loc;
        }
       
         public void setLoc(Locale loc) {
             this .loc = loc;
        }
       
        @Override
         public String execute() {
             // LocalizedTextUtil是Struts 2.0中国际化的工具类,<s:text>标志就是通过调用它实现国际化的
            msg = LocalizedTextUtil.findDefaultText( " HelloWorld " , loc);
             return SUCCESS;
        }
    }
    然后,在源代码文件夹下的struts.xml加入如下代码新建Action:
      

    <
    package
    name
    ="ConverterDemo"
    extends
    ="struts-default"
    >

         
    <
    action
    name
    ="HelloWorld"
    class
    ="tutorial.HelloWorld"
    >

             
    <
    result
    >
    /HelloWorld.jsp
    </
    result
    >

         
    </
    action
    >


    </
    package
    >
    再在Web文件夹下,新建 HelloWorld.jsp,代码如下:
      

    <
    %@ page   
    contentType
    ="text/html; charset=UTF-8"
    %
    >


    <
    %@taglib
    prefix
    ="s"
    uri
    ="/struts-tags"
    %
    >


    <
    html
    >


    <
    head
    >

         
    <
    title
    >
    Hello World
    </
    title
    >


    </
    head
    >


    <
    body
    >

         
    <
    s:form
    action
    ="HelloWorld"
    theme
    ="simple"
    >
                
             Locale:
    <
    s:textfield
    name
    ="loc"

    />
       
    <
    s:submit
    />

         
    </
    s:form
    >
       
         
    <
    h2
    ><
    s:property
    value
    ="msg"

    /></
    h2
    >


    </
    body
    >


    </
    html
    >
    接下来,在源代码文件夹的tutorial包中新建LocaleConverter.java文件,代码如下:
      


    package
    tutorial;


    import
    java.util.Locale;

    import
    java.util.Map;


    public

    class
    LocaleConverter
    extends
    ognl.DefaultTypeConverter

    {
        @Override
         public Object convertValue(Map context, Object value, Class toType) {
             if (toType == Locale. class ) {
                String locale = ((String[]) value)[ 0 ];
                 return new Locale(locale.substring( 0 , 2 ), locale.substring( 3 ));
            } else if (toType == String. class ) {
                Locale locale = (Locale) value;
                 return locale.toString();
            }
             return null ;
        }
    }
    再接下来,在源代码文件夹下新建xwork-conversion.properties,并在其中添加如下代码:
      

    java.util.Locale
    =
    tutorial.LocaleConverter
    发布运行应用程序,在浏览器中键入http://localhost:8080/Struts2_Converter/HelloWorld.action,输出页面如图2所示:


    图2 HelloWorld英文输出 在Locale输入框中输入“zh_CN”,按“Submit”提交,出现如图3所示页面:


    图3 HelloWorld中文输出 上述例子中,Locale文本输入框对应是Action中的类型为java.util.Locale的属性loc,所以需要创建一个自定义转变器实现两者间的转换。所有的Struts 2.0中的转换器都必须实现ognl.TypeConverter接口。 为了简单起见,OGNL包也为你提供了ognl.DefaultTypeConverter类去帮助您实现转换器。在例子中,LocaleConverter继承了ognl.DefaultTypeConverter,重载了其方法原型为“public Object convertValue(Map context, Object value, Class toType)”的方法。下面简单地介绍一下函数的参数:  

    context――用于获取当前的ActionContext
    value――需要转换的值
    toType――需要转换成的目标类型  
    实现转换器,我们需要通过配置告诉Struts 2.0。我们可以通过以下两种方法做到这点:

    配置全局的类型转换器,也即是上例的做法――在源代码文件夹下,新建一个名为“xwork-conversion.properties”的配置文件,并在文件中加入“待转换的类型的全名(包括包路径和类名)=转换器类的全名”对;
    应用于某个特定类的类型转换器,做法为在该类的包中添加一个格式为“类名-conversion.properties”的配置文件,并在文件中加入“待转换的属性的名字=转换器类的全名”对。上面的例子也可以这样配置――在源代码文件夹的tutorial包下新建名为“HelloWorld-conversion.properties”文件,并在其中加入“loc=tutorial.LocaleConverter”。


      
       
       
       
        在继承DefaultTypeConverter时,如果是要将value转换成其它非字符串类型时,要记住value是String[]类型,而不是String类型。它是通过request.getParameterValues(String arg)来获得的,所以不要试图将其强行转换为String类型。  
       
       
      
    已有的转换器 对于一此经常用到的转换器,如日期、整数或浮点数等类型,Struts 2.0已经为您实现了。下面列出已经实现的转换器。  

    预定义类型,例如int、boolean、double等;
    日期类型, 使用当前区域(Locale)的短格式转换,即DateFormat.getInstance(DateFormat.SHORT);
    集合(Collection)类型, 将request.getParameterValues(String arg)返回的字符串数据与java.util.Collection转换;
    集合(Set)类型, 与List的转换相似,去掉相同的值;
    数组(Array)类型, 将字符串数组的每一个元素转换成特定的类型,并组成一个数组。
    对于已有的转换器,大家不必再去重新发明轮子。Struts在遇到这些类型时,会自动去调用相应的转换器。 批量封装对象(Bean) 不知道大家是否遇过这种情况,在一个页面里同时提交几个对象。例如,在发布产品的页面,同时发布几个产品。我在之前一个项目就遇到过这种需求,当时用的是Struts 1.x。那是一个痛苦的经历,我在Google搜了很久都没有理想的结果。幸运的是,在Struts 2.0中这种痛苦将一去不复返。下面我就演示一下如何实现这个需求。 首先,在源代码文件夹下的tutorial包中新建Product.java文件,内容如下:
      


    package
      tutorial;


    import
      java.util.Date;


    public

    class
      Product

    {
        private String name;
        privatedouble price;
        private Date dateOfProduction;
       
        public Date getDateOfProduction() {
            return dateOfProduction;
        }
       
        publicvoid setDateOfProduction(Date dateOfProduction) {
            this.dateOfProduction = dateOfProduction;
        }
       
        public String getName() {
            return name;
        }
       
        publicvoid setName(String name) {
            this.name = name;
        }
       
        publicdouble getPrice() {
            return price;
        }
       
        publicvoid setPrice(double price) {
            this.price = price;
        }   
    }
    然后,在同上的包下添加ProductConfirm.java类,代码如下:
      


    package
      tutorial;


    import
      java.util.List;


    import
      com.opensymphony.xwork2.ActionSupport;


    public

    class
      ProductConfirm
    extends
      ActionSupport

    {
        public List<Product> products;

        public List<Product> getProducts() {
            return products;
        }

        publicvoid setProducts(List<Product> products) {
            this.products = products;
        }
       
        @Override
        public String execute() {
            for(Product p : products) {
                System.out.println(p.getName() + " | "+ p.getPrice() +" | " + p.getDateOfProduction());
            }
            return SUCCESS;
        }
    }
    接看,在同上的包中加入ProductConfirm-conversion.properties,代码如下:
      

    Element_products
    =
    tutorial.Product
    再在struts.xml文件中配置ProductConfirm Action,代码片段如下:
      

    <
    action
    name
    ="ProductConfirm"
      class
    ="tutorial.ProductConfirm"
    >

         
    <
    result
    >
    /ShowProducts.jsp
    </
    result
    >


    </
    action
    >
    在WEB文件夹下新建AddProducts.jsp,内容如下:
      

    <%
    @ page  contentType
    =
    "
    text/html; charset=UTF-8
    "
    %>


    <%
    @taglib prefix
    =
    "
    s
    "
      uri
    =
    "
    /struts-tags
    "

    %>


    <
    html
    >


    <
    head
    >

         
    <
    title
    >
    Hello World
    </
    title
    >


    </
    head
    >


    <
    body
    >

         
    <
    s:form
    action
    ="ProductConfirm"
      theme
    ="simple"
    >
                
             
    <
    table
    >

                
    <
    tr
    style
    ="background-color:powderblue; font-weight:bold;"
    >

                     
    <
    td
    >
    Product Name
    </
    td
    >

                     
    <
    td
    >
    Price
    </
    td
    >

                     
    <
    td
    >
    Date of production
    </
    td
    >

                
    </
    tr
    >

                
    <
    s:iterator
    value
    ="new int[3]"
      status
    ="stat"
    >

                     
    <
    tr
    >

                         
    <
    td
    ><
    s:textfield
    name
    ="%{"products["+#stat.index+"].name"}"

    /></
    td
    >

                         
    <
    td
    ><
    s:textfield
    name
    ="%{"products["+#stat.index+"].price"}"

    /></
    td
    >

                         
    <
    td
    ><
    s:textfield
    name
    ="%{"products["+#stat.index+"].dateOfProduction"}"

    /></
    td
    >

                     
    </
    tr
    >

                
    </
    s:iterator
    >

                
    <
    tr
    >

                     
    <
    td
    colspan
    ="3"
    ><
    s:submit
    /></
    td
    >

                
    </
    tr
    >

             
    </
    table
    >

         
    </
    s:form
    >
         

    </
    body
    >


    </
    html
    >
    在同样的文件夹下创建ShowProducts.jsp,内容如下:
      

    <%
    @ page  contentType
    =
    "
    text/html; charset=UTF-8
    "
    %>


    <%
    @taglib prefix
    =
    "
    s
    "
      uri
    =
    "
    /struts-tags
    "

    %>


    <
    html
    >


    <
    head
    >

         
    <
    title
    >
    Hello World
    </
    title
    >


    </
    head
    >


    <
    body
    >
         
         
    <
    table
    >

             
    <
    tr
    style
    ="background-color:powderblue; font-weight:bold;"
    >

                
    <
    td
    >
    Product Name
    </
    td
    >

                
    <
    td
    >
    Price
    </
    td
    >

                
    <
    td
    >
    Date of production
    </
    td
    >

             
    </
    tr
    >

             
    <
    s:iterator
    value
    ="products"
      status
    ="stat"
    >

                
    <
    tr
    >

                     
    <
    td
    ><
    s:property
    value
    ="name"

    /></
    td
    >

                     
    <
    td
    >
    $
    <
    s:property
    value
    ="price"

    /></
    td
    >

                     
    <
    td
    ><
    s:property
    value
    ="dateOfProduction"

    /></
    td
    >

                
    </
    tr
    >

             
    </
    s:iterator
    >

         
    </
    table
    >


    </
    body
    >


    </
    html
    >
    发布运行应用程序,在浏览器中键入http://localhost:8080/Struts2_Converter/AddProducts.jsp,出现如图4所示页面:


    图4 添加产品页面 按图4所示,填写表单,按“Submit”提交,出现图5所示页面:


    图5 查看产品页面 查看服务器的控制台,有如下输出:  

    Expert One-on-One J2EE Development without EJB |
    39.99
      | Mon Jun
    21

    00
    :
    00
    :
    00
      CST
    2004

    Pro Spring |
    32.99
      | Mon Jan
    31

    00
    :
    00
    :
    00
      CST
    2005

    Core J2EE Patterns: Best Practices and Design Strategies
    ,
      Second Edition |
    34.64
      | Sat May
    10

    00
    :
    00
    :
    00
      CST
    2003
    上面的代码并不复杂,但有几点需要说明:  

    ProductConfirm文件中的for(Product p : productes)的写法是J2SE 5.0中的新特性,作用遍历products列表;
    List<Product>也是J2SE 5.0的才有的泛型(Generic);
    ProductConfirm-conversion.properties中“Element_products=tutorial.Product”是告诉Struts 2.0列表products的元素的类型为Product,而不是定义转换器;
    在AddProducts.jsp的<s:textfield>的name为“%{"products["+#stat.index+"].name"}”,%{exp}格式表示使用OGNL表达式,上述表达式的相当于<%= "products[" + stat.index + "].name" %>,至于<s:iterator>标志的用法可以参考我之前的文章《常用的Struts 2.0的标志(Tag)介绍》。
    转换错误处理 不知道大家在运行上面的例子时,有没有填错日期或数字情况,又或者您有没有思考过这种情况?如果还没有尝试的朋友可以试一下,在第一行的Price和Date of production中输入英文字母,然后按“Submit”提交。你会看到页面为空白,再看一下服务器的控制台输出,有如下语句: 警告: No result defined for action tutorial.ProductConfirm and result input,它提示我们没有为Action定义输入结果,所以,我们应该在源代码文件夹下的struts.xml中的ProductConfirm Action中加入以下代码:
      

    <
    result
    name
    ="input"
    >
    /AddProducts.jsp
    </
    result
    >
    重新加载应用程序,刷新浏览器重新提交请求,这时页面返回AddProducts.jsp,格式错误的输入框的值被保留,如下图6所示:


    图6 没有提示的错返回页面 当然,我们还可以在页面上加上错误提示信息,通过在AddProducts.jsp的“<body>”后,加入下面代码可以实现:
      

    <
    div
    style
    ="color:red"
    >

         
    <
    s:fielderror
    />


    </
    div
    >
    刷新浏览器,重新提交请求,出现如图7所示页面:


    图7 带提示的错返回页面 以上的功能的都是通过Struts 2.0里的一个名为conversionError的拦截器(interceptor)工作,它被注册到默认拦截器栈(default interceptor stack)中。Struts 2.0在转换出错后,会将错误放到ActionContext中,在conversionError的作用是将这些错误封装为对应的项错误(field error),因此我们可以通过<s:fielderror />来将其在页面上显示出来。另外,大家看第二和第三行的Price都被赋为0.0的值,而第一行则保留其错误值。这同样是conversionError的功劳――没有出错的行调用的products[index].price(默认值为0.0),而出错的行则会被赋为页面所提交的错误值,这样可以提供更好的用户体验。 总结 Struts 2.0的转换器简化的WEB应用程序的模型,为我们的编程带来极大的方便。
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-26 13:54 , Processed in 0.310835 second(s), 36 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表