2013-04-30 149 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

相关问题