在任何与Servlet相关的类中按名称获取JSF托管bean


101

我正在尝试编写一个自定义servlet(用于AJAX / JSON),在其中我想@ManagedBeans按名称引用我的名字。我希望映射:

http://host/app/myBean/myProperty

至:

@ManagedBean(name="myBean")
public class MyBean {
    public String getMyProperty();
}

是否可以从常规servlet中按名称加载bean?我可以使用JSF servlet或帮助程序吗?

我似乎对Spring感到宠爱,在Spring中所有这些都太明显了。


我不确定是否可以在JSF / EL之外使用这些新注释,但我将从查看JSR 299规范开始:jcp.org/en/jsr/detail?id=
McDowell,

其他遇到类似问题的人也可以检查bpcatalog.dev.java.net/ajax/jsf-ajax(与AJAX有关,并请求映射/处理,而不是按名称获取bean)
Konrad Garus 2010年

Answers:


263

在基于Servlet的神器,比如@WebServlet@WebFilter@WebListener,你可以抓住一个“普通的香草” JSF @ManagedBean @RequestScoped的:

Bean bean = (Bean) request.getAttribute("beanName");

@ManagedBean @SessionScoped通过:

Bean bean = (Bean) request.getSession().getAttribute("beanName");

@ManagedBean @ApplicationScoped通过:

Bean bean = (Bean) getServletContext().getAttribute("beanName");

请注意,这需要先由JSF自动创建Bean。否则这些会回来null。然后,您需要手动创建Bean并使用setAttribute("beanName", bean)


如果您能够使用CDI @Named而不是自JSF 2.3弃用以来的版本@ManagedBean,那么它会更加容易,尤其是因为您不再需要手动创建bean了:

@Inject
private Bean bean;

请注意,这在您使用时将不起作用,@Named @ViewScoped因为只能通过JSF视图状态来标识Bean,并且仅FacesServlet在调用时才可用。因此,在此之前运行的过滤器中,访问@Injected @ViewScoped将始终throw ContextNotActiveException


仅当您在室内时@ManagedBean,您可以使用@ManagedProperty

@ManagedProperty("#{bean}")
private Bean bean;

请注意,这并不是一个内部工作@Named@WebServlet或任何其他神器。它@ManagedBean仅在内部有效。


如果您不在内@ManagedBean,但FacesContext可以随时使用(即FacesContext#getCurrentInstance()不返回null),则也可以使用Application#evaluateExpressionGet()

FacesContext context = FacesContext.getCurrentInstance();
Bean bean = context.getApplication().evaluateExpressionGet(context, "#{beanName}", Bean.class);

可以方便地进行以下操作:

@SuppressWarnings("unchecked")
public static <T> T findBean(String beanName) {
    FacesContext context = FacesContext.getCurrentInstance();
    return (T) context.getApplication().evaluateExpressionGet(context, "#{" + beanName + "}", Object.class);
}

可以如下使用:

Bean bean = findBean("bean");

也可以看看:


9
您的第二个建议就是只注入豆子,它是如此之简单,以至于我完全忽略了它。与往常一样,您的回应是最恰当的。非常感谢您在SO方面的工作。
jnt30 2011年

2
同时(从JSF 2.2开始),似乎对validateExpressionGet方法扩展了第三个参数,该参数允许指定期望的类,因此不再需要强制类型转换。 PostBean bean = context.getApplication().evaluateExpressionGet(context, "#{beanName}", PostBean.class);
Marc Juchli 2014年

1
@Marc:从一开始就加入。我猜只是从复制粘贴错误中遗留下来的。答案已更正。感谢您的通知。
BalusC 2014年

FacesContext即使在纯Java类中定义了static实用程序方法,也可以使用findBean()。非JSF管理的普通Java类中如何提供它?
微小的

1
@Tiny:依次由同一线程中的JSF工件调用。
BalusC 2015年

11

我使用以下方法:

public static <T> T getBean(final String beanName, final Class<T> clazz) {
    ELContext elContext = FacesContext.getCurrentInstance().getELContext();
    return (T) FacesContext.getCurrentInstance().getApplication().getELResolver().getValue(elContext, null, beanName);
}

这使我能够以类型化的方式获取返回的对象。


3
这已经被当前接受的答案所覆盖,甚至可以通过更方便的方式解决(Class在该结构中,参数是不必要的)。
BalusC

3

您是否尝试过这种链接上的方法?我不确定是否createValueBinding()仍然可用,但是应该可以从普通的旧Servlet访问这样的代码。这确实需要bean已经存在。

http://www.coderanch.com/t/211706/JSF/java/access-managed-bean-JSF-from

 FacesContext context = FacesContext.getCurrentInstance();  
 Application app = context.getApplication();
 // May be deprecated
 ValueBinding binding = app.createValueBinding("#{" + expr + "}"); 
 Object value = binding.getValue(context);

这可能在常规servlet中不起作用。FacesContext是由JSF生命周期(通常是FacesServlet)设置的每个请求的线程局部工件。
McDowell 2010年

7
从4年前的JSF 1.2开始不推荐使用ValueBinding。
BalusC 2010年

@BalusC:它显示了我最近的情况。在一个旁注中,使用搜索引擎研究技术被证明与所有旧信息都适得其反。@McDowell:确实有道理。我将做一个测试,只是看看会发生什么。
James P.

3

您可以通过传递名称来获取托管bean:

public static Object getBean(String beanName){
    Object bean = null;
    FacesContext fc = FacesContext.getCurrentInstance();
    if(fc!=null){
         ELContext elContext = fc.getELContext();
         bean = elContext.getELResolver().getValue(elContext, null, beanName);
    }

    return bean;
}

我尝试从servlet做到这一点,但是它不起作用。
Fernando Pie

0

我有同样的要求。

我用下面的方法来得到它。

我有会话范围的豆。

@ManagedBean(name="mb")
@SessionScopedpublic 
class ManagedBean {
     --------
}

我在servlet doPost()方法中使用了以下代码。

ManagedBean mb = (ManagedBean) request.getSession().getAttribute("mb");

它解决了我的问题。


您使用哪种servlet?伴侣
Fernando Pie

1
它是HttpServlet。
艾尼尔

-1

我用这个:

public static <T> T getBean(Class<T> clazz) {
    try {
        String beanName = getBeanName(clazz);
        FacesContext facesContext = FacesContext.getCurrentInstance();
        return facesContext.getApplication().evaluateExpressionGet(facesContext, "#{" + beanName + "}", clazz);
    //return facesContext.getApplication().getELResolver().getValue(facesContext.getELContext(), null, nomeBean);
    } catch (Exception ex) {
        return null;
    }
}

public static <T> String getBeanName(Class<T> clazz) {
    ManagedBean managedBean = clazz.getAnnotation(ManagedBean.class);
    String beanName = managedBean.name();

    if (StringHelper.isNullOrEmpty(beanName)) {
        beanName = clazz.getSimpleName();
        beanName = Character.toLowerCase(beanName.charAt(0)) + beanName.substring(1);
    }

    return beanName;
}

然后调用:

MyManageBean bean = getBean(MyManageBean.class);

这样,您可以重构代码并跟踪使用情况而不会出现问题。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.