【永恒的瞬间】
☜Give me hapy ☞
Flex Remote Object中直接使用HttpSession的方法

问题的背景

Flex Remote Object可以是POJO,JavaBean或是EJB。在面向服务的架构中(Service Oriented Architecture),我们可以用Remote Object来作为Service Facade,利用应用服务器提供的persistent service来储存状态信息。

Flex既可以提供stateful或stateless的remote object, 另外还有session servlet让mxml获取/和储存session中的内容。这一切听上去都很完美,但是有一个问题,Flex Remote Object本身是无法获得任何有关Running Context的信息,也就是说,你无法从你的 Remote Object 中获得 HttpSession, HttpRequest 和 ServletContext。 所谓的 Flex Session servlet只是让MXML获得session的内容,而不是直接让Remote Object获得session。

Remote Object为什么需要获得HttpRequest, HttpSession?
既然Flex提供了stateful的remote object为什么还要让remote object获得Running Context呢?问题在于Flex中的stateful是基于应用服务器的http session,而且你无法控制AMFGateway建立remote object的过程。打个简单的比方,我们知道一般的应用服务器中,session的时限只有20分钟,而在很多系统的登陆过程中却有选择保持登陆几个月的选项。

其具体实现上就是利用cookie来储存id和password hash,通过控制cookie的存活时间来实现的。而在服务器端,一旦session过期了,则可以从cookie中获得id和password hash重新登陆一遍,从而达到自动认证用户的目的。

如果你的Remote Object无法获得 HttpServletRequest, HttpSession,你就无法实现上述的情况。另外,对于小型的应用来说,直接在Remote object中获得servlet context并利用它来储存/获得共享的资源,可以大大降低开发的复杂程度。

解决方案
要让Remote Object获得HttpSession,HttpRequest和ServletContext并不是一件容易的事情。这里提供了我的一种方法,供大家参考。希望能抛砖引玉,让大家提出更好,更有效的方案。

这个方法的基本思路是利用JAVA提供的 ThreadLocal Object。当服务器接收到一个HTTP请求后,这个请求的整个处理过程是运行在同一个线程中的。

每个HTTP请求的处理会都运行在各自独立的线程中。而在Flex中,所有AMF Remote Object 的请求都需要通过 AMF Gateway Servlet,而Remote Object 的建立和调用恰恰就是运行在这个HTTP请求的线程中。

有了这个原则,我们就可以建立一个Context Object,每当请求建立的时候,就可以把这个请求放入 Context 的 ThreadLocal 中,而当 Remote Object 被AMF Gateway Servlet调用的时候,就可以通过访问 Context 的ThreadLoca l来获得其所对应的那个请求。

而截获发送到AMF Gateway的请求则可以通过Servlet Filter来实现。废话不说了,看代码吧!



1. 添加以下内容到WEB-INF/web.xml中

 <filter>
    <filter-name>AMFSessionFilter </filter-name>
    <filter-class>com.netop.forum.servlets.AMFSessionFilter </filter-class>
  <filter>

  <filter-mapping>
    <filter-name>AMFSessionFilter </filter-name>
    <servlet-name>AMFGatewayServlet </servlet-name>
  <filter-mapping>      


2. AMFSessionFilter的代码

/*
* Created on 1/07/2004
*/
package com.netop.forum.servlets;


import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.*;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
* @author Zombie
* @version 0.5
*/

public class AMFSessionFilter implements Filter
{
     private static Log log = LogFactory.getLog(AMFSessionFilter.class);
     
     public void init(FilterConfig config)
     {            
           log.info("Init AMFSessionFilter filter");
     }
     
     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException,IOException
     {                  
           AMFContext.setCurrentContext((HttpServletRequest)request, (HttpServletResponse)response);            
           chain.doFilter(request,response);            
     }
     
     public void destroy()
     {
           log.info("Destory AMFSessionFilter filter");
     }
}


3. AMFContext的代码

/*
* Created on 1/07/2004
*/
package com.netop.forum.servlets;


import javax.servlet.*;
import javax.servlet.http.*;
import com.netop.forum.business.*;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
* @author Zombie
* @version 0.5
*/
public class AMFContext
{      
     
     /**
      * Context Attribute key for the connection the factory
      */
     public final static String CONNECTION_FACTORY_KEY = "sqlMapFactory";      

     /**
      * The log
      */
     private static Log log = LogFactory.getLog(AMFContext.class);      

     /**
      * ThreadLocal object for storing object in current thread.
      */
     private static ThreadLocal tl = new ThreadLocal();
     
     /**
      * Set current context
      *
      * @param request The HttpRequest object
      * @param response The HttpResponses object
      */
     static public void setCurrentContext(HttpServletRequest request, HttpServletResponse response)
     {
           AMFContext c = getCurrentContext();
           if (c == null)
           {
                 c = new AMFContext(request,response);
                 tl.set(c);
           }
           else
           {
                 c.setRequest(request);
                 c.setResponse(response);
           }            
     }
     
