代码改变世界

sturts2架构,后台向前端传递消息应该怎么设计?

2014-01-17 17:44  _cha1R  阅读(256)  评论(0编辑  收藏  举报

在开发WEB项目时,我们经常需要再后台代码里向前端页面传递消息。例如当用户登陆后,向用户提示登陆成功。

在我们最初学习的时候,我们一般会在action里写上一个message变量,然后提供get set方法。当我们在action 返回result后转发到jsp页面,那样在jsp页面就可以用el表达式或者ognl表达式获取到。

public class UserAction {
    private String message;
    
    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }
    public String execute()throws Exception {
        return SUCCESS;
    }
}

后来我发现这种方式不太好。

首先,我们填写完账户和密码的时候,跳转到action,然后action跳转到index.jsp,index.jsp是主页,但是提示登录成功。看起来一切都很好,但是当我习惯性的按了下F5刷新的时候,我发现浏览器提示我在尝试重复提交表单,是否要重复提交这个表单(即重复登录)。

我顿时就觉得这用户体验太不行,起码目前来说,有哪个网站是首页刷新会提示这个的。。

于是我想到了redirect,在struts.xml里配上:

<result name="index" type="redirect">/index.jsp</result>

重启,重新登陆。一切似乎很顺利,跳到index.jsp,刷新,没提示我重复提交。。

但是我发现“登陆成功”的提示不见了。。原因很显然,我redirect后,在ValueStack里的message变量已经被清空.

那这时候就只能依赖session了。于是我参考了新浪微博的一个设计:每一个账号拥有自己的一个消息队列(猜的)。

我写了一个类,专门用来存取消息的,这个类很简单:

package cn.tanjiay.mbt.pojo;

import java.util.LinkedList;

/**
 * 消息队列,该对象会放在Session中,以先进先出的方式。
 * 每次获取后会清除该消息
 * @author _cha1R
 * @data 2014-1-17
 */
public class MessageQueue {
    LinkedList<String> messageList = new LinkedList<String>();
    public void putMessage(String message){
        messageList.addLast(message);
    }
    public String getMessage(){
        return messageList.pollFirst();
    }
}

这个类型依赖了LinkedList类,但是我为什么不直接用LinkList呢?很简单的原因。我在jsp页面用了el表达式。

在我写${message}的时候,el会找到getMessage()方法,调用它然后返回值显示子页面上。所以我顺便改了一下getMessage()方法和setMessage()方法:

/**
     * 获取一个消息
     * @return
     */
    public String getMessage() {
        MessageQueue mq = getFromSession("messageQueue");
        if(mq == null){
            return null;
        }
        return mq.getMessage();
    }
    
    /**
     * 向session消息队里推送一个消息
     * @param message
     */
    public void setMessage(String message) {
        MessageQueue mq = getFromSession("messageQueue");
        if(mq == null){
            mq = new MessageQueue();
            put2Session("messageQueue", mq);
        }
        mq.putMessage(message);
    }

setMessage()方法每次都会判定session里有没有消息队列,如果没有就创一个丢进session。然后往session里的消息队列存放消息。

当调用getMessage()的时候,就可以拿到存放的消息。而且只能拿一次。

这样就实现了一个session一个消息队列。