Jsf 在注入servlet过滤器的CDIBean中访问FacesContext

Jsf 在注入servlet过滤器的CDIBean中访问FacesContext,jsf,servlets,cdi,servlet-filters,Jsf,Servlets,Cdi,Servlet Filters,我在下面的servlet中注入cdibean public class FBOAuthFilter implements Filter { @Inject private Instance<LoginBean> loginBeanSource; @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain

我在下面的servlet中注入cdibean

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");
        }
   }
}

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

这不是正确的方法

在命中servlet之前,所有过滤器都会运行。FacesContext仅在点击FacesServlet时可用。因此,只要FacesServlet尚未命中,那么FacesContext就不可用。所以在所有过滤器中它总是空的

您需要以这样的方式重写代码:您可以在过滤器中单独使用现成的请求和响应对象以及CDI,而不依赖FacesContext。看起来您只想执行重定向。简单的方法是:

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
    }
}
最后,在过滤器中使用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所做的工作进行一些本地认证。另请参见在FacesServlet中创建的FacesContext。因为过滤器是在servlet之前执行的,所以FacesContext还不可用。为什么需要FacesContext?你可以不用它吗?@tuner我的大部分业务逻辑都是在servlet筛选器中完成的,我可以做一个变通办法,将所有内容移到Faces servlet,但我想知道在servlet筛选器中访问FacesContext并获取CDI bean的实际实例,而不是代理的可能性。我知道关于这一点有一个Q/a!在过滤器中执行业务逻辑。无法直接找到它,但这将是一个很好的补充回答“请参阅”section@Kukeltje:这取决于功能要求。在这种情况下,它似乎通过某种令牌自动登录,这种令牌可以出现在任何任意URL上。在工作中使用过滤器不是不合理的。登录本身显然是自产代码,而不是使用已建立的库,这实际上往往是一种糟糕的做法。但从技术上讲,这个问题与此无关。没错,我更多的是指OP的声明,即所有业务逻辑都是在过滤器中完成的,而不是登录部分…@Kukeltje:哦,在对他的问题的评论中。对不起,我没看到。似乎与技术问题无关。

@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");
    }
}
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);
        }
    }
}