我正在开发一个java-spring项目,我有一个包gr.serafeim.domain
,其中包含我所有的域类(例如,学生,学校等 - 它们是具体的类)。所有这些都通过JPA注释与它们之间有关系。到目前为止一切都很好,但现在我需要为这些类实现需要查询数据库以获得结果的方法。
我应该如何实施这些方法?我的第一选择是将放在域类中,但为了做到这一点,我需要在所有域类中包含对数据存储库的引用。我不太喜欢这个 - 这是一个很好的设计选择吗?我应该实现我的域类将实现的接口吗?您能否提出更好的解决方案 - 在这种情况下通常的做法是什么?
TIA
答案 0 :(得分:12)
我的回答:不,不要将存储库的引用放入域模型中。将它们放入业务服务中。并且根本不管理域中的任何安全性。安全性是指用例,而不是域逻辑,因此安全性是通过域进行的。
我不同意Sandhu。我使用以下架构:
这种方法符合DDD风格,由Martin Fowler描述。我认为JPA在大多数现代项目中都很受欢迎。它不是用作持久性提供程序,而是用作活动记录。活动记录不是域模型实现模式,而是数据库抽象模式。因此,如果您真的想要事务脚本方法,请使用一些活动记录库或类似MyBatis而不是重量级JPA提供程序。
另外我不明白DAO的需要。 JPA提供者自己做数据抽象,不是吗?数据抽象也不是关于模型,而是关于基础设施。那么为什么DAO放在模型上呢?如果你真的需要DAO,你应该将它置于模型之下(我认为是存储库实现)。
正确用法示例:
package my.example.model;
@Entity
public class User {
@Id
@GeneratedValue
private Integer id;
private String login;
private String password;
@Temporal(TemporalType.TIMESTAMP)
private Date registrationDate;
User() {
// for persistence provider only
}
public User(String login, String password) {
this.login = login;
this.password = hashPassword(password);
this.registrationDate = new Date();
}
public String getLogin() {
return login;
}
public String setPassword(String password) {
this.password = hashPassword(password);
}
public boolean matchPassword(String password) {
return this.password.equals(hashPassword(password));
}
public Date getRegistrationDate() {
return registrationDate;
}
private static String hashPassword(String password) {
try {
MessageDigest digest = MessageDigest.getInstance("sha-1");
StringBuilder sb = new StringBuilder();
byte[] bytes = digest.digest(password.getBytes(charset));
for (byte b : bytes) {
sb.append(Character.forDigit((b >>> 4) & 0xF, 16)).append(Character.forDigit(b & 0xF, 16));
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
}
}
}
package my.example.model;
public interface UserRepository {
User findByLogin(String login);
User findBySurrogateId(int id);
Integer getSurrogateId(User user);
boolean contains(User user);
void add(User user);
void delete(User user);
}
package my.example.infrastructure;
@Component
public class PersistentUserRepository implements UserRepository {
@PersistenceContext
private EntityManager em;
public void setEntityManager(EntityManager em) {
this.em = em;
}
@Override public User findByLogin(String login) {
// I'd use QueryDSL here
QUser qusr = new QUser("usr");
return new JPAQuery(em)
.from(qusr)
.where(qusr.login.eq(login))
.singleResult(qusr);
}
@Override public User findBySurrogateId(int id) {
return em.find(User.class, id);
}
@Override public Integer getSurrogateId(User user) {
return (Integer)em.getEntityManagerFactory().getPersistenceUnitUtil().getIdentity(user);
}
@Override public boolean contains(User user) {
return em.contains(user);
}
@Override public void add(User user) {
em.persist(user);
}
@Override public void delete(User user) {
em.remove(user);
}
}
package my.example.facade;
public interface UserRemoteFacade {
UserDTO getUser(String login);
UserDTO getUser(int id);
void changePassword(int userId, String newPassword);
void registerUser(String login, String password) throws LoginOccupiedException;
boolean authenticate(String login, String password);
}
package my.example.facade;
public class UserDTO implements Serializable {
private int id;
private String login;
private Date registrationDate;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public Date getRegistrationDate() {
return registrationDate;
}
public void setRegistrationDate(Date registrationDate) {
this.registrationDate = registrationDate;
}
}
package my.example.server;
@Transactional @Component
public class UserRemoteFacadeImpl imlements UserRemoteFacade {
private UserRepository repository;
private Security security;
@Autowired
public UserRemoteFacadeImpl(UserRepository repository, Security security) {
this.repository = repository;
this.security = security;
}
@Override public UserDTO getUser(String login) {
return mapUser(repository.findByLogin(login));
}
@Override public UserDTO getUser(int id) {
return mapUser(repository.findBySurrogateId(id));
}
private UserDTO mapUser(User user) {
if (user != security.getCurrentUser()) {
security.checkPermission("viewUser");
}
UserDTO dto = new UserDTO();
dto.setId(repository.getSurrogateId(user));
dto.setLogin(user.getLogin());
dto.setRegistrationDate(user.getRegistrationDate());
return dto;
}
@Override public void changePassword(int userId, String newPassword) {
User user = repository.findByLogin(login);
if (user != security.getCurrentUser()) {
security.checkPermission("changePassword");
}
user.setPassword(newPassword);
}
@Override public void registerUser(String login, String password) throws LoginOccupiedException {
if (repository.findByLogin(login) != null) {
throw new LoginOccupiedException(login);
}
User user = new User(login, password);
repository.add(user);
}
@Override public boolean authenticate(String login, String password) throws LoginOccupiedException {
User user = repository.findByLogin(login);
return user != null && user.matchPassword(password);
}
}
答案 1 :(得分:5)
实现Spring的最佳方法是在项目中包含以下组件:
@Entity
) - 完全是您的域类@Repository
)@Service
)@Controller
) 2& 3形成Persistence Layer
和4& 5形成Service Layer
示例:强>
模型类
@Entity
public class User implements Serializable {
private static final long serialVersionUID = -8034624922386563274L;
@Id
@GeneratedValue
@Column(name = "id")
private int id;
@Column(name = "name")
private String name;
public int getId() {
return id;
}
public void setId(final int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
}
Dao界面
public interface UserDao {
public User getUser(String username);
}
Dao实施
@Repository
public class UserDaoImpl implements UserDao {
@Autowired
private SessionFactory sessionFactory;
private Session openSession() {
return sessionFactory.getCurrentSession();
}
@Override
public User getUser(String username) {
List<User> userList = new ArrayList<User>();
Query query = openSession().createQuery(
"from User u where u.username = :username");
query.setParameter("username", username);
userList = query.list();
if (userList.size() > 0)
return userList.get(0);
else
return null;
}
}
服务界面
public interface UserService {
public User getUser(String username);
}
服务实施
@Service
@Transactional
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
public User getUser(final String username) {
return userDao.getUser(username);
}
}