我正在开发一些应用程序,它由三层组成:
- 数据库访问层(JPA + Hibernate 作为提供者)
- 业务逻辑层
- 表示层(JSF 2.0)
在开始之前,我已经阅读了 Core JavaServer Faces(第 3 版)一书中的一些章节大卫·吉尔里和凯·S·霍斯特曼。在本书中,作者强烈建议使用@Named
注释而不是@ManagedBean
。好吧,我想我可以尝试一下。
然后,我通过实现一些基本功能(用户登录)继续对应用程序进行分层构建。
我还阅读了一些新注释,即 @Inject
。我认为仅基于接口将一层注入另一层会非常舒服。但我担心我误解了什么,所以我带着我的问题来找你。
让我介绍一下我的代码的一些部分:
CredentialsBean.java:
@Named("userCredentials")
public class CredentialsBean {
@Inject
AccountService accountService;
private String login;
private String password;
public String verify()
{
if (accountService.verifyCredentials(login, password))
return "success";
else
return "failure";
}
// getters and setters
}
AccountService.java:
public interface AccountService {
public Boolean verifyCredentials(String login, String password);
}
AccountServiceImpl.java:
public class AccountServiceImpl implements AccountService {
@Inject
AccountDAO dao;
@Override
public Boolean verifyCredentials(String login, String password) {
// some logic
}
}
AccountDAO.java:
public interface AccountDAO {
public Account getAccount(String login);
}
AccountDAOImpl.java:
public class AccountDAOImpl implements AccountDAO {
@PersistenceContext(unitName = "MyApp")
protected EntityManager em;
public EntityManager getEntityManager() {
return em;
}
@Override
public Account getAccount(String login) {
// some data processing
}
}
最后一个类对带有@Entity
注释的Java类进行操作,没关系。
我感觉我的解决方案有问题。
基本错误是事实,即使我在调试
、
标记创建的表单提供一些数据>verify() 方法我可以看到,login
和 password
是 null
,所以这里出了问题,但我有不知道是什么。
我还担心我是否能很好地理解 @Inject
。我可以像上面提供的那样使用它来使用接口耦合层吗?
好的。我找到了登录名和密码字段为空的原因,但我还不知道解决方案。
发生这种情况是因为在以某种神奇的方式执行期间,创建了多个(至少两个)CredentialsBean 实例。在 Eclipse 调试器中检查。第一个字段得到正确设置,但第二个字段没有正确设置,第二个字段的值被发送到服务层。
我想知道这是否不是范围的问题。我不应该将 @SessionScoped 放在 CredentialsBean 中吗?
I am developing some application, which consists of three layers:
- Database access layer (JPA + Hibernate as provider)
- Business logic layer
- Presentation layer (JSF 2.0)
Before I started I have read some chapters from the book Core JavaServer Faces (3rd Edition) by David Geary and Cay S. Horstmann. In this book, authors strongly recommend using @Named
annotation instead of @ManagedBean
. Ok, I thought I can try.
Then I proceeded to layers construction of my application by just implementing some basic functionality - users logging in.
I also read about some new annotation, namely @Inject
. I thought that it can be very comfortable to just inject one layer into another basing only on interfaces. But I am afraid that I misunderstood something, so I came to you with my problem.
Let me present some parts of my code:
CredentialsBean.java:
@Named("userCredentials")
public class CredentialsBean {
@Inject
AccountService accountService;
private String login;
private String password;
public String verify()
{
if (accountService.verifyCredentials(login, password))
return "success";
else
return "failure";
}
// getters and setters
}
AccountService.java:
public interface AccountService {
public Boolean verifyCredentials(String login, String password);
}
AccountServiceImpl.java:
public class AccountServiceImpl implements AccountService {
@Inject
AccountDAO dao;
@Override
public Boolean verifyCredentials(String login, String password) {
// some logic
}
}
AccountDAO.java:
public interface AccountDAO {
public Account getAccount(String login);
}
AccountDAOImpl.java:
public class AccountDAOImpl implements AccountDAO {
@PersistenceContext(unitName = "MyApp")
protected EntityManager em;
public EntityManager getEntityManager() {
return em;
}
@Override
public Account getAccount(String login) {
// some data processing
}
}
This last class operates on some Java class with @Entity
annotation, nevermind.
I have a feeling that something is wrong with my solution.
Basic bug is fact, that even if I provide some data to the form created with <h:form>
, <h:inputText>
tag, when debugging verify()
method I can see, that login
and password
are null
, so something is wrong here, but I have no idea what.
I have also concerns if I understand @Inject
well. Can I use it in such way like provided above to couple layers using interfaces?
Ok. I found reason why I get nulls on login and password fields, but I don't know the solution yet.
It happens because during execution in some magic way, there are multiple (at least two) instances of CredentialsBean created. Checked in Eclipse debugger. First gets its fields set properly, but second one does not, and this second one's values are sent to service layer.
I am wondering if it is not a question of scope. Shouldn't I put @SessionScoped in CredentialsBean?
发布评论
评论(2)
我相信问题出在您的 CredentialsBean 类上。您没有指定 bean 的范围,因此它使用默认范围(请参阅 命名 CDI bean 的默认范围是什么? 了解更多信息)。
如果您将 @RequestScoped 之类的内容添加到您的类中,它应该可以工作。确保您使用 javax.enterprise.context.RequestScoped 而不是 javax.faces 版本。
I believe the problem is with your CredintialsBean class. You didn't specify a scope for the bean so it's using the default scope (see What is the default scope of a Named CDI bean? for more info).
If you add something like @RequestScoped to your class it should work. Make sure you use javax.enterprise.context.RequestScoped and not the javax.faces version.
您对 @Inject 的理解是正确的,这正是它的用途。您的注入点很可能为空,因为您没有 bean 存档(您需要 WEB-INF 或 META-INF 中名为 beans.xml 的文件,如果它是 jar,则它可以为空)。这是注入点为 null 的常见原因。
Your understanding of
@Inject
is correct, that's exactly what it is there for. Chances are your injection points are null because you do not have a bean archive (you need a file named beans.xml in WEB-INF or META-INF if it's a jar, it can be empty). That's the common reason for having null in your injection points.