2013-04-30 96 views
2

好的,我對這個主題有一個賞金,只有部分答案,所以我打開這個主題並簡化主題,因爲我猜原來的主題太臃腫了。服務工廠實例化bean如何訪問httpServletRequest對象?

我面臨的情況是,我基本上有一個過濾器,它從servlet上下文獲取Spring服務工廠對象,當過濾器調用它的getService方法時,該工廠分配一個bean的實例,但我需要訪問會話或請求的實際httpServletRequest對象,因爲我需要來自請求的用戶ID。我認爲,從我讀過的內容來看,我不應該將它傳遞給bean,這不僅因爲它不是線程安全的,而且還因爲它會打破擁有過濾器的遠程服務橋(CP2JavaWS)的抽象。

我怎樣才能讓這個bean訪問會話或httpServletRequest?

我嘗試使用FacesContext,但它沒有奏效,因爲我認爲這個bean沒有被一個jsp調用實例化,而是來自一個過濾器。

現在有些代碼。

這是我的web.xml

<display-name>CP2JavaWSTest</display-name> 
<welcome-file-list> 
    <welcome-file>index.html</welcome-file> 
</welcome-file-list> 

<error-page> 
    <error-code>404</error-code> 
    <location>/err.jsp</location> 
</error-page> 

<context-param> 
    <param-name>contextConfigLocation</param-name> 
    <param-value>/WEB-INF/applicationContext*.xml</param-value> 
</context-param> 
<listener> 
<listener-class> 
    org.springframework.web.context.request.RequestContextListener 
</listener-class> 

<listener> 
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
</listener> 

<listener> 
    <listener-class>com.cp2javaws.listeners.SpringContextWrapperListener</listener-class> 
</listener> 

<listener> 
    <listener-class>com.bucle.listeners.BCLUserDatabaseContextListener</listener-class> 
</listener> 

<filter> 
    <filter-name>BCLAuthenticationFilter</filter-name> 
    <filter-class>com.bucle.filters.BCLAuthenticationFilter</filter-class> 
</filter> 

<filter> 
    <filter-name>BCLAuthorizationFilter</filter-name> 
    <filter-class>com.bucle.filters.BCLAuthorizationFilter</filter-class> 
</filter> 
<filter> 
    <filter-name>CPJSonFilter</filter-name> 
    <filter-class>com.cp2javaws.filters.CPJSonFilter</filter-class> 

</filter> 

應用程序上下文:

<bean id="service1" class="com.bucle.database.BCLDb4oManager" scope="request"/> 
    <bean id="service2" class="com.bucle.services.appe.BCLUserCFVC"/> 
    <bean id="service3" class="com.bucle.services.appe.BCLUserCustomizedFutureValueCalculator"/> 

的CPWJavaWS過濾

public class CPJSonFilter implements Filter { 

    //.. properties 

    public void init(FilterConfig filterConfig) 
    throws ServletException { 
    //.. init code 
    } 

    public void destroy() { 
     //.. 
    } 

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
     throws IOException, ServletException { 


     HttpSession session = ((HttpServletRequest)request).getSession(true); 

     //..Class and method decoding and mapping from JSON 

       Class type = null; 
       String value = request.getParameter(CP2JavaWSRequestParameterType+paramOrderString); 
       if(paramName.indexOf(CP2JavaWSRequestGenericParamSuffix)>0 || request.getParameter(CP2JavaWSRequestParameterType+paramOrderString).equals("id")) {//SAMIR 
        type = Object.class; 
       } else { 
        if(paramName.indexOf(CP2JavaWSRequestNullParamSuffix)>0) { 
         String CPClassName = paramName.substring(paramName.indexOf(CP2JavaWSRequestNullParamSuffix)+CP2JavaWSRequestNullParamSuffix.length()); 
         try { 
          type = getJavaClassForCPClass(CPClassName); 
         } catch (CP2JavaWSException e) { 
          throw new ServletException("Cannot find corresponding Java class for null argument at index "+paramOrderString+" (passed CP class name is"+CPClassName+")"); 
         } 
        } else if(List.class.isAssignableFrom(convertedObject.getClass())) { 
         type = List.class; 
        } else if(Map.class.isAssignableFrom(convertedObject.getClass())) { 
         type = Map.class; 
        } else { 
         type = convertedObject.getClass(); 
        } 
       } 
       typesOrderedMap.put(new Integer(paramOrderString), type); 
      } 
     } 
     // invoke the service method using the provided service factory class 
     Object result = null; 
     try { 
       Class serviceInterfaceClass = Class.forName(serviceInterfaceName); 
       ServiceFactory serviceFactory = (ServiceFactory) filterConfig.getServletContext().getAttribute(ServiceFactory.CP2JAVAWS_SERVICES_FACTORY); 
       Object service = serviceFactory.getService(serviceInterfaceClass); 


       Method method = service.getClass().getDeclaredMethod(serviceMethodName, (Class[]) typesOrderedMap.values().toArray(new Class[typesOrderedMap.size()])); 
       result = method.invoke(service, argumentsOrderedMap.values().toArray()); 

     } catch(Exception e) { 
      throw new ServletException("Error invoking the service method :"+serviceMethodName+" on service "+serviceInterfaceName,e); 
     } 

     //...Convert result to JSON 
      response.setContentType("application/json"); 
      PrintWriter writer = response.getWriter(); 
    StringBuffer stb = new StringBuffer(); 

      //... append result and some other stuff to the string buffer stb 

     response.setContentLength(stb.length()); 
     ((HttpServletResponse)response).setStatus(HttpServletResponse.SC_OK); 
     writer.write(stb.toString()); 
     writer.flush(); 
    } 

    public static Class getJavaClassForCPClass(String CPClassName) throws CP2JavaWSException { 
    //... returns the matching Class.class according to a default map like: CPArray -> List.class 
    } 
} 

