Spirytus
Spirytus 是一个用来粘合 Scala 和 Spring Boot 的小工具.
虽然 Java 一直在改进那个糟糕的语法, 但是对集合进行操作还是 Scala 的语法更舒服. 但是 Scala 来说, 如果拿来构建一个 Web 服务, 无论是 Play Framework, 还是 Akka Http, 用起来都没有那么方便. 这个时候 Spring Boot 就很吸引人了.
Spirytus 可以在纯粹的 Scala 项目中, 顺利的使用 Spring Boot 提供的各项方便的服务.
Example domain:
@Entity
class ExampleDomain {
@Id
var id: String = ""
//Let's assume name is unique.
@Column
var name: String = ""
@Column
var city: String = ""
@Column
var age: Int = -1
@Column
var alive: Boolean = false
}
Example repository:
@Repository
trait ExampleRepo extends JpaRepository[ExampleDomain, String]{
//You might still mark the return type as Java list as jpa does not recognise Scala list.
def findByAlive(alive: Boolean): java.util.List[ExampleDomain]
def findByCity(city: String): java.util.List[ExampleDomain]
def findByAgeBetween(ageStart: Int, ageStop: Int): java.util.List[ExampleDomain]
def findByName(name: String): java.util.Optional[ExampleDomain]
}
Example repository singleton:
@Service
@ObjectAnnotation(ExampleRepoSingleton)
object ExampleRepoSingleton extends RepoHelper[ExampleDomain, String, ExampleRepo] with ObjectAutoConfig{
//All you need to do is to override the setRepo method with Autowired Repo.
@Autowired
override def setRepo(r: ExampleRepo): Unit = super.setRepo(r)
//Still needs to write some boilerplate codes though, it doesn't come in that handy for now.
//All default methods come with JPARepository had been implemented in RepoHelper.
//So, say we don't need customised methods, the above two lines are all you need.
def listByCity(city: String): List[ExampleDomain] = repo.findByCity(city).toScala
def listAlive(alive: Boolean): List[ExampleDomain] = repo.findByAlive(alive).toScala
def listInAgeRange(min: Int, max: Int): List[ExampleDomain] = repo.findByAgeBetween(min, max).toScala
def fetchByName(name: String): Option[ExampleDomain] = repo.findByName(name).toScala
def listAllNames(): List[String] = findAll.map(_.name)
def listAllCities(): List[String] = findAll.map(_.city).distinct
}
class ExampleRepoSingleton
Example service:
@Service
@ObjectAnnotation(ExampleService)
object ExampleService extends ObjectAutoConfig{
def chartByCity(): Map[String, Int] = {
ExampleRepoSingleton.findAll.groupBy(_.city).map(z => (z._1, z._2.length))
}
def existsByName(name: String): Boolean = {
ExampleRepoSingleton.fetchByName(name).fold(false)(_ => true)
}
def fetchCitiesByIds(ids: List[String]): List[String] = {
ExampleRepoSingleton.findAllById(ids).map(_.city).distinct
}
}
class ExampleService
Example service with autowired repository:
@Service
@ObjectAnnotation(ExampleService2)
object ExampleService2 extends ObjectAutoConfig with JavaCollectionMapper{
var exampleRepo: ExampleRepo = _
@Autowired
def setRepo(r: ExampleRepo): Unit ={
exampleRepo = r
}
def chartByCity(): Map[String, Int] = {
exampleRepo.findAll().toScala.groupBy(_.city).map(z => (z._1, z._2.length))
}
def existsByName(name: String): Boolean = {
exampleRepo.findByName(name).toScala.fold(false)(_ => true)
}
def fetchCitiesByIds(ids: List[String]): List[String] = {
exampleRepo.findAllById(ids.toJava).toScala.map(_.city).distinct
}
}
class ExampleService2
详细的还是去 Github 直接看代码吧. Spirytus.