【问题标题】:Access FacesContext in CDI bean injected in servlet-filter在 servlet-filter 中注入的 CDI bean 中访问 FacesContext
【发布时间】:2017-09-24 10:52:43
【问题描述】:

我有以下要注入 CDI bean 的 servlet

public class FBOAuthFilter implements Filter {
    @Inject 
    private Instance<LoginBean> loginBeanSource;


    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
        FilterChain fc) throws IOException, ServletException {
        try{
           String code = request.getParameter("code");
           LoginBean loginBean = loginBeanSource.get();
           loginBean.doLogin(code);
        } catch(Exception ex){
           System.out.println("Exception");
        }
   }
}

CDI 豆:

@Named(value="loginbean")
@SessionScoped
public class LoginBean implements Serializable{



     public void doLogin(String code){
        //do something

        FacesContext context = FacesContext.getCurrentInstance();
        System.out.println(context == null);
        context.getExternalContext().redirect("somepage");

    }
}

但是,当我尝试访问 CDI Bean 中的 FacesContext 时,它为空。有没有办法访问 FacesContext ?

【问题讨论】:

  • FacesContext 是在 FacesServlet 中创建的。因为过滤器在 servlet 之前执行,所以 FacesContext 还不可用。为什么需要 FacesContext?没有它你能应付吗?
  • @tuner 我的大部分业务逻辑都是在 servlet 过滤器中完成的,我可以做一个解决方法并将所有内容移至 Faces Servlet,但我想知道在 servlet-filter 中访问 FacesContext 并获得CDI bean 的实际实例,而不是代理。

标签: jsf servlets cdi servlet-filters


【解决方案1】:

这不是正确的方法。

所有过滤器 servlet 被命中之前运行。 FacesContext 仅在FacesServlet 被点击时可用。所以只要FacesServlet 还没有被击中,那么FacesContext 还不可用。所以在所有过滤器中总是null

您需要重写代码,以便您可以在过滤器中仅使用现成的requestresponse 对象和CDI,而不依赖FacesContext。您似乎只想执行重定向。 “普通的”servlet 方式是:

response.sendRedirect("somepage");

为了正确使用它,只需将您的 LoginBean 代码拆分为两个新 bean:一个不使用 javax.faces.* 的东西,另一个需要 javax.faces.* 的东西。没有使用javax.faces.*的东西可以被过滤器和托管bean共享。

@Dependent
public class LoginBeanWithoutFacesContext implements Serializable {

    public void doLogin(String code) {
        // do something without faces context
    }
}

@Named
@SessionScoped
public class LoginBean implements Serializable {

     @Inject
     private LoginBeanWithoutFacesContext loginBeanWithoutFacesContext;

     public void doLogin(String code) {
         loginBeanWithoutFacesContext.doLogin(code);

         FacesContext context = FacesContext.getCurrentInstance();
         context.getExternalContext().redirect("somepage");
    }
}

最后在您的过滤器中使用LoginBeanWithoutFacesContext

public class FBOAuthFilter implements Filter {

    @Inject 
    private LoginBeanWithoutFacesContext loginBeanWithoutFacesContext;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        try {
            String code = request.getParameter("code");
            loginBeanWithoutFacesContext.doLogin(code);
            response.sendRedirect("somepage");
        }
        catch (Exception e) {
            throw new ServletException(e);
        }
    }
}

也就是说,考虑使用 JEE 标准身份验证或完善的库,而不是使用某些本地身份验证来完成您显然在 LoginBeanWithoutFacesContext 中所做的工作。另见How to handle authentication/authorization with users in a database?

【讨论】:

  • 我知道有一个关于(不是!)在过滤器中执行业务逻辑的问答。无法直接找到它,但它会是这个答案'另见'部分中的一个很好的补充
  • @Kukeltje:这取决于功能要求。在这种情况下,它似乎是通过某种令牌进行的某种自动登录,该令牌可以出现在任何任意 URL 上。在工作中使用过滤器并非不合理。登录本身显然是本土代码,而不是使用已建立的库,这反过来确实通常是一种糟糕的做法。但从技术上讲,这个问题与此无关。
  • 正确,我更多的是指 OP 的声明,即所有业务逻辑都在过滤器中完成,而不是特别是登录部分......
  • @Kukeltje:哦,在对他问题的评论中。抱歉,我没看到。似乎与技术问题无关。
猜你喜欢
  • 2012-12-10
  • 2017-06-03
  • 2011-05-29
  • 2014-03-20
  • 1970-01-01
  • 1970-01-01
  • 2017-02-16
  • 2014-04-23
相关资源
最近更新 更多