从Servlet访问JSF管理的Bean

10

我需要知道从servlet访问JSF托管的Bean(该Bean具有应用程序范围)的最佳方法。

目前,我的servlet中有类似以下内容:

  MyApplicationScopeBean bean = null;
  try {
   FacesContext fContext = FacesUtil.getFacesContext(req, resp);
   ServletContext sc = (ServletContext) fContext.getExternalContext().getContext();
   bean = (MyApplicationScopeBean) sc.getAttribute("myManagedBean");   
  } catch (Exception e) {
   e.printStackTrace();
  }

FacesUtil.java(如http://balusc.blogspot.com/2006/06/communication-in-jsf.html所述):

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.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class FacesUtil {
    // Getters -----------------------------------------------------------------------------------
    public static FacesContext getFacesContext(
        HttpServletRequest request, HttpServletResponse response)
    {
        // Get current FacesContext.
        FacesContext facesContext = FacesContext.getCurrentInstance();
        // Check current FacesContext.
        if (facesContext == null) {
            // Create new Lifecycle.
            LifecycleFactory lifecycleFactory = (LifecycleFactory)
                FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY); 
            Lifecycle lifecycle = lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
            // Create new FacesContext.
            FacesContextFactory contextFactory  = (FacesContextFactory)
                FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
            facesContext = contextFactory.getFacesContext(
                request.getSession().getServletContext(), request, response, lifecycle);
            // Create new View.
            UIViewRoot view = facesContext.getApplication().getViewHandler().createView(
                facesContext, "");
            facesContext.setViewRoot(view);                
            // Set current FacesContext.
            FacesContextWrapper.setCurrentInstance(facesContext);
        }
        return facesContext;
    }
    // Helpers -----------------------------------------------------------------------------------
    // Wrap the protected FacesContext.setCurrentInstance() in a inner class.
    private static abstract class FacesContextWrapper extends FacesContext {
        protected static void setCurrentInstance(FacesContext facesContext) {
            FacesContext.setCurrentInstance(facesContext);
        }
    }     
}

当我尝试从servlet中访问bean时,总是得到一个null值。您有什么建议吗?
我正在Tomcat 6上运行JSF 1.2。
谢谢您的帮助。

1个回答

21

JSF将应用程序范围的托管bean存储在ServletContext中。在servlet中,ServletContext只能通过继承的getServletContext()方法获得。您不需要手动创建一个完整的FacesContext。对于此目的来说,这只是一个不必要的昂贵任务。

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    Bean bean = (Bean) getServletContext().getAttribute("bean");
    // ...
}

如果返回null,则意味着JSF尚未自动为您创建bean(即servlet调用过早)。您需要自己创建和存储它。如果托管bean名称(属性键)相同,则JSF将使用它。
    if (bean == null) {
        bean = new Bean();
        getServletContext().setAttribute("bean", bean);
    }

那么,这个servlet的目的是什么呢?难道你不是在错误的方式下试图实现一些功能需求吗?


好的,现在我知道问题出在哪里了。我有一个 managedBean,其中有一个创建我所需 bean 的方法,但当我到达 servlet 时,它不在 ServletContext 中,因为它从未真正加载。该 servlet 的目的是使用 OutputStream 写入文件,以便我的用户能够保存 webservice 调用的结果(PDF 文件)。我知道这不是最好的方法,但我面临着截止日期。任何帮助都将不胜感激。 - azathoth
你也可以在托管的bean方法中实现这个功能。你可以在这个答案中找到一些提示。你绝对不应该使用servletcontext来实现它。它被所有使用web应用程序的用户共享。 - BalusC
谢谢您提供的示例,我已经修改了我的应用程序,现在它使用相同的Bean(会话范围)进行上传和下载,完全不需要涉及ServletContext。 - azathoth
BalusC:话说,这个servlet的目的是什么?你不是在用错误的方式实现某些功能需求吗?这是一个很好的观点。我曾经使用了一个普通的servlet来进行图像服务,但是根据BalusC的评论,我意识到bean同样可以做到,并且更容易地与页面集成。 - J Slick
@Milo:图片服务是一个单独的故事。从这里开始:http://stackoverflow.com/q/11649524 - BalusC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接