在任何 Servlet 相关类中按名称获取 JSF 托管 bean
Posted
技术标签:
【中文标题】在任何 Servlet 相关类中按名称获取 JSF 托管 bean【英文标题】:Get JSF managed bean by name in any Servlet related class 【发布时间】:2011-02-07 15:41:19 【问题描述】:我正在尝试编写一个自定义 servlet(用于 AJAX/JSON),我想在其中按名称引用我的 @ManagedBeans
。我希望映射:
http://host/app/myBean/myProperty
到:
@ManagedBean(name="myBean")
public class MyBean
public String getMyProperty();
是否可以从常规 servlet 中按名称加载 bean?有没有我可以使用的 JSF servlet 或助手?
我似乎被春天宠坏了,这一切都太明显了。
【问题讨论】:
我不确定您是否可以在 JSF/EL 之外使用这些新注释,但我先看看 JSR 299 规范:jcp.org/en/jsr/detail?id=299 其他有类似问题的人也可以查看bpcatalog.dev.java.net/ajax/jsf-ajax(与AJAX和请求映射/处理有关,不按名称获取bean) 【参考方案1】:在基于 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");
请注意,这预先要求 bean 已经由 JSF 预先自动创建。否则这些将返回null
。然后您需要手动创建 bean 并使用 setAttribute("beanName", bean)
。
如果您能够使用 CDI @Named
而不是自 JSF 2.3 弃用的 @ManagedBean
,那么它会更加容易,特别是因为您不再需要手动创建 bean:
@Inject
private Bean bean;
请注意,当您使用 @Named @ViewScoped
时,这将不起作用,因为 bean 只能由 JSF 视图状态标识,并且仅在调用 FacesServlet
时可用。所以在之前运行的过滤器中,访问@Inject
ed @ViewScoped
总是会抛出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");
另见:
Backing beans (@ManagedBean) or CDI Beans (@Named)?【讨论】:
你第二个关于注入 bean 的建议非常简单,我完全忽略了它。与往常一样,您的回答非常中肯。非常感谢您在 SO 上所做的工作。 与此同时(从 JSF 2.2 开始),evaluateExpressionGet 方法似乎扩展了第三个参数,该参数允许指定预期的类,因此不再需要强制转换。PostBean bean = context.getApplication().evaluateExpressionGet(context, "#beanName", PostBean.class);
@Marc:从一开始就在。我猜这只是复制粘贴错误的遗留物。答案已更正。感谢您的通知。
FacesContext
可用,即使 static
实用方法 findBean()
是在普通 Java 类中定义的。它如何在不受 JSF 管理的普通 Java 类中可用?
@Tiny:它又被同一线程中的 JSF 工件调用。【参考方案2】:
我也有同样的要求。
我已使用以下方式获取它。
我有会话范围的 bean。
@ManagedBean(name="mb")
@SessionScopedpublic
class ManagedBean
--------
我在我的 servlet doPost() 方法中使用了以下代码。
ManagedBean mb = (ManagedBean) request.getSession().getAttribute("mb");
它解决了我的问题。
【讨论】:
你使用什么样的servlet?伴侣 是HttpServlet。【参考方案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 执行此操作,但它不起作用。【参考方案4】:我用这个:
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);
这样您就可以毫无问题地重构代码并跟踪使用情况。
【讨论】:
【参考方案5】:我使用以下方法:
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);
这允许我以键入的方式获取返回的对象。
【讨论】:
这已经被当前接受的答案所涵盖,甚至以更方便的方式(Class
参数在此构造中是不必要的)。【参考方案6】:
您是否尝试过类似此链接的方法?我不确定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)设置的按请求线程本地工件。 ValueBinding 自 4 年前的 JSF 1.2 起已弃用。 @BalusC:这表明我是最新的,哈哈。在旁注中,使用搜索引擎来研究技术结果会适得其反,因为所有旧信息都在那里。 @McDowell:这实际上是有道理的。我会做一个测试,看看会发生什么。以上是关于在任何 Servlet 相关类中按名称获取 JSF 托管 bean的主要内容,如果未能解决你的问题,请参考以下文章