Java 为什么我需要一个存储库和一个服务+;合同

Java 为什么我需要一个存储库和一个服务+;合同,java,spring,spring-data,kotlin,dao,Java,Spring,Spring Data,Kotlin,Dao,我是来自PHP/Larvel、Ruby/Rails和Python/Django的Spring新手。来自这些框架,我习惯于只看到模型(实体/Dao?),其他一切都由框架/ORM/QueryBuilders处理,因此我所要做的就是声明一个模型,并向其中添加我需要的任何操作/关系/方法 在这些框架中,我所能做的就是: class User extends BaseModel { public function devices() { .. } // Relation to Device model

我是来自PHP/Larvel、Ruby/Rails和Python/Django的Spring新手。来自这些框架,我习惯于只看到模型(实体/Dao?),其他一切都由框架/ORM/QueryBuilders处理,因此我所要做的就是声明一个模型,并向其中添加我需要的任何操作/关系/方法

在这些框架中,我所能做的就是:

class User extends BaseModel
{
  public function devices() { .. } // Relation to Device model

  // Any additional functions on user go here these can operate on 
  // just the User model or pull additional data from DB or other models.  
  public function assignUserToDevice();
  public function getUsersScore();
  public function connectUserToService();
}
但是,在本春季教程之后,我现在有了以下内容:

模型(实体/Dao?):仅包含属性,除GET/SET和relations外,不包含任何方法

@Entity  
@Table(name = "users")  
class User {
  @Id
  @GeneratedValue  
  var id: Long = 0

  var username: String = "" //...
}
存储库:

interface UserRepository : CrudRepository<User, Long> {
  fun findByUsername(username: String): User
}
interface UserRepository:CrudRepository{
fun findByUsername(用户名:字符串):用户
}
用户服务合同:

interface UserServiceContract {

    /**
     * Attempts to find User associated with the given id.
     * @throws ModelNotFoundException if not user has been found associated with the given id.
     * @param id given users id.
     * @return User associated with the given id.
     */
    @Throws(ModelNotFoundException::class)
    fun find(id: Long): User

    /**
     * Returns all existing users.
     * @return list of all existing users.
     */
    fun findAll(): List<User>
}  
接口用户服务合同{
/**
*尝试查找与给定id关联的用户。
*@如果未找到与给定id关联的用户,则抛出ModelNotFoundException。
*@param id给定用户id。
*@返回与给定id关联的用户。
*/
@抛出(ModelNotFoundException::类)
有趣的发现(id:Long):用户
/**
*返回所有现有用户。
*@返回所有现有用户的列表。
*/
fun findAll():列表
}  
和一项服务:

@Service
class UserService : UserServiceContract {

    @Autowired
    lateinit var userRepository: UserRepository

    /**
     * Attempts to find User associated with the given id.
     * @throws ModelNotFoundException if not user has been found associated with the given id.
     * @param id given users id.
     * @return User associated with the given id.
     */
    override fun find(id: Long) = userRepository.findOne(id) ?: throw ModelNotFoundException("User not found!")

    override fun findAll(): List<User> {
        throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
    }
}  
@服务
类UserService:UserServiceContract{
@自动连线
lateinit var userRepository:userRepository
/**
*尝试查找与给定id关联的用户。
*@如果未找到与给定id关联的用户,则抛出ModelNotFoundException。
*@param id给定用户id。
*@返回与给定id关联的用户。
*/
覆盖有趣的查找(id:Long)=userRepository.findOne(id)?:抛出ModelNotFoundException(“未找到用户!”)
重写fun findAll():列表{
抛出UnsupportedOperationException(“未实现”)//要更改创建的函数体,请使用文件|设置|文件模板。
}
}  
问题:

  • 为什么我需要
    UserRepository
    UserService+UserServiceContract
    ?根据我在存储库Spring指南上读到的内容,您已经获得了默认的
    CRUD
    方法
    save、read、update、delete..
    除此之外,您还可以使用查询方法执行
    findUserBy…
    或编写带注释的原始查询。所以我有点困惑,为什么仅仅为了实现存储库已经提供的功能而声明
    UserServiceContract
    UserService

  • 之前,我会在上述模型中保留处理/使用我的模型的方法,但是,我从少数资源中注意到,这不是春季使用的方法,所以我应该将它们保存在哪里?这就是为什么会有
    用户服务
    用户服务合同
    ? 我是否真的应该将
    UserRepository
    仅用于数据库访问,并在
    UserServiceContract
    中声明处理用户的方法,如:
    public function connectUserToService()


  • 用户就是实体。它基本上表示数据库表中的一行。它肯定有办法。将与该实体无关的方法仅放在实体类中通常不是一个好主意。特别是那些需要访问外部依赖项(如存储库或服务)的方法

    存储库是允许执行与给定实体相关的查询或保存该实体的新实例的组件

    服务包含业务逻辑。它可以像简单地委托给存储库一样简单,但除非您的应用程序只是用于查看数据库中的信息,否则它通常包含更复杂的逻辑,涉及多个实体和存储库

    将存储库与服务分离非常有用,因为它允许

    • 避免混合责任
    • 轻松地测试查询,而不必使用它们调用复杂的逻辑
    • 通过模拟存储库轻松高效地测试业务逻辑
    • 划分事务边界:服务方法通常是事务
    您是否使用接口来定义服务的契约取决于您自己。春天不会强迫你这么做。如果你想打击自己,你也可以将服务和存储库混合使用,但是Spring并不鼓励这样做,如果你使用SpringDataJPA,你将无法做到这一点。SpringDataJPA基本上是基于一个接口为你生成一个存储库实现

    我不太了解您所使用的框架,但是在考虑spring应用程序的设计时,您需要记住这一点:spring是一个依赖注入框架,它包括将组件注入到其他组件中。实体不是Spring组件,因此如果它们包含业务逻辑,就不能注入它们所需的依赖项(IMO,这同样会混合责任)。依赖注入本身主要用于生成代码
    可测试,并且能够围绕方法调用添加方面(例如,启动和提交事务)。这就是Spring设计的驱动力:单一责任原则、依赖注入带来的可测试性,以及。

    您不需要严格的服务。您可以直接使用DAO/存储库。但是,如果您想将低级数据库表示转换为严格的内部模型(不可变和断言),该服务可以派上用场。这些模型更适合由更高级别的层进行处理(所以您不需要公开像ID之类的数据库内部)。这取决于你的应用程序有多大,如果你需要这个额外的分层。哦,哇,谢谢,这实际上是一个很好的解释。例如,在我的例子中,如果你看第一个代码片段,我有3个函数
    getUsersScore
    ,这是一个基于3个fi计算用户分数的算法