JPA Tools API - lifedever/kt-speedy-toolbox GitHub Wiki
kt-speedy-data-jpa 模块提供了 Spring Data JPA 的增强工具,包括基础实体类、服务层基类、查询构建器等,简化 JPA 开发。
提供了包含审计字段的基础实体类,自动处理创建时间、修改时间、创建人、修改人等字段。
@MappedSuperclass
@EntityListeners(AuditingEntityListener::class)
open class SupportModal : Serializable
字段说明:
-
id: String?
- 主键,自动生成19位UUID -
createdDate: Date?
- 创建时间,自动设置 -
lastModifiedDate: Date?
- 最后修改时间,自动更新 -
createdBy: String?
- 创建人,需要配置审计 -
lastModifiedBy: String?
- 最后修改人,需要配置审计 -
deleted: Boolean?
- 删除标识,默认false
使用示例:
@Entity
@Table(name = "users")
class User : SupportModal() {
@Column(name = "username")
var username: String? = null
@Column(name = "email")
var email: String? = null
@Column(name = "phone")
var phone: String? = null
}
扩展了 JpaRepository 和 JpaSpecificationExecutor,提供了额外的查询方法。
interface SupportRepository<T : SupportModal, ID : Serializable> :
JpaRepository<T, ID>, JpaSpecificationExecutor<T>
使用示例:
@Repository
interface UserRepository : SupportRepository<User, String> {
fun findByUsername(username: String): User?
fun findByEmail(email: String): User?
}
提供了通用的服务层基类,包含常用的 CRUD 操作和查询方法。
@Transactional(readOnly = true)
abstract class SupportService<T : SupportModal, ID : Serializable>
核心方法:
fun findById(id: ID): Optional<T>
fun findAllById(ids: MutableList<ID>): MutableList<T>
fun getOne(id: ID): T // 找不到时抛出异常
fun getOneOrNull(id: ID?): T? // 找不到时返回null
fun findAll(): List<T>
fun findAll(sort: Sort): List<T>
fun findAll(spec: Specification<T>): List<T>
fun findAll(spec: Specification<T>, pageable: Pageable): Page<T>
fun findAll(pageable: Pageable): Page<T>
@Transactional
open fun save(t: T): T
@Transactional
open fun saveAll(entities: List<T>): List<T>
@Transactional
open fun deleteById(id: ID)
@Transactional
open fun delete(entity: T)
@Transactional
open fun deleteAll()
@Transactional
open fun deleteAllById(ids: List<ID>)
@Transactional
open fun deleteLogic(id: ID) // 逻辑删除
fun count(): Long
fun count(spec: Specification<T>): Long
使用示例:
@Service
class UserService : SupportService<User, String>() {
@Autowired
override lateinit var repository: UserRepository
fun findByUsername(username: String): User? {
return repository.findByUsername(username)
}
fun createUser(username: String, email: String): User {
val user = User().apply {
this.username = username
this.email = email
}
return save(user)
}
fun getUsersWithPagination(page: Int, size: Int): Page<User> {
val pageable = PageRequest.of(page, size, Sort.by("createdDate").descending())
return findAll(pageable)
}
}
提供了链式构建 JPA Specification 查询的工具。
class SpecificationBuilder<T> private constructor()
核心方法:
companion object {
fun <T> builder(): SpecificationBuilder<T>
}
fun and(newSpec: Specification<T>): SpecificationBuilder<T>
fun or(newSpec: Specification<T>): SpecificationBuilder<T>
fun build(): Specification<T>
使用示例:
@Service
class UserService : SupportService<User, String>() {
fun searchUsers(username: String?, email: String?, isActive: Boolean?): List<User> {
val spec = SpecificationBuilder.builder<User>()
.apply {
username?.let {
and(Specification.where { root, _, cb ->
cb.like(root.get("username"), "%$it%")
})
}
email?.let {
and(Specification.where { root, _, cb ->
cb.equal(root.get("email"), it)
})
}
isActive?.let {
and(Specification.where { root, _, cb ->
cb.equal(root.get("deleted"), !it)
})
}
}
.build()
return findAll(spec)
}
}
提供了19位UUID生成器,确保ID的唯一性和可读性。
object IdKit {
fun get(): String // 生成19位UUID
fun getUUID(): String // 生成32位UUID(无横线)
}
使用示例:
val shortId = IdKit.get() // "2Hs7K8mN9pQ3rT5vW"
val longId = IdKit.getUUID() // "550e8400e29b41d4a716446655440000"
提供了事务同步工具,可以在事务提交后执行特定操作。
object TransactionUtil {
fun triggerAfterCommit(call: () -> Unit)
}
使用示例:
@Service
class UserService : SupportService<User, String>() {
@Transactional
fun createUserWithNotification(username: String, email: String): User {
val user = User().apply {
this.username = username
this.email = email
}
val savedUser = save(user)
// 事务提交后发送通知
TransactionUtil.triggerAfterCommit {
sendWelcomeEmail(savedUser.email!!)
}
return savedUser
}
private fun sendWelcomeEmail(email: String) {
// 发送欢迎邮件的逻辑
println("发送欢迎邮件到: $email")
}
}
// 1. 实体类
@Entity
@Table(name = "articles")
class Article : SupportModal() {
@Column(name = "title", nullable = false)
var title: String? = null
@Column(name = "content", columnDefinition = "TEXT")
var content: String? = null
@Column(name = "author")
var author: String? = null
@Column(name = "published")
var published: Boolean = false
}
// 2. 仓库接口
@Repository
interface ArticleRepository : SupportRepository<Article, String> {
fun findByTitleContaining(title: String): List<Article>
fun findByAuthorAndPublished(author: String, published: Boolean): List<Article>
}
// 3. 服务类
@Service
class ArticleService : SupportService<Article, String>() {
@Autowired
override lateinit var repository: ArticleRepository
fun publishArticle(id: String): Article {
val article = getOne(id)
article.published = true
return save(article)
}
fun searchArticles(keyword: String?, author: String?, published: Boolean?): List<Article> {
val spec = SpecificationBuilder.builder<Article>()
.apply {
keyword?.let {
and(Specification.where { root, _, cb ->
cb.or(
cb.like(root.get("title"), "%$it%"),
cb.like(root.get("content"), "%$it%")
)
})
}
author?.let {
and(Specification.where { root, _, cb ->
cb.equal(root.get("author"), it)
})
}
published?.let {
and(Specification.where { root, _, cb ->
cb.equal(root.get("published"), it)
})
}
}
.build()
return findAll(spec)
}
fun getPublishedArticlesPaged(page: Int, size: Int): Page<Article> {
val spec = Specification.where<Article> { root, _, cb ->
cb.equal(root.get<Boolean>("published"), true)
}
val pageable = PageRequest.of(page, size, Sort.by("createdDate").descending())
return findAll(spec, pageable)
}
}
@Configuration
@EnableJpaAuditing
class JpaConfig {
@Bean
fun auditorProvider(): AuditorAware<String> {
return AuditorAware {
// 返回当前用户ID,可以从Security Context获取
Optional.of("system") // 这里简化为固定值
}
}
}
-
审计功能: 需要启用
@EnableJpaAuditing
并配置AuditorAware
-
逻辑删除:
deleteLogic()
方法只是设置deleted
字段为 true,不会物理删除数据 -
事务管理: 服务类默认开启只读事务,写操作方法需要
@Transactional
注解 - ID生成: 实体类会自动生成19位UUID作为主键
-
查询构建: 使用
SpecificationBuilder
可以灵活构建复杂查询条件