2009-09-30 18 views
25

我有一個處理多部分表單帖子的servlet。這篇文章實際上是通過嵌入頁面的Flash文件上傳組件製作的。在一些瀏覽器中,Flash生成的POST不包含JSESSIONID,這使得我無法在後期加載會話中的某些信息。如何使用JSESSIONID手動加載Java會話?

Flash上​​傳組件在特殊的表單域中包含cookie和會話信息。使用這個表單字段,我實際上可以檢索JSESSIONID值。問題是,我不知道如何使用此JSESSIONID值手動加載該特定會話。

編輯 -基於ChssPly76的解決方案,我創建了以下HttpSessionListener實現:

@Override 
    public void sessionCreated(final HttpSessionEvent se) { 
     final HttpSession session = se.getSession(); 
     final ServletContext context = session.getServletContext(); 
     context.setAttribute(session.getId(), session); 
    } 

    @Override 
    public void sessionDestroyed(final HttpSessionEvent se) { 
     final HttpSession session = se.getSession(); 
     final ServletContext context = session.getServletContext(); 
     context.removeAttribute(session.getId()); 
    } 

它增加了所有會話的ServletContext的由它們的唯一ID映射的屬性。我可以在上下文中放置一個會話地圖,但似乎是多餘的。請發表任何關於這個決定的想法。接下來,我將以下方法添加到我的servlet通過ID來解決會話:

private HttpSession getSession(final String sessionId) { 
     final ServletContext context = getServletContext(); 
     final HttpSession session = (HttpSession) context.getAttribute(sessionId); 
     return session; 
    } 
+0

+1 ..非常好的問題 – peakit 2009-09-30 17:38:02

回答

21

沒有API通過id檢索會話。

但是,您可以執行的操作是在您的Web應用程序中實施session listener,並手動維護由id標識的會話映射(會話標識可通過session.getId()獲取)。然後你將能夠找回你想要的任何會話(而不是像其他人所建議的那樣,用它來替換你的當前會話)

+0

這很聰明。 – 2009-09-30 17:46:32

+1

我唯一關心的是人爲錯誤部分,你將有一個開發人員使用request.getSession()來引入一些代碼,而不是使用會話ID的映射。我相信「更簡單」的解決方案是適當構建URL。 – 2009-09-30 17:48:51

+0

我可以想象servlet向會話映射提供監聽器的兩種方式:listener是一個單例,或者將映射放置在ServletContext中。 – rcampbell 2009-09-30 18:04:53

1

還有就是Servlet規範中沒有辦法,但你可以嘗試:

  • 手動設置在cookie由Flash提出的請求

  • 或者像Taylor L那樣做,因爲我正在鍵入並將jsessionid參數添加到URI的路徑中。

這兩種方法都會將您的應用綁定到運行在類似於Tomcat的servlet容器上;我認爲他們中的大多數人都會。兩者都需要您的Flash小程序向頁面詢問其Cookie,這可能會強加JavaScript依賴性。

0

這是一個非常好的帖子。使用會話監聽器向會話添加會話時看到的一個潛在問題是,根據您擁有的併發會話數量,會變得很胖。然後是監聽器的Web服務器配置的所有額外工作。

那麼這個如何更簡單的解決方案。我確實實現了這一點,它工作得很好。因此,在加載Flash上​​傳對象的頁面上,將session和sessionid作爲鍵值對存儲在應用程序對象中,然後將該會話ID作爲post參數傳遞給上載頁面。在上傳頁面上,查看sessionid是否已經在應用程序中,是否如此使用該會話,否則,從請求中獲取該sessionid。此外,然後繼續並從應用程序中刪除該密鑰,以保持一切清潔。

在SWF頁:

application.setAttribute(session.getId(), session); 

然後上傳頁面上:

很不錯的解決方案傢伙。謝謝你。

+5

「挺胖」?你測過它了嗎?你熟悉Java嗎?這只是一個參考,不是價值的副本... – BalusC 2012-08-12 00:47:14

+0

糟糕,你是對的。沒有想到通過。儘管如此,更容易實施原來的建議。另外,由於我已經完全測試了這個代碼,我發現了以下內容。如果原始海報特別提到了SWFUpload,那麼當您上傳多個文件時,SWFUpload會單獨發佈每個文件,而不是全部發布在一個帖子中。所以通過在第一次上傳之後從應用程序對象中刪除會話,所有其他人都失敗了。僅供參考。 – Garfield 2012-08-12 12:18:44

2

一個安全的方法是在Cookie中設置jsession id - 這比在url中設置更安全。

一旦它被設置爲一個cookie,那麼您可以在使用

request.getSession(); 

method.setRequestHeader("Cookie", "JSESSIONID=88640D6279B80F3E34B9A529D9494E09"); 
0

如果您使用的是Tomcat正常的方式檢索會話,你的tomcat直接詢問(但它的醜陋)。我敢打賭,其他網絡服務器還有其他的黑客解決方案。

它使用「管理器」界面的一個實例來管理會話。是什麼讓它變得醜陋是因爲我沒有找到一個好的公共接口能夠接入,所以我們必須使用反射來獲得經理。

下面是一個上下文偵聽器,它在上下文啓動時抓取該管理器,然後可用於獲取Tomcat會話。

public class SessionManagerShim implements ServletContextListener { 
    static Manager manager; 

    @Override 
    public void contextInitialized(ServletContextEvent sce) { 
     try { 
      manager = getManagerFromServletContextEvent(sce); 
     } catch (NoSuchFieldException | IllegalAccessException e) { 
      e.printStackTrace(); 
     } 
    } 

    @Override 
    public void contextDestroyed(ServletContextEvent sce) { 
     manager = null; 
    } 

    private static Manager getManagerFromServletContextEvent(ServletContextEvent sce) throws NoSuchFieldException, IllegalAccessException { 
     // Step one - get the ApplicationContextFacade (Tomcat loves facades) 
     ApplicationContextFacade contextFacade = (ApplicationContextFacade)sce.getSource(); 

     // Step two - get the ApplicationContext the facade wraps 
     Field appContextField = ApplicationContextFacade.class.getDeclaredField("context"); 
     appContextField.setAccessible(true); 
     ApplicationContext applicationContext = (ApplicationContext) 
       appContextField.get(contextFacade); 

     // Step three - get the Context (a tomcat context class) from the facade 
     Field contextField = ApplicationContext.class.getDeclaredField("context"); 
     contextField.setAccessible(true); 
     Context context = (Context) contextField.get(applicationContext); 

     // Step four - get the Manager. This is the class Tomcat uses to manage sessions 
     return context.getManager(); 
    } 

    public static Session getSession(String sessionID) throws IOException { 
     return manager.findSession(sessionID); 
    } 
} 

您可以將其添加爲您的web.xml中的偵聽器,它應該可以工作。

然後你可以這樣做來獲得一個會話。