     /**
      * Get current context value
      * @return The current context
      */
     static public AMFContext getCurrentContext()
     {
           return (AMFContext)tl.get();
     }
     
     
     
     
     
     //----------------------------------------------------------
     //
     // Class members
     //
     //----------------------------------------------------------
     
     /**
      * The http request object. The lifecycle of the request object is defined as the request
      * scope. It may be reused in another incoming connection, so dont use it in another thread.
      */
     private HttpServletRequest request;
     
     /**
      * The http response object. The lifecycle of the response object is defined as the request
      * scope. Dont use it in another thread. Also dont write output to the response when it is
      * used in the context, but you may get or set some response header when it is safe.
      */
     private  HttpServletResponse response;
     
     
     /**
      * The constructor is private, to get an instance of the AMFContext, please use
      * getCurrentContext() method.
      *
      * @param request
      * @param response
      */
     private AMFContext (HttpServletRequest request, HttpServletResponse response)
     {
           this.request = request;
           this.response = response;
     }
     
     
     /**
      * Get request object
      *
      * @return Http request object
      */
     public HttpServletRequest getRequest()
     {
           return request;
     }

     /**
      * Set request object
      *
      * @param Http request object
      */
     public void setRequest(HttpServletRequest request)
     {
           this.request = request;
     }

     /**
      * Get response object
      *
      * @return Http response object
      */
     public HttpServletResponse getResponse()
     {
           return response;
     }

     /**
      * Set response object
      *
      * @param response Http response object
      */
     public void setResponse(HttpServletResponse response)
     {
           this.response = response;
     }      
     
     /**
      * Get the servlet context
      * @return
      */
     public ServletContext getServletContext()
     {
           HttpSession session = this.getSession();
           return session.getServletContext();
     }
     
     /**
      * Get the current running session
      * @return
      */
     public HttpSession getSession()
     {
           return request.getSession();
     }
     
     
     /**
      * Get an object stored in the session.
      *
      * @param attr Attribute Name
      * @return The value stored under the attribute name.
      */
     public Object getSessionAttribute(String attr)
     {
           HttpSession session = this.getSession();
           return session.getAttribute(attr);
     }
     
     /**
      * Store an object in the session.
      *
      * @param attr Attribute Name
      * @param value The value.
      */
     public void setSessionAttribute(String attr, Object value)
     {
           HttpSession session = this.getSession();
           session.setAttribute(attr, value);
     }
     
     /**
      * Get an object stored in the servlet context.
      *
      * @param attr Attribute Name
      * @return The value stored under the attribute name.
      */
     public Object getContextAttribute(String attr)
     {
           ServletContext sc = this.getServletContext();
           return sc.getAttribute(attr);
     }
     
     /**
      * Store an object in the servlet context.
      *
      * @param attr Attribute Name
      * @param value The value.
      */
     public void setContextAttribute(String attr, Object value)
     {
           ServletContext sc = this.getServletContext();
           sc.setAttribute(attr,value);
     }
     
     /**
      * Get an object stored in the current request.
      *
      * @param attr Attribute Name
      * @return The value stored under the attribute name.
      */
     public Object getRequestAttribute(String attr)
     {
           return request.getAttribute(attr);
     }      
     
     /**
      * Store an object in the current request.
      *
      * @param attr Attribute Name
      * @param value The value.
      */
     public void setRequestAttribute(String attr, Object value)
     {
           request.setAttribute(attr,value);
     }

     
     /**
      * Get the connection factory from the servlet context. The connection factory is in the
      * application scope.
      *
      * @return The connection factory for creating sqlMap objects.
      */
     public ConnectionFactory getConnectionFactory()
     {
           ConnectionFactory factory =(ConnectionFactory)this.getContextAttribute(CONNECTION_FACTORY_KEY);            
           if (factory == null)
           {
                 try
                 {
                       factory = new ConnectionFactory();
                       //      factory is lazy instantiated, so we need to invoke it once to make sure it is ok.
                       factory.getSqlMap();
                       this.setContextAttribute(CONNECTION_FACTORY_KEY, factory);                        
                 }
                 catch (Throwable e)
                 {
                       log.fatal("Can not create connection factory: "+e.getMessage(), e);                        
                 }
           }            
           return factory;            
     }
     
}

4. 如何在remote object中使用AMFContext


class YouRemoteService
{
 public void serviceMethod()
 {
   AMFContext context = AMFContext.getCurrentContext();
   HttpSession = context.getSession();
   ServletContext = context.getServletContext();

   HttpServletRequest request = context.getRequest();
   HttpServletResponse response = context.getResponse();

   context.setSessionAttribute("attr","value");
   context.setContextAttribute("attr","value");

 }
}

posted on 2007-02-28 13:38 ☜♥☞MengChuChen 阅读(1695) 评论(0)  编辑  收藏 所属分类: flex2.0

只有注册用户登录后才能发表评论。


网站导航: