论坛首页 Java企业应用论坛

Struts2+JSON+YUI构建Rich Client应用(一)

浏览 8375 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-12-21  

Struts2的出现在Web2.0纷争的年代,以Ajax为代表的富客户端(Rich Client)应用正唱着Web2.0的主角。虽然Struts2本身对Ajax的应用也提供了自己的Ajax标签,但是这种比较牵强的支持也是赶鸭子上架,不是Struts本身的特长。

 

这里,就Struts对JSON支持的技术特点,来构建一个Rich Client应用,UI层使用的是YUI工具包,详情参考Yahoo的YUI网站。http://developer.yahoo.com/yui/

 

本文中所涉及的Web应用的大致结构图如下:

 

先一睹为快,该应用的实际运行界面如下:

 

 

页面功能大致是,用户加入一个New Test User和New Message,然后点击按钮Add Now,页面无刷新添加新加入的消息。

 

首先,建立一个Struts的Action类StrutsTestAction,代码如下:

package com.tail.test.actions;   
  
import java.util.ArrayList;   
import java.util.List;   
  
//import org.apache.log4j.Logger;   
  
import com.opensymphony.xwork2.ActionSupport;   
import com.tail.test.objects.Message;   
  
public class StrutsTestAction extends BaseAction {   
    // Our logger.   
//    private static Logger logger = Logger.getLogger(StrutsTestAction.class);   
       
    private String newUser;   
       
    private String newMessage;   
       
    private List<Message> messageList;   
  
    public List<Message> getMessageList() {   
        return messageList;   
    }   
  
    public void setMessageList(List<Message> messageList) {   
        this.messageList = messageList;   
    }   
  
    public String getNewMessage() {   
        return newMessage;   
    }   
  
    public void setNewMessage(String newMessage) {   
        this.newMessage = newMessage;   
    }   
  
    public String getNewUser() {   
        return newUser;   
    }   
  
    public void setNewUser(String newUser) {   
        this.newUser = newUser;   
    }   
  
    @Override  
    public String execute() throws Exception {         
        return super.execute();   
    }   
       
    public String loadMessages() {   
        messageList = new ArrayList<Message>();   
        messageList.add(new Message("tail", "This is an piece of initial message."));   
        return result(SUCCESS);   
    }   
       
    public String addMessageToUser() {   
        messageList.add(new Message(newUser, newMessage));   
        //logger.debug("Add user='" + newUser + "', message='" + newMessage + "'");   
        return result(SUCCESS);   
    }   
} 

 

其中,newUser和newMessage分别对应界面上的New Test User和New Message这两个输入框中的value。messageList则是下方显示的消息内容,注意messageList本身内含多个Message对象的List,Message类的定义如下:

package com.tail.test.objects;   
  
public class Message {   
    private String userName;   
  
    private String content;   
  
    public String getContent() {   
        return content;   
    }   
  
    public void setContent(String content) {   
        this.content = content;   
    }   
  
    public String getUserName() {   
        return userName;   
    }   
  
    public void setUserName(String userName) {   
        this.userName = userName;   
    }   
  
    public Message() {   
  
    }   
  
    public Message(String userName, String content) {   
        this.userName = userName;   
        this.content = content;   
    }   
}  

 

loadMessages()方法负责初始化装载数据,比如说我们从数据库或第三方资源中取出数据来初始化现有的List,它在页面上的实现,实际上也是结合Ajax来进行的。

 

addMessageToUser()方法对应了界面上Add Now按钮的动作内容,他们中间的交互过程也是通过Ajax来完成的,这也是这个应用的核心所在。

 

注意,这里的Struts Action Bean本身的默认的excute方法也被override过来了,而方法体本身是空的,这里这样做的目的就是,可以让界面操作用户一进入此页面,界面能马上构造出来,而不用等待服务器端的数据装载和返回,在初始装载数据量较大的时候,这一点尤其重要。这一点,大家可以结合后部分讲到的YUI部分的代码来体会。

 

现在已经有了StrutsTestAction这个工作类,那么这里的Struts核心的配置文件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="test" namespace="/" extends="json-default">  
        <global-results>  
            <!-- any exceptions should redirect to the exception page -->  
            <result name="exception" type="redirect-action">  
              <param name="actionName">exception</param>  
              <param name="namespace">/</param>  
            </result>  
        </global-results>  
       
        <action name="exception" class="com.tail.test.actions.ExceptionAction">  
            <result>/exception.jsp</result>  
        </action>  
       
        <action name="home" class="com.tail.test.actions.StrutsTestAction">  
            <result>/userMessage.jsp</result>  
            <result name="input">/userMessage.jsp</result>  
        </action>  
    </package>  
       
    <package name="tail-json" namespace="/page" extends="test">  
        <global-results>  
            <!-- Don't redirect to login for ajax requests. -->  
            <result name="login" type="httpheader">  
                <param name="status">403</param>  
            </result>  
            <!-- Send a 503 for errors in ajax requests. -->  
            <result name="error" type="httpheader">  
                <param name="status">503</param>  
            </result>  
        </global-results>  
    </package>  
       
    <package name="tail-home" namespace="/home" extends="tail-json">  
        <global-results>  
            <result name="input" type="json">  
                <param name="includeProperties">  
                    result, actionErrors.*, fieldErrors.*   
                </param>  
            </result>  
        </global-results>  
        <action name="loadMessages" method="loadMessages"  
            class="com.tail.test.actions.StrutsTestAction">  
           <result type="json">  
                <param name="includeProperties">  
                    result, messageList.*   
                </param>  
            </result>  
        </action>  
        <action name="addMessageToUser" method="addMessageToUser"  
            class="com.tail.test.actions.StrutsTestAction">  
           <result type="json">  
                <param name="includeProperties">  
                    result, messageList.*   
                </param>  
            </result>  
        </action>  
    </package>  
</struts> 

 

其中定义了三个package,前两个package没有什么好讲的,如果要详细了解其配置原理,可以参考Struts2的官方文档。

 

大家注意到,针对StrutsTestAction事实上已经在第一个package中定义了一次,为什么在第三个tail-home包中也要定义一遍呢,看到其中的json result的定义,大家应该也就看出其中的异样了。

 

不错,这里的定义主要是为了利用Struts JSON的插件功能将Action中的一个或多个属性/对象转换为json对象,提供到UI层去使用。而第一个package中定义的action,仅仅是页面第一次进入时的入口。

 

这里的result和messageList.*则是对StrutsTestAction的result和messageList属性的对外公布,includeProperties节点是支持正则表达式的,当然还有其他的json param,详细地大家可以参考struts2-jsonplugin-0.6.jar中的定义。

 

这里提到一个messageList,主要是给大家谈谈Struts2的conversion的支持,看看StrutsTestAction-conversion.properties文件的内容,大家应该就明白了。

Element_messageList = com.tail.test.objects.Message
CreateIfNull_messageList = true

 

不错,这里的定义主要是为了让json对象能被解析和传输。精确一点地说,在Action->UI的时候,他事实上用处不大,或者说可以省去。但是,如果如果经历UI->Action的时候,这个conversion定义就是必须的,否则Struts Action无法理解UI传送过来的数据。

 

   发表时间:2008-03-25  
Where is the "RICH" client?
0 请登录后投票
   发表时间:2008-03-25  
Here is just a demo for RICH client.

You may take a look at my following article "http://tailsherry.iteye.com/blog/149892"
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics