如何在@EJB
中注入@PersistenceContext
,@Inject
,@AutoWired
,@FacesConverter
等依赖项?在我的具体情况下,我需要通过@EJB
注入EJB:
@FacesConverter
public class MyConverter implements Converter {
@EJB
protected MyService myService;
@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
// myService.doSomething
}
}
然而,它没有被注射,它仍然是null
,导致NPE。似乎@PersistenceContext
和@Inject
也不起作用。
如何在转换器中注入服务依赖项以便我可以访问数据库?
答案 0 :(得分:53)
我可以使用
@EJB
将我的服务注入@FacesConverter
吗?
不,直到JSF 2.3发布。 JSF / CDI的人正在研究JSF 2.3。另请参阅JSF spec issue 1349和我的同事Arjan Tijms的相关"What's new in JSF 2.3?"文章。只有当您向注释明确添加@EJB
属性时,@PersistenceContext
,@Inject
,@FacesConverter
等依赖注入才会在managed=true
中生效。
@FacesConverter(value="yourConverter", managed=true)
public class YourConverter implements Converter {
@Inject
private YourService service;
// ...
}
如果没有,那么“正确”的方式是什么?
在JSF 2.3之前,您有几个选择:
改为使其成为托管bean。您可以通过@ManagedBean
,@Named
或@Component
将其设置为JSF,CDI或Spring托管bean。下面的示例使它成为JSF托管bean。
@ManagedBean
@RequestScoped
public class YourConverter implements Converter {
@EJB
private YourService service;
// ...
}
以下示例使其成为CDI托管bean。
@Named
@RequestScoped
public class YourConverter implements Converter {
@Inject
private YourService service;
// ...
}
将其引用为<h:inputXxx converter="#{yourConverter}">
而不是<h:inputXxx converter="yourConverter">
,或引用<f:converter binding="#{yourConverter}">
而不是<f:converter converterId="yourConverter">
。不要忘记删除@FacesConverter
注释!
缺点是您无法指定forClass
,因此需要在视图中的任何位置手动定义转换器。
将其注入常规托管bean中。
@ManagedBean
@RequestScoped
public class YourBean {
@EJB
private YourService service;
// ...
}
在您的转换器中,通过EL抓取或调用它。
YourBean yourBean = context.getApplication().evaluateExpressionGet(context, "#{yourBean}", YourBean.class);
// Then e.g. either
YourEntity yourEntity = yourBean.getService().findByStringId(value);
// Or
YourEntity yourEntity = yourBean.findEntityByStringId(value);
这样您就可以继续使用@FacesConverter
。
从JNDI手动获取EJB。
YourService yourService = (YourService) new InitialContext().lookup("java:global/appName/YourService");
缺点是存在一定的风险,即这不是完全便携的。另请参阅Inject EJB bean from JSF managed bean programmatically。
安装OmniFaces。从版本1.6开始,它在@EJB
中透明地添加了对@Inject
(和@FacesConverter
)的支持,而无需进一步修改。另见the showcase。如果您恰好需要<f:selectItem(s)>
的转换器,那么替代方法是使用其SelectItemsConverter
,它将根据选择项自动执行转换作业,而无需任何数据库交互。
<h:selectOneMenu ... converter="omnifaces.SelectItemsConverter">
答案 1 :(得分:2)
如果您可以在Web应用程序中容纳Seam Faces模块,答案是肯定的。请查看此帖Injection of EntityManager or CDI Bean in FacesConverter。你可以用类似的方式使用@EJB。
答案 2 :(得分:0)
您可以通过FacesContext间接访问它,FacesContext是两个Converter方法中的参数。
转换器也可以带有应用范围的注释CDI。访问外观时,使用同一类的两个实例。一个是转换器实例本身,哑,不知道EJB注释。另一个实例保留在应用程序范围中,可以通过FacesContext访问。该实例是一个Named对象,因此它知道EJB注释。由于一切都在一个类中完成,因此可以保护访问。
请参阅以下示例:
@FacesConverter(forClass=Product.class)
@Named
@ApplicationScoped
public class ProductConverter implements Converter{
@EJB protected ProductFacade facade;
protected ProductFacade getFacadeFromConverter(FacesContext ctx){
if(facade==null){
facade = ((ProductConverter) ctx.getApplication()
.evaluateExpressionGet(ctx,"#{productConverter}",ProductConverter.class))
.facade;
}
return facade;
}
@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
return getFacadeFromConverter(context).find(Long.parseLong(value));
}
...
答案 3 :(得分:0)
@Inject 仅适用于CDI托管实例
这仅适用于 Java EE 7 和 CDI 1.1 服务器:
@FacesConverter
public class MyConverter implements Converter {
protected MyService myService;
@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
myService = CDI.current().select(MyService .class).get();
myService.doSomething();
}
}
答案 4 :(得分:-3)
Luis Chacon,Sv
工作正常,经过测试
定义EJB:
@Stateless
@LocalBean
public class RubroEJB {
@PersistenceContext(unitName = "xxxxx")
private EntityManager em;
public List<CfgRubroPres> getAllCfgRubroPres(){
List<CfgRubroPres> rubros = null;
Query q = em.createNamedQuery("xxxxxxx");
rubros = q.getResultList();
return rubros;
}
}
使用Aplication bean范围定义bean,以获取EJB对象
@ManagedBean(name="cuentaPresService", eager = true)
@ApplicationScoped
public class CuentaPresService {
@EJB
private RubroEJB cfgCuentaEJB;
public RubroEJB getCfgCuentaEJB() {
return cfgCuentaEJB;
}
public void setCfgCuentaEJB(RubroEJB cfgCuentaEJB) {
this.cfgCuentaEJB = cfgCuentaEJB;
}
}
从转换器最终访问Ejb对象:
@FacesConverter("cuentaPresConverter")
public class CuentaPresConverter implements Converter {
@EJB
RubroEJB rubroEJB;
public Object getAsObject(FacesContext fc, UIComponent uic, String value) {
if(value != null && value.trim().length() > 0) {
try {
CuentaPresService service = (CuentaPresService) fc.getExternalContext().getApplicationMap().get("cuentaPresService");
List<CfgCuentaPres> listCuentas=service.getCfgCuentaEJB().getAllCfgCuentaPres();
................