据我所知,CDI应该在过滤器中工作,但我不能让它为我工作。代码如下所示:
@WebFilter(filterName="authFilter",servletNames={"Faces Servlet"})
public class AuthFilter implements Filter {
@Inject UserBean userBean;
public AuthFilter() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
userBean.doSomething(); // Causes NullPointerException
chain.doFilter(request, response);
}
}
UserBean.class
@Stateless
public class UserBean extends JPABean{
// Omitted
}
CDI是启用的,如果我通过initialcontext . dollookup()或Servlet手动进行注入,则注入工作,如下所示:
@WebServlet(name = "MyServlet", urlPatterns = {"/MyPage"})
@ServletSecurity(@HttpConstraint(rolesAllowed={"somerole"}))
public class MyServlet extends HttpServlet {
@Inject private UserBean userBean;
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
userBean.doStuff(); // Works
response.sendRedirect(request.getContextPath());
}
CDI在过滤器中不工作吗?既然如此,为什么不呢?如果是这样,我又能做错什么呢?
在本例中,我将CODI @ViewAccessScoped bean (RegisterView)注入过滤器,在bean中设置属性并导航到使用该bean的视图。当页面加载时,我看到用户名设置为"弗雷德"。这也适用于@SessionScoped(但不是@RequestScoped或@ViewScoped)。我认为动态注入是线程安全所必需的,因为在web容器中只有一个过滤器实例,因此所有的实例变量。
要解决的问题是过滤器执行时Faces Servlet没有运行,所以没有FacesContext。getFacesContext()所做的聪明工作是我从2004年的这个博客中直接引用的,我不知道它是谁写的,而且已经有几年没有添加内容了,但是如果有人知道,请告诉我!也许是BalusC穿着他的年轻的时候。它使用静态内部类来访问受保护的FacesServlet#setCurrentInstance()方法。
如果你使用response.sendRedirect(),它将不起作用。
package uk.co.myco.jsfbeans.helper;
import java.io.IOException;
import javax.enterprise.inject.Instance;
import javax.faces.FactoryFinder;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.context.FacesContextFactory;
import javax.faces.lifecycle.Lifecycle;
import javax.faces.lifecycle.LifecycleFactory;
import javax.inject.Inject;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import uk.co.sportquest.entities.User;
import uk.co.sportquest.general.BaseClass;
import uk.co.sportquest.general.Log;
import uk.co.sportquest.jsfbeans.RegisterView;
/*
* @author Brendan Healey
*
* http://www.thoughtsabout.net/blog/archives/000033.html
*
*/
@WebFilter(filterName = "SocialAuthFilter", urlPatterns = {"/pages/socialAuthFilter.xhtml"},
dispatcherTypes = {DispatcherType.FORWARD, DispatcherType.ERROR, DispatcherType.REQUEST, DispatcherType.INCLUDE})
public class SocialAuthFilter extends BaseClass implements Filter {
@Inject
private Instance<RegisterView> rvDynamic;
private ServletContext servletContext;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
servletContext = filterConfig.getServletContext();
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
Log.log("testFilter: " + request.getPathInfo());
FacesContext ctx = getFacesContext(req, res);
RegisterView registerView;
registerView = rvDynamic.get();
User user = new User();
user.setUserName("fred");
registerView.setInputUser(user);
FacesContext.getCurrentInstance().getExternalContext().redirect("/pages/register.xhtml");
}
@Override
public void destroy() {
}
private abstract static class InnerFacesContext extends FacesContext {
protected static void setFacesContextAsCurrentInstance(FacesContext facesContext) {
FacesContext.setCurrentInstance(facesContext);
}
}
private FacesContext getFacesContext(ServletRequest request, ServletResponse response) {
// Try to get it first
FacesContext facesContext = FacesContext.getCurrentInstance();
if (facesContext != null) {
return facesContext;
}
FacesContextFactory contextFactory = (FacesContextFactory) FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
Lifecycle lifecycle = lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
// Either set a private member servletContext = filterConfig.getServletContext();
// in you filter init() method or set it here like this:
// ServletContext servletContext = ((HttpServletRequest)request).getSession().getServletContext();
// Note that the above line would fail if you are using any other protocol than http
// Doesn't set this instance as the current instance of FacesContext.getCurrentInstance
facesContext = contextFactory.getFacesContext(servletContext, request, response, lifecycle);
// Set using our inner class
InnerFacesContext.setFacesContextAsCurrentInstance(facesContext);
// set a new viewRoot, otherwise context.getViewRoot returns null
UIViewRoot view = facesContext.getApplication().getViewHandler().createView(facesContext, "");
facesContext.setViewRoot(view);
return facesContext;
}
}