【问题标题】:Inject HttpServletRequest in CDI SessionScoped bean在 CDI SessionScoped bean 中注入 HttpServletRequest
【发布时间】:2013-08-12 14:17:27
【问题描述】:

我有一个会话范围的 CDI bean,我需要以某种方式访问​​此 bean 的 @PostConstruct 方法中的 HttpServletRequest 对象。可能吗?我试图注入这样一个对象,但结果是:

WELD-001408 Unsatisfied dependencies for type [HttpServletRequest] with qualifiers     [@Default] at injection point [[field] @Inject ...]

我在谷歌搜索时了解到,Seam 框架具有这样的功能,但我在 GlassFish 服务器上有一个标准的 Java EE 应用程序。

是否有可能以某种方式将请求传递给 CDI bean 的 @PostConstruct 方法?

【问题讨论】:

  • 貌似要访问请求查询字符串参数吧?
  • 我要访问 UserPrincipal
  • Injection of HttpServletRequest 的可能重复项
  • 我已经看到了这个话题,但是@Context 注释使我的 bean 的钝化崩溃了,当我有这个注释时,我不能再注入我的 bean(bean 已经实现了 Serializable)。
  • @Luiggi(和 wojetk)我发现那个副本也很好奇。 @Context 注释仅适用于 JAX-RS webservice 类(就像 @ManagedProperty 仅适用于 JSF 托管 bean 类)。但是,问题中的 nothing 表明 OP 正在使用 JAX-RS,而答案中的 nothing 表明 @Context 仅限于 JAX-RS Web 服务。然而答案被接受并且OP确认它有效。这要么是一个很大的巧合,而且是一个非常好的盲目猜测,要么是 OP 在撒谎。

标签: java jakarta-ee cdi


【解决方案1】:

根据您的评论,您希望访问用户主体。你可以像这样注入它:@Inject Principal principal;@Resource Principal principal;,参见Java EE 6 Tutorial

更新

我会回答你的直接问题。在 Java EE 7 (CDI 1.1) 中,支持开箱即用的 HttpServletRequest 注入。但是,在 Java EE 6 (CDI 1.0) 中,不支持开箱即用。要使其正常工作,请将以下类包含到您的网络应用中:

import javax.enterprise.inject.Produces;
import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;

@WebListener
public class CDIServletRequestProducingListener implements ServletRequestListener {

    private static ThreadLocal<ServletRequest> SERVLET_REQUESTS = new ThreadLocal<>();

    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        SERVLET_REQUESTS.set(sre.getServletRequest());
    }

    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        SERVLET_REQUESTS.remove();
    }

    @Produces
    private ServletRequest obtain() {
        return SERVLET_REQUESTS.get();
    }

}

注意:仅在 GlassFish 3.1.2.2 上测试

【讨论】:

  • 施威特!这行得通!但是,我确实需要将自己的限定符添加到 obatain() 方法和注入点。但除此之外,请注意!
  • 如果它被注入到 SessionScoped bean 或任何其他具有钝化上下文的 bean 中,我认为它不会正确处理钝化?
【解决方案2】:

使用 rdcrng 中的代码时,请注意以下几点:
* 生产者方法obtain 是依赖作用域的,因此对于应用程序作用域的 bean 仅调用一次(并且将解决除第一个请求之外的所有其他请求的问题)
* 你可以用@RequestScoped解决这个问题
* 当RequestScoped注解时,你只会得到一个代理,因此你不能将它转换为HttpServletRequest。因此,您可能需要 HttpServletRequest 的生产者。

另请注意:根据 CDI 规范 link 第 3.6 段,java ee bean 不被视为托管 bean。因此,您最终会得到两个CDIServletRequestProducingListener 实例——一个由Java EE 容器管理,一个由CDI 容器管理。它之所以有效,是因为 SERVLET_REQUESTS 是静态的。

为方便起见,请遵循修改后的代码。

import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Produces;
import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpServletRequest;

@WebListener
public class CDIServletRequestProducingListener implements ServletRequestListener {

private static ThreadLocal<ServletRequest> SERVLET_REQUESTS = new ThreadLocal<ServletRequest>();

@Override
public void requestInitialized(ServletRequestEvent sre) {
    SERVLET_REQUESTS.set(sre.getServletRequest());
}

@Override
public void requestDestroyed(ServletRequestEvent sre) {
    SERVLET_REQUESTS.remove();
}

@RequestScoped
@Produces
private HttpServletRequest obtainHttp() {
    ServletRequest servletRequest = SERVLET_REQUESTS.get();
    if (servletRequest instanceof HttpServletRequest) {
        return (HttpServletRequest) servletRequest;
    } else {
        throw new RuntimeException("There is no HttpServletRequest avaible for injection");
    }
}

}

【讨论】:

    猜你喜欢
    • 2016-08-02
    • 1970-01-01
    • 2019-08-04
    • 1970-01-01
    • 2015-07-14
    • 2014-10-20
    • 2016-12-04
    • 2013-06-30
    相关资源
    最近更新 更多