這是Spring上下文監聽器:

public class SpringContextWrapperListener implements ServletContextListener { 


    private ServletContext context = null; 


    public void contextDestroyed(ServletContextEvent event) { 
     this.context = null; 
     //log.info("Spring Context Destruido"); 
    } 


    public void contextInitialized(ServletContextEvent event) { 
     this.context = event.getServletContext(); 
     ApplicationContext springContext = (ApplicationContext) WebApplicationContextUtils.getRequiredWebApplicationContext(this.context); 
     SpringContextWrapper aSpringContextWrapper = new SpringContextWrapper(springContext); 
     this.context.setAttribute(ServiceFactory.CP2JAVAWS_SERVICES_FACTORY, aSpringContextWrapper); 
    } 
} 

和工廠:

public class SpringContextWrapper implements ServiceFactory { 

private ApplicationContext springContext; 

public SpringContextWrapper(ApplicationContext springContext) { 

    this.springContext = springContext; 
} 

public Object getService(Class serviceInterfaceClass) throws CP2JavaWSException { 

    Map services = this.springContext.getBeansOfType(serviceInterfaceClass); 
    Iterator it = services.values().iterator(); 
    if(it.hasNext()) { 
     return it.next(); 
    } 
    throw new CP2JavaWSException("can't find service for interface "+serviceInterfaceClass.getName()); 
} 

public Object getService(String serviceName) throws CP2JavaWSException { 

    Object service = this.springContext.getBean(serviceName); 
    if(service==null) { 
     throw new CP2JavaWSException("can't find service for name "+serviceName); 
    } 
    return service; 
}} 
+0

我張貼此作爲一個評論,因爲我還沒有使用它factorymethods但僅限於控制器尚未:使用Spring,你可以使用參數解析器注入需要的對象成你的方法。有一個localeargumentresolver以及您可以在您的請求映射方法中使用的requestargumentresolver。基本上這些是關於如何處理框架調用的方法的參數的合約。也許這只是工廠方法? – 2013-04-30 05:03:54

+0

謝謝你回答馬丁,NilsH的答案很容易測試,它確實有用,但我會更深入地研究你對解決問題的解決方案的回答,因爲我的春天的知識是基本的。它也可能工作。不要擔心,我不會投下它。 – Jigzat 2013-05-01 21:05:31

回答

2

我不是100%肯定我明白了這個問題,但我認爲可以使用RequestContextHolder爲你在做什麼。

ServletRequestAttributes attrs = (ServletRequestAttributes)RequestContextHolder.currentRequestAttributes(); 
HttpServletRequest req = attrs.getRequest(); 

但是,看到一些代碼會有所幫助。我懷疑你可能會用你的bean的正確scope來達到你想要的。

+0

謝謝,讓我試試看,我會發布一些代碼。我不想要,因爲我試圖讓帖子更具可讀性,但在我們用代碼表達的時候。 – Jigzat 2013-04-30 23:48:52

+0

它實際上工作,尤里卡!現在我有一個很好的db4o文件,每個用戶名註冊和登錄。我沒有選擇作爲一個明確的答案,因爲我需要測試多個用戶登錄在同一個,我真的很想第二個意見,請不要冒犯,只是我希望我不必依賴Spring。你認爲我應該添加一個原型標籤到bean的XML配置? – Jigzat 2013-05-01 21:08:39

+0

如果除了你需要的請求對象之外,你的方法中沒有任何狀態,那麼它不需要是原型。但是我詢問有關som使用示例的原因是因爲我懷疑你可能能夠使用Spring'request'範圍或自定義作用域。 – NilsH 2013-05-01 21:18:05

1

您可以使用threadlocal存儲一個對象,該對象將原始HttpServletRequest和HttpServletResponse包裝在您的過濾器的doFilter方法中,然後從bean中的threadlocal訪問此包裝器對象。下面是一個粗略的實現,你會如何實現它:

public class WebRequest { 

    private HttpServletRequest request; 

    private HttpServletResponse response; 

    public WebRequest(HttpServletRequest request, HttpServletResponse response) { 
     this.request = request; 
     this.response = response; 
    } 
} 

class WebRequestUtils { 

    private static ThreadLocal<WebRequest> webRequest; 

    public static void setWebRequest(WebRequest value) { 
     webRequest.set(value); 
    } 

    public static WebRequest getWebRequest() { 
     return webRequest.get(); 
    } 
} 

class CustomFilter { 

    doFilter(HttpServletRequest request, HttpServletResponse response) { 
     WebRequest webRequest = new WebRequest(request, response); 
     WebRequestUtils.setWebRequest(webRequest); 
    } 
} 

class Bean { 

    void someMethod() { 
     WebRequest webRequest = WebRequestUtils.getWebRequest(); 
    } 
} 
+0

正如NilsH提到的RequestContextHolder將是另一個,可能是一個更乾淨的方式來實現相同的事情。 – 2013-04-30 05:26:24

+0

是的,這基本上是'RequestContextHolder'已經做的。 – NilsH 2013-04-30 05:58:52

+0

謝謝大家的回答。是的,我在CP2JavaWS中看到了一些使用threadLocal請求某些內容的東西,但看起來有點奇怪。這可能是其中一件看起來像黑客行爲的事情,但最終卻是正確的做法。我會檢查它。 – Jigzat 2013-04-30 23:47:40