mirror of
https://github.moeyy.xyz/https://github.com/GeWuYou/forgeboot
synced 2025-10-27 16:24:22 +08:00
Merge branch 'refactor/7-mvc-dto-spec-refactoring-mvc-s-dto-and-spec-modules' into 'main'
refactor(webmvc): 重构 Web 项目通用 CRUD 接口规范模块 Closes #7 See merge request gewuyou/forgeboot!12
This commit is contained in:
commit
4a804c4a54
@ -29,6 +29,10 @@ object Modules {
|
||||
const val VALIDATION = ":forgeboot-webmvc-spring-boot-starter:forgeboot-webmvc-validation"
|
||||
const val VERSION = ":forgeboot-webmvc-spring-boot-starter:forgeboot-webmvc-version-spring-boot-starter"
|
||||
const val LOGGER = ":forgeboot-webmvc-spring-boot-starter:forgeboot-webmvc-logger-spring-boot-starter"
|
||||
object Spec{
|
||||
const val CORE = ":forgeboot-webmvc-spring-boot-starter:forgeboot-webmvc-spec-core"
|
||||
const val JPA = ":forgeboot-webmvc-spring-boot-starter:forgeboot-webmvc-spec-jpa"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -7,8 +7,6 @@ dependencies {
|
||||
implementation(libs.kotlinReflect)
|
||||
compileOnly(libs.springBootDependencies.bom)
|
||||
compileOnly(libs.jackson.annotations)
|
||||
compileOnly(libs.springBootStarter.jpa)
|
||||
compileOnly(libs.springBootStarter.validation)
|
||||
}
|
||||
i18nKeyGen {
|
||||
rootPackage.set("com.gewuyou.forgeboot.webmvc.dto.i18n")
|
||||
|
||||
@ -1,38 +0,0 @@
|
||||
package com.gewuyou.forgeboot.webmvc.dto.page
|
||||
|
||||
import jakarta.persistence.criteria.CriteriaBuilder
|
||||
import jakarta.persistence.criteria.Predicate
|
||||
import jakarta.persistence.criteria.Root
|
||||
|
||||
/**
|
||||
* 可过滤接口,用于支持泛型类型的过滤操作
|
||||
*
|
||||
* 该接口定义了过滤功能的基本契约,允许实现类根据给定的过滤条件构建查询规范。
|
||||
* 主要用于与 JPA Criteria API 集成,以构建动态查询条件。
|
||||
*
|
||||
* @param <FilterType> 过滤条件的类型,通常是一个包含过滤参数的数据传输对象(DTO)。
|
||||
* @param <EntityType> 被查询的实体类型,通常对应数据库中的某个实体类。
|
||||
*
|
||||
* @since 2025-07-19 08:56:56
|
||||
* @author gewuyou
|
||||
*/
|
||||
interface Filterable<FilterType, EntityType> : QueryComponent {
|
||||
/**
|
||||
* 获取当前的过滤条件对象。
|
||||
*
|
||||
* @return 返回一个可空的 FilterType 实例,表示当前的过滤条件。
|
||||
*/
|
||||
val filter: FilterType?
|
||||
|
||||
/**
|
||||
* 构建查询条件的谓词列表。
|
||||
*
|
||||
* 此方法根据当前的过滤条件,使用给定的 CriteriaBuilder 创建一组 Predicate 对象,
|
||||
* 这些谓词可以用于构建最终查询语句。
|
||||
*
|
||||
* @param root 代表查询的根实体,用于访问实体的属性。
|
||||
* @param cb CriteriaBuilder 实例,用于创建查询条件。
|
||||
* @return 返回一个包含查询条件的 Predicate 列表。
|
||||
*/
|
||||
fun buildSpecification(root: Root<EntityType>, cb: CriteriaBuilder): List<Predicate>
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
package com.gewuyou.forgeboot.webmvc.dto.request
|
||||
|
||||
import com.gewuyou.forgeboot.webmvc.dto.entities.SortCondition
|
||||
import com.gewuyou.forgeboot.webmvc.dto.page.DateRangeFilterable
|
||||
import com.gewuyou.forgeboot.webmvc.dto.page.Filterable
|
||||
import com.gewuyou.forgeboot.webmvc.dto.page.Pageable
|
||||
import com.gewuyou.forgeboot.webmvc.dto.page.Sortable
|
||||
|
||||
/**
|
||||
* 抽象排序日期过滤分页请求基类
|
||||
*
|
||||
* 该抽象类为分页请求提供了基础结构,支持以下功能:
|
||||
* - 分页控制(通过Pageable接口)
|
||||
* - 排序功能(通过Sortable接口)
|
||||
* - 日期范围过滤(通过DateRangeFilterable接口)
|
||||
* - 通用数据过滤(通过Filterable<T,E>接口)
|
||||
*
|
||||
* @property currentPage 当前页码,从1开始计数,默认值为1
|
||||
* @property pageSize 每页记录数,默认值为10
|
||||
*
|
||||
* @since 2025-07-19 14:50:36
|
||||
* @author gewuyou
|
||||
*/
|
||||
abstract class AbstractSortedDateFilterPageRequest<T,E>(
|
||||
override val currentPage: Int = 1,
|
||||
override val pageSize: Int = 10,
|
||||
override val sortConditions: List<SortCondition> = mutableListOf()
|
||||
) : Pageable, Sortable, DateRangeFilterable, Filterable<T,E>
|
||||
3
forgeboot-webmvc/spec-core/build.gradle.kts
Normal file
3
forgeboot-webmvc/spec-core/build.gradle.kts
Normal file
@ -0,0 +1,3 @@
|
||||
dependencies {
|
||||
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package com.gewuyou.forgeboot.webmvc.dto.entities
|
||||
package com.gewuyou.webmvc.spec.core.entities
|
||||
|
||||
import java.time.Instant
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
package com.gewuyou.forgeboot.webmvc.dto.entities
|
||||
package com.gewuyou.webmvc.spec.core.entities
|
||||
|
||||
import org.hibernate.query.SortDirection
|
||||
import com.gewuyou.webmvc.spec.core.enums.SortDirection
|
||||
|
||||
/**
|
||||
* 排序条件
|
||||
@ -17,5 +17,5 @@ class SortCondition {
|
||||
/**
|
||||
* 排序方向
|
||||
*/
|
||||
var direction: SortDirection = SortDirection.DESCENDING
|
||||
var direction: SortDirection = SortDirection.DESC
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
package com.gewuyou.webmvc.spec.core.enums
|
||||
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* 排序方向枚举
|
||||
*
|
||||
* @author gewuyou
|
||||
* @since 2025-01-16 17:56:01
|
||||
*/
|
||||
enum class SortDirection {
|
||||
ASC, DESC;
|
||||
|
||||
/**
|
||||
* 获取当前排序方向的反方向
|
||||
*
|
||||
* @return 返回与当前方向相反的排序方向枚举值
|
||||
* - 当前为ASC时返回DESC
|
||||
* - 当前为DESC时返回ASC
|
||||
*/
|
||||
fun reverse(): SortDirection = when (this) {
|
||||
ASC -> DESC
|
||||
DESC -> ASC
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* 将字符串解析为排序方向枚举值(忽略大小写)
|
||||
*
|
||||
* 支持的输入包括:
|
||||
* - "asc", "ascending" → ASC
|
||||
* - "desc", "descending" → DESC
|
||||
*
|
||||
* @param value 待解析的字符串,可为空
|
||||
* @return 解析成功返回对应的枚举值,value为空时返回null,无法解析时抛出异常
|
||||
* @throws IllegalArgumentException 当输入字符串无法识别为有效的排序方向时
|
||||
*/
|
||||
@JvmStatic
|
||||
fun interpret(value: String?): SortDirection? {
|
||||
if (value == null) return null
|
||||
return when (value.lowercase(Locale.ROOT)) {
|
||||
"asc", "ascending" -> ASC
|
||||
"desc", "descending" -> DESC
|
||||
else -> throw IllegalArgumentException("Unknown sort direction: $value")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全地将字符串解析为排序方向枚举值,如果解析失败则返回默认值
|
||||
*
|
||||
* @param value 待解析的字符串,可为空
|
||||
* @param default 解析失败时返回的默认值,默认为ASC
|
||||
* @return 解析成功返回对应的枚举值,解析失败或value为空时返回默认值
|
||||
*/
|
||||
fun interpretOrDefault(value: String?, default: SortDirection = ASC): SortDirection {
|
||||
return try {
|
||||
interpret(value) ?: default
|
||||
} catch (_: IllegalArgumentException) {
|
||||
default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
package com.gewuyou.forgeboot.webmvc.dto.page
|
||||
package com.gewuyou.webmvc.spec.core.page
|
||||
|
||||
import com.gewuyou.webmvc.spec.core.entities.DateRangeCondition
|
||||
|
||||
import com.gewuyou.forgeboot.webmvc.dto.entities.DateRangeCondition
|
||||
|
||||
/**
|
||||
* 日期范围可过滤接口
|
||||
@ -0,0 +1,19 @@
|
||||
package com.gewuyou.webmvc.spec.core.page
|
||||
|
||||
/**
|
||||
* 可过滤接口,用于支持泛型类型的过滤操作
|
||||
*
|
||||
*
|
||||
* @param <FilterType> 过滤条件的类型,通常是一个包含过滤参数的数据传输对象(DTO)。
|
||||
*
|
||||
* @since 2025-07-19 08:56:56
|
||||
* @author gewuyou
|
||||
*/
|
||||
interface Filterable<FilterType> : QueryComponent {
|
||||
/**
|
||||
* 获取当前的过滤条件对象。
|
||||
*
|
||||
* @return 返回一个可空的 FilterType 实例,表示当前的过滤条件。
|
||||
*/
|
||||
val filter: FilterType?
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package com.gewuyou.forgeboot.webmvc.dto.page
|
||||
package com.gewuyou.webmvc.spec.core.page
|
||||
|
||||
/**
|
||||
* 关键字可搜索接口,用于支持包含关键字搜索条件的数据结构
|
||||
@ -1,4 +1,4 @@
|
||||
package com.gewuyou.forgeboot.webmvc.dto.page
|
||||
package com.gewuyou.webmvc.spec.core.page
|
||||
|
||||
/**
|
||||
* 可分页接口,用于支持分页功能的类实现
|
||||
@ -1,4 +1,4 @@
|
||||
package com.gewuyou.forgeboot.webmvc.dto.page
|
||||
package com.gewuyou.webmvc.spec.core.page
|
||||
|
||||
/**
|
||||
* QueryComponent 是一个密封接口,用于定义查询组件的公共契约。
|
||||
@ -1,7 +1,7 @@
|
||||
package com.gewuyou.forgeboot.webmvc.dto.page
|
||||
package com.gewuyou.webmvc.spec.core.page
|
||||
|
||||
import com.gewuyou.forgeboot.webmvc.dto.entities.SortCondition
|
||||
import org.hibernate.query.SortDirection
|
||||
import com.gewuyou.webmvc.spec.core.entities.SortCondition
|
||||
import com.gewuyou.webmvc.spec.core.enums.SortDirection
|
||||
|
||||
/**
|
||||
* 可排序接口,用于定义排序相关属性
|
||||
@ -0,0 +1,10 @@
|
||||
package com.gewuyou.webmvc.spec.core.page
|
||||
|
||||
/**
|
||||
* 启用状态可过滤接口,用于支持启用/禁用状态的过滤功能。
|
||||
*
|
||||
*
|
||||
* @since 2025-07-19 09:00:42
|
||||
* @author gewuyou
|
||||
*/
|
||||
interface StatusFilterable : QueryComponent
|
||||
@ -1,7 +1,8 @@
|
||||
package com.gewuyou.forgeboot.webmvc.dto.request
|
||||
package com.gewuyou.webmvc.spec.core.request
|
||||
|
||||
import com.gewuyou.webmvc.spec.core.page.DateRangeFilterable
|
||||
import com.gewuyou.webmvc.spec.core.page.Pageable
|
||||
|
||||
import com.gewuyou.forgeboot.webmvc.dto.page.DateRangeFilterable
|
||||
import com.gewuyou.forgeboot.webmvc.dto.page.Pageable
|
||||
|
||||
/**
|
||||
* 抽象日期分页请求
|
||||
@ -1,8 +1,9 @@
|
||||
package com.gewuyou.forgeboot.webmvc.dto.request
|
||||
package com.gewuyou.webmvc.spec.core.request
|
||||
|
||||
import com.gewuyou.webmvc.spec.core.page.DateRangeFilterable
|
||||
import com.gewuyou.webmvc.spec.core.page.Pageable
|
||||
import com.gewuyou.webmvc.spec.core.page.StatusFilterable
|
||||
|
||||
import com.gewuyou.forgeboot.webmvc.dto.page.DateRangeFilterable
|
||||
import com.gewuyou.forgeboot.webmvc.dto.page.Pageable
|
||||
import com.gewuyou.forgeboot.webmvc.dto.page.StatusFilterable
|
||||
|
||||
/**
|
||||
* 日期状态页面请求
|
||||
@ -1,7 +1,8 @@
|
||||
package com.gewuyou.forgeboot.webmvc.dto.request
|
||||
package com.gewuyou.webmvc.spec.core.request
|
||||
|
||||
import com.gewuyou.webmvc.spec.core.page.KeywordSearchable
|
||||
import com.gewuyou.webmvc.spec.core.page.Pageable
|
||||
|
||||
import com.gewuyou.forgeboot.webmvc.dto.page.KeywordSearchable
|
||||
import com.gewuyou.forgeboot.webmvc.dto.page.Pageable
|
||||
|
||||
/**
|
||||
* 抽象搜索分页请求类
|
||||
@ -1,8 +1,9 @@
|
||||
package com.gewuyou.forgeboot.webmvc.dto.request
|
||||
package com.gewuyou.webmvc.spec.core.request
|
||||
|
||||
import com.gewuyou.webmvc.spec.core.page.DateRangeFilterable
|
||||
import com.gewuyou.webmvc.spec.core.page.Pageable
|
||||
import com.gewuyou.webmvc.spec.core.page.Sortable
|
||||
|
||||
import com.gewuyou.forgeboot.webmvc.dto.page.DateRangeFilterable
|
||||
import com.gewuyou.forgeboot.webmvc.dto.page.Pageable
|
||||
import com.gewuyou.forgeboot.webmvc.dto.page.Sortable
|
||||
|
||||
/**
|
||||
* 抽象排序日期分页请求
|
||||
@ -1,7 +1,8 @@
|
||||
package com.gewuyou.forgeboot.webmvc.dto.request
|
||||
package com.gewuyou.webmvc.spec.core.request
|
||||
|
||||
import com.gewuyou.webmvc.spec.core.page.Pageable
|
||||
import com.gewuyou.webmvc.spec.core.page.Sortable
|
||||
|
||||
import com.gewuyou.forgeboot.webmvc.dto.page.Pageable
|
||||
import com.gewuyou.forgeboot.webmvc.dto.page.Sortable
|
||||
|
||||
/**
|
||||
* 抽象排序分页请求数据类
|
||||
@ -1,6 +1,7 @@
|
||||
package com.gewuyou.forgeboot.webmvc.dto.request
|
||||
package com.gewuyou.webmvc.spec.core.request
|
||||
|
||||
import com.gewuyou.webmvc.spec.core.page.Pageable
|
||||
|
||||
import com.gewuyou.forgeboot.webmvc.dto.page.Pageable
|
||||
|
||||
/**
|
||||
* 基本分页请求数据类
|
||||
@ -1,7 +1,4 @@
|
||||
package com.gewuyou.forgeboot.webmvc.dto.request
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import jakarta.validation.constraints.NotEmpty
|
||||
package com.gewuyou.webmvc.spec.core.request
|
||||
|
||||
/**
|
||||
* 根据id列表删除请求
|
||||
@ -12,16 +9,13 @@ import jakarta.validation.constraints.NotEmpty
|
||||
* @author gewuyou
|
||||
* @since 2025-01-18 17:39:18
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
open class DeleteByIdsReq<T>(
|
||||
/**
|
||||
* 待删除的实体id列表
|
||||
*
|
||||
* 这个字段是删除操作的核心参数,它不能为空,以确保至少有一个id被指定用于删除
|
||||
* 使用@NotNull注解来确保在序列化和反序列化过程中,该字段不能为空
|
||||
*
|
||||
* @param ids 实体的唯一标识符列表,用于指定哪些实体应当被删除
|
||||
*/
|
||||
@field:NotEmpty(message = "The list of Ids requested to be removed cannot be empty!")
|
||||
var ids: List<T>,
|
||||
)
|
||||
3
forgeboot-webmvc/spec-jpa/.gitattributes
vendored
Normal file
3
forgeboot-webmvc/spec-jpa/.gitattributes
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/gradlew text eol=lf
|
||||
*.bat text eol=crlf
|
||||
*.jar binary
|
||||
40
forgeboot-webmvc/spec-jpa/.gitignore
vendored
Normal file
40
forgeboot-webmvc/spec-jpa/.gitignore
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
HELP.md
|
||||
.gradle
|
||||
build/
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
bin/
|
||||
!**/src/main/**/bin/
|
||||
!**/src/test/**/bin/
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
out/
|
||||
!**/src/main/**/out/
|
||||
!**/src/test/**/out/
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
### Kotlin ###
|
||||
.kotlin
|
||||
@ -1,6 +1,5 @@
|
||||
|
||||
dependencies {
|
||||
compileOnly(libs.springBootStarter.jpa)
|
||||
api(project(Modules.Webmvc.DTO))
|
||||
api(project(Modules.Core.EXTENSION))
|
||||
api(project(Modules.Webmvc.Spec.CORE))
|
||||
compileOnly(libs.springBootStarter.jpa)
|
||||
}
|
||||
@ -1,22 +1,31 @@
|
||||
package com.gewuyou.forgeboot.webmvc.dto.extension
|
||||
package com.gewuyou.webmvc.spec.jpa.extension
|
||||
|
||||
import com.gewuyou.forgeboot.webmvc.dto.page.*
|
||||
|
||||
import com.gewuyou.webmvc.spec.core.enums.SortDirection
|
||||
import com.gewuyou.webmvc.spec.core.page.DateRangeFilterable
|
||||
import com.gewuyou.webmvc.spec.core.page.KeywordSearchable
|
||||
import com.gewuyou.webmvc.spec.core.page.Pageable
|
||||
import com.gewuyou.webmvc.spec.core.page.QueryComponent
|
||||
import com.gewuyou.webmvc.spec.core.page.Sortable
|
||||
import com.gewuyou.webmvc.spec.jpa.page.JpaFilterable
|
||||
import com.gewuyou.webmvc.spec.jpa.page.JpaStatusFilterable
|
||||
import jakarta.persistence.criteria.CriteriaBuilder
|
||||
import jakarta.persistence.criteria.Predicate
|
||||
import jakarta.persistence.criteria.Root
|
||||
import org.hibernate.query.SortDirection
|
||||
|
||||
import org.springframework.data.domain.PageRequest
|
||||
import org.springframework.data.domain.Sort
|
||||
import org.springframework.data.jpa.domain.Specification
|
||||
import java.time.Instant
|
||||
|
||||
|
||||
/**
|
||||
* 将 Hibernate 的 SortDirection 转换为 Spring Data 的 Sort.Direction。
|
||||
* 将自定义的排序方向枚举转换为 Spring Data JPA 的排序方向
|
||||
*
|
||||
* @return 返回对应的 Sort.Direction 实例
|
||||
* @return 对应的 Spring Data Sort.Direction 枚举值
|
||||
*/
|
||||
fun SortDirection.toSpringDirection(): Sort.Direction =
|
||||
if (this == SortDirection.DESCENDING) Sort.Direction.DESC else Sort.Direction.ASC
|
||||
if (this == SortDirection.DESC) Sort.Direction.DESC else Sort.Direction.ASC
|
||||
|
||||
/**
|
||||
* 将当前排序配置转换为可用于 Spring Data Pageable 的排序条件列表
|
||||
@ -140,17 +149,17 @@ fun <T> QueryComponent.toSpecification(): Specification<T> {
|
||||
(this as? DateRangeFilterable)?.let {
|
||||
predicates += it.buildDateRangePredicates(root, cb)
|
||||
}
|
||||
// 判断并组合 Status
|
||||
(this as? StatusFilterable)?.let {
|
||||
// 判断并组合 JpaStatusFilterable
|
||||
(this as? JpaStatusFilterable)?.let {
|
||||
predicates += it.buildStatusPredicates(root, cb)
|
||||
}
|
||||
// 判断并组合 KeywordSearchable
|
||||
(this as? KeywordSearchable)?.let {
|
||||
predicates += it.buildKeywordPredicates(root, cb)
|
||||
}
|
||||
// 判断并组合 Filterable
|
||||
// 判断并组合 JpaFilterable
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
(this as? Filterable<*, T>)?.let {
|
||||
(this as? JpaFilterable<*, T>)?.let {
|
||||
predicates += it.buildSpecification(root, cb)
|
||||
}
|
||||
// 组合所有查询条件,返回逻辑 AND 结果
|
||||
@ -1,4 +1,4 @@
|
||||
package com.gewuyou.forgeboot.webmvc.dto.extension
|
||||
package com.gewuyou.webmvc.spec.jpa.extension
|
||||
|
||||
import com.gewuyou.forgeboot.webmvc.dto.PageResult
|
||||
import org.springframework.data.domain.Page
|
||||
@ -1,4 +1,4 @@
|
||||
package com.gewuyou.forgeboot.webmvc.dto.extension
|
||||
package com.gewuyou.webmvc.spec.jpa.extension
|
||||
|
||||
import com.gewuyou.forgeboot.webmvc.dto.PageResult
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package com.gewuyou.forgeboot.webmvc.dto.extension
|
||||
package com.gewuyou.webmvc.spec.jpa.extension
|
||||
|
||||
import jakarta.persistence.criteria.Predicate
|
||||
|
||||
@ -0,0 +1,26 @@
|
||||
package com.gewuyou.webmvc.spec.jpa.page
|
||||
|
||||
import com.gewuyou.webmvc.spec.core.page.Filterable
|
||||
import jakarta.persistence.criteria.CriteriaBuilder
|
||||
import jakarta.persistence.criteria.Predicate
|
||||
import jakarta.persistence.criteria.Root
|
||||
|
||||
/**
|
||||
*JPA可过滤接口
|
||||
*
|
||||
* @since 2025-07-24 21:40:33
|
||||
* @author gewuyou
|
||||
*/
|
||||
interface JpaFilterable<FilterType, EntityType> : Filterable<FilterType> {
|
||||
/**
|
||||
* 构建JPA查询条件规范
|
||||
*
|
||||
* 根据当前过滤条件构建JPA Criteria查询所需的谓词列表,用于动态生成查询条件。
|
||||
* 这些谓词将被用于构建最终的JPA查询语句。
|
||||
*
|
||||
* @param root 查询根对象,用于访问实体属性
|
||||
* @param cb CriteriaBuilder对象,用于创建查询条件谓词
|
||||
* @return 包含查询条件谓词的列表
|
||||
*/
|
||||
fun buildSpecification(root: Root<EntityType>, cb: CriteriaBuilder): List<Predicate>
|
||||
}
|
||||
@ -1,19 +1,19 @@
|
||||
package com.gewuyou.forgeboot.webmvc.dto.page
|
||||
package com.gewuyou.webmvc.spec.jpa.page
|
||||
|
||||
import com.gewuyou.webmvc.spec.core.page.StatusFilterable
|
||||
import jakarta.persistence.criteria.CriteriaBuilder
|
||||
import jakarta.persistence.criteria.Predicate
|
||||
import jakarta.persistence.criteria.Root
|
||||
|
||||
|
||||
/**
|
||||
* 启用状态可过滤接口,用于支持启用/禁用状态的过滤功能。
|
||||
*
|
||||
* 此接口定义了构建状态过滤条件的方法,适用于基于 JPA Criteria API 的查询构建。
|
||||
* 实现该接口的类可通过 [buildStatusPredicates]方法提供具体过滤逻辑。
|
||||
*
|
||||
* @since 2025-07-19 09:00:42
|
||||
* @author gewuyou
|
||||
*/
|
||||
interface StatusFilterable : QueryComponent {
|
||||
interface JpaStatusFilterable : StatusFilterable{
|
||||
/**
|
||||
* 构建与启用状态相关的查询条件列表。
|
||||
*
|
||||
@ -1,12 +1,12 @@
|
||||
package com.gewuyou.forgeboot.webmvc.spec.repository
|
||||
package com.gewuyou.webmvc.spec.jpa.repository
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor
|
||||
|
||||
/**
|
||||
*CRUD 存储库规范
|
||||
* Jpa CRUD 存储库规范
|
||||
*
|
||||
* @since 2025-05-29 20:39:11
|
||||
* @author gewuyou
|
||||
*/
|
||||
interface CrudRepositorySpec<Entity, Id>: JpaRepository<Entity, Id>, JpaSpecificationExecutor<Entity>
|
||||
interface JpaCrudRepositorySpec<Entity, Id>: JpaRepository<Entity, Id>, JpaSpecificationExecutor<Entity>
|
||||
@ -1,7 +1,9 @@
|
||||
package com.gewuyou.forgeboot.webmvc.dto.request
|
||||
package com.gewuyou.webmvc.spec.jpa.request
|
||||
|
||||
import com.gewuyou.forgeboot.webmvc.dto.page.Filterable
|
||||
import com.gewuyou.forgeboot.webmvc.dto.page.Pageable
|
||||
|
||||
import com.gewuyou.webmvc.spec.core.page.Pageable
|
||||
import com.gewuyou.webmvc.spec.jpa.page.JpaFilterable
|
||||
import org.hibernate.query.SortDirection
|
||||
|
||||
|
||||
/**
|
||||
@ -16,8 +18,9 @@ import com.gewuyou.forgeboot.webmvc.dto.page.Pageable
|
||||
* @since 2025-07-19 09:16:36
|
||||
* @author gewuyou
|
||||
*/
|
||||
abstract class AbstractFilteredPageRequest<T,E>(
|
||||
abstract class AbstractFilteredPageRequest<T, E>(
|
||||
override val currentPage: Int = 1,
|
||||
override val pageSize: Int = 10,
|
||||
override val filter: T? = null,
|
||||
) : Pageable, Filterable<T,E>
|
||||
sortDirection: SortDirection
|
||||
) : Pageable, JpaFilterable<T, E>
|
||||
@ -1,6 +1,12 @@
|
||||
package com.gewuyou.forgeboot.webmvc.dto.request
|
||||
package com.gewuyou.webmvc.spec.jpa.request
|
||||
|
||||
import com.gewuyou.forgeboot.webmvc.dto.page.*
|
||||
|
||||
import com.gewuyou.webmvc.spec.core.page.DateRangeFilterable
|
||||
import com.gewuyou.webmvc.spec.core.page.KeywordSearchable
|
||||
import com.gewuyou.webmvc.spec.core.page.Pageable
|
||||
import com.gewuyou.webmvc.spec.core.page.Sortable
|
||||
import com.gewuyou.webmvc.spec.core.page.StatusFilterable
|
||||
import com.gewuyou.webmvc.spec.jpa.page.JpaFilterable
|
||||
|
||||
/**
|
||||
* 抽象分页请求类,用于封装分页查询的通用参数
|
||||
@ -11,9 +17,6 @@ import com.gewuyou.forgeboot.webmvc.dto.page.*
|
||||
*
|
||||
* @property currentPage 当前页码,默认值为1
|
||||
* @property pageSize 每页记录数,默认值为10
|
||||
* @property sortBy 排序字段,默认值为"createdAt"
|
||||
* @property sortDirection 排序方向,默认值为降序(SortDirection.DESCENDING)
|
||||
* @property sortConditions 排序条件列表,默认为空列表
|
||||
* @property keyword 关键词搜索内容,可为空
|
||||
* @property filter 自定义过滤条件,可为空,类型为泛型T
|
||||
*
|
||||
@ -28,6 +31,6 @@ abstract class AbstractFullPageRequest<T,E>(
|
||||
) : Pageable,
|
||||
Sortable,
|
||||
KeywordSearchable,
|
||||
Filterable<T,E>,
|
||||
JpaFilterable<T, E>,
|
||||
DateRangeFilterable,
|
||||
StatusFilterable
|
||||
@ -1,8 +1,9 @@
|
||||
package com.gewuyou.forgeboot.webmvc.dto.request
|
||||
package com.gewuyou.webmvc.spec.jpa.request
|
||||
|
||||
import com.gewuyou.forgeboot.webmvc.dto.page.Filterable
|
||||
import com.gewuyou.forgeboot.webmvc.dto.page.KeywordSearchable
|
||||
import com.gewuyou.forgeboot.webmvc.dto.page.Pageable
|
||||
|
||||
import com.gewuyou.webmvc.spec.core.page.KeywordSearchable
|
||||
import com.gewuyou.webmvc.spec.core.page.Pageable
|
||||
import com.gewuyou.webmvc.spec.jpa.page.JpaFilterable
|
||||
|
||||
/**
|
||||
* 抽象搜索过滤分页请求
|
||||
@ -18,9 +19,9 @@ import com.gewuyou.forgeboot.webmvc.dto.page.Pageable
|
||||
* @since 2025-07-19 10:22:41
|
||||
* @author gewuyou
|
||||
*/
|
||||
abstract class AbstractSearchFilterPageRequest<T,E>(
|
||||
abstract class AbstractSearchFilterPageRequest<T, E>(
|
||||
override val currentPage: Int = 1,
|
||||
override val pageSize: Int = 10,
|
||||
override val keyword: String? = null,
|
||||
override val filter: T? = null,
|
||||
) : Pageable, KeywordSearchable, Filterable<T,E>
|
||||
) : Pageable, KeywordSearchable, JpaFilterable<T, E>
|
||||
@ -0,0 +1,29 @@
|
||||
package com.gewuyou.webmvc.spec.jpa.request
|
||||
|
||||
|
||||
import com.gewuyou.webmvc.spec.core.entities.SortCondition
|
||||
import com.gewuyou.webmvc.spec.core.page.DateRangeFilterable
|
||||
import com.gewuyou.webmvc.spec.core.page.Pageable
|
||||
import com.gewuyou.webmvc.spec.core.page.Sortable
|
||||
import com.gewuyou.webmvc.spec.jpa.page.JpaFilterable
|
||||
|
||||
/**
|
||||
* 抽象排序日期过滤分页请求基类
|
||||
*
|
||||
* 该抽象类为分页请求提供了基础结构,支持以下功能:
|
||||
* - 分页控制(通过[Pageable]接口)
|
||||
* - 排序功能(通过[Sortable]接口)
|
||||
* - 日期范围过滤(通过[DateRangeFilterable]接口)
|
||||
* - 通用数据过滤(通过[JpaFilterable]<T,E>接口)
|
||||
*
|
||||
* @property currentPage 当前页码,从1开始计数,默认值为1
|
||||
* @property pageSize 每页记录数,默认值为10
|
||||
*
|
||||
* @since 2025-07-19 14:50:36
|
||||
* @author gewuyou
|
||||
*/
|
||||
abstract class AbstractSortedDateFilterPageRequest<T, E>(
|
||||
override val currentPage: Int = 1,
|
||||
override val pageSize: Int = 10,
|
||||
override val sortConditions: List<SortCondition> = mutableListOf(),
|
||||
) : Pageable, Sortable, DateRangeFilterable, JpaFilterable<T, E>
|
||||
@ -1,10 +1,11 @@
|
||||
package com.gewuyou.forgeboot.webmvc.spec.service
|
||||
package com.gewuyou.webmvc.spec.jpa.service
|
||||
|
||||
import com.gewuyou.forgeboot.webmvc.dto.PageResult
|
||||
import com.gewuyou.forgeboot.webmvc.dto.page.QueryComponent
|
||||
import com.gewuyou.webmvc.spec.core.page.QueryComponent
|
||||
|
||||
|
||||
/**
|
||||
* CRUD 服务规范
|
||||
* Jpa CRUD 服务规范
|
||||
*
|
||||
* 定义了对实体进行基本操作的服务接口,包括增删查改和分页查询等功能
|
||||
*
|
||||
@ -13,7 +14,7 @@ import com.gewuyou.forgeboot.webmvc.dto.page.QueryComponent
|
||||
* @since 2025-05-29 20:18:22
|
||||
* @author gewuyou
|
||||
*/
|
||||
interface CrudServiceSpec<Entity: Any, Id: Any> {
|
||||
interface JpaCrudServiceSpec<Entity: Any, Id: Any> {
|
||||
/**
|
||||
* 根据ID获取实体
|
||||
*
|
||||
@ -1,24 +1,25 @@
|
||||
package com.gewuyou.forgeboot.webmvc.spec.service.impl
|
||||
package com.gewuyou.webmvc.spec.jpa.service.impl
|
||||
|
||||
import com.gewuyou.forgeboot.webmvc.dto.PageResult
|
||||
import com.gewuyou.forgeboot.webmvc.dto.extension.map
|
||||
import com.gewuyou.forgeboot.webmvc.dto.extension.toJpaQuery
|
||||
import com.gewuyou.forgeboot.webmvc.dto.extension.toPageResult
|
||||
import com.gewuyou.forgeboot.webmvc.dto.extension.toSpecification
|
||||
import com.gewuyou.forgeboot.webmvc.dto.page.QueryComponent
|
||||
import com.gewuyou.forgeboot.webmvc.spec.repository.CrudRepositorySpec
|
||||
import com.gewuyou.forgeboot.webmvc.spec.service.CrudServiceSpec
|
||||
|
||||
import com.gewuyou.webmvc.spec.core.page.QueryComponent
|
||||
import com.gewuyou.webmvc.spec.jpa.extension.map
|
||||
import com.gewuyou.webmvc.spec.jpa.extension.toJpaQuery
|
||||
import com.gewuyou.webmvc.spec.jpa.extension.toPageResult
|
||||
import com.gewuyou.webmvc.spec.jpa.extension.toSpecification
|
||||
import com.gewuyou.webmvc.spec.jpa.repository.JpaCrudRepositorySpec
|
||||
import com.gewuyou.webmvc.spec.jpa.service.JpaCrudServiceSpec
|
||||
|
||||
|
||||
/**
|
||||
* CRUD 服务实现的抽象类,提供通用的数据访问操作。
|
||||
* Jpa CRUD 服务实现的抽象类,提供通用的数据访问操作。
|
||||
*
|
||||
* @since 2025-05-29 20:37:27
|
||||
* @author gewuyou
|
||||
*/
|
||||
abstract class CrudServiceImplSpec<Entity : Any, Id : Any>(
|
||||
private val repository: CrudRepositorySpec<Entity, Id>,
|
||||
) : CrudServiceSpec<Entity, Id> {
|
||||
abstract class JpaCrudServiceImplSpec<Entity : Any, Id : Any>(
|
||||
private val repository: JpaCrudRepositorySpec<Entity, Id>,
|
||||
) : JpaCrudServiceSpec<Entity, Id> {
|
||||
|
||||
/**
|
||||
* 根据实体的唯一标识符查找实体对象。
|
||||
@ -184,15 +185,16 @@ abstract class CrudServiceImplSpec<Entity : Any, Id : Any>(
|
||||
return repository.saveAll(entities)
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记实体为软删除状态。
|
||||
*
|
||||
* 此方法应在子类中实现,用于定义如何将实体标记为已删除(例如设置一个 deleted 字段)。
|
||||
* 软删除不会从数据库中物理移除记录,而是将其标记为已删除状态,以便保留历史数据。
|
||||
*
|
||||
* @param entity 实体对象,表示要标记为删除状态的对象
|
||||
*/
|
||||
/**
|
||||
* 标记实体为软删除状态。
|
||||
*
|
||||
* 此方法应在子类中实现,用于定义如何将实体标记为已删除(例如设置一个 deleted 字段)。
|
||||
* 软删除不会从数据库中物理移除记录,而是将其标记为已删除状态,以便保留历史数据。
|
||||
*
|
||||
* @param entity 实体对象,表示要标记为删除状态的对象
|
||||
*/
|
||||
protected abstract fun setDeleted(entity: Entity)
|
||||
|
||||
/**
|
||||
* 执行软删除操作。
|
||||
*
|
||||
@ -1,117 +0,0 @@
|
||||
# forgeboot-webmvc-spec
|
||||
|
||||
> 🧩 Web 项目通用 CRUD 接口规范模块,封装 Repository 与 Service 层的标准增删改查接口与默认实现,简化重复代码。
|
||||
|
||||
---
|
||||
|
||||
## 🧩 简介
|
||||
|
||||
`forgeboot-webmvc-spec` 是 ForgeBoot 提供的统一接口规范模块,旨在为常见的 Web 开发提供可复用的 Repository 和 Service 层增删改查基础接口及实现模板。
|
||||
|
||||
通过继承和组合该模块中的接口和基类,可以快速构建具有一致风格的业务组件,提升开发效率、降低重复代码、统一项目结构。
|
||||
|
||||
---
|
||||
|
||||
## ✨ 核心功能
|
||||
|
||||
- ✅ `CrudRepositorySpec<T, ID>`:通用 Repository 接口规范(继承自 `JpaRepository`)
|
||||
- ✅ `CrudServiceSpec<T, ID>`:业务层接口标准化定义
|
||||
- ✅ `CrudServiceImplSpec<T, ID>`:默认 Service 实现(依赖 Repository)
|
||||
- ✅ 泛型支持 Entity 类型与主键类型的自动推导
|
||||
- ✅ 与 DTO 模块 (`forgeboot-webmvc-dto`) 无缝协作
|
||||
|
||||
---
|
||||
|
||||
## 📦 引入依赖
|
||||
|
||||
使用 Maven:
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>io.github.gewuyou</groupId>
|
||||
<artifactId>forgeboot-webmvc-spec</artifactId>
|
||||
<version>${version}</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
使用 Gradle:
|
||||
|
||||
```groovy
|
||||
implementation "io.github.gewuyou:forgeboot-webmvc-spec:${version}"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 快速开始
|
||||
|
||||
### ✅ 定义实体类
|
||||
|
||||
```kotlin
|
||||
@Entity
|
||||
data class Product(
|
||||
@Id val id: Long,
|
||||
val name: String,
|
||||
val status: Int
|
||||
)
|
||||
```
|
||||
|
||||
### ✅ 创建 Repository 接口
|
||||
|
||||
```kotlin
|
||||
interface ProductRepository : CrudRepositorySpec<Product, Long>
|
||||
```
|
||||
|
||||
### ✅ 创建 Service 接口
|
||||
|
||||
```kotlin
|
||||
interface ProductService : CrudServiceSpec<Product, Long>
|
||||
```
|
||||
|
||||
### ✅ 创建默认实现类
|
||||
|
||||
```kotlin
|
||||
@Service
|
||||
class ProductServiceImpl(
|
||||
override val repository: ProductRepository
|
||||
) : CrudServiceImplSpec<Product, Long>(), ProductService
|
||||
```
|
||||
|
||||
现在你就拥有了以下功能:
|
||||
- 新增:`save(entity)`
|
||||
- 修改:`updateById(id, modifier)`
|
||||
- 删除:`deleteById(id)`
|
||||
- 查询单个:`findById(id)`
|
||||
- 查询全部:`findAll()`
|
||||
|
||||
---
|
||||
|
||||
## 🧩 扩展方法(默认实现中提供)
|
||||
|
||||
```kotlin
|
||||
fun updateById(id: ID, modifier: (T) -> Unit): Boolean
|
||||
fun existsById(id: ID): Boolean
|
||||
fun deleteById(id: ID): Boolean
|
||||
```
|
||||
|
||||
可自由覆写或组合使用。
|
||||
|
||||
---
|
||||
|
||||
## 🧠 与其他模块集成建议
|
||||
|
||||
| 模块 | 集成方式说明 |
|
||||
|------------------------|-------------------------------------------|
|
||||
| `forgeboot-webmvc-dto` | 可配合 `PageResult`, `QueryComponent` 返回分页数据 |
|
||||
---
|
||||
|
||||
## 📄 许可协议
|
||||
|
||||
本项目采用 [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) 开源协议。
|
||||
|
||||
---
|
||||
|
||||
## 📬 联系作者
|
||||
|
||||
由 [@gewuyou](https://github.com/gewuyou) 维护。
|
||||
|
||||
欢迎提交 Issue 或 PR 改进本模块!
|
||||
@ -75,7 +75,8 @@ include(
|
||||
":forgeboot-webmvc:exception-i18n",
|
||||
":forgeboot-webmvc:dto",
|
||||
":forgeboot-webmvc:validation",
|
||||
":forgeboot-webmvc:spec"
|
||||
":forgeboot-webmvc:spec-core",
|
||||
":forgeboot-webmvc:spec-jpa",
|
||||
)
|
||||
project(":forgeboot-webmvc").name = "forgeboot-webmvc-spring-boot-starter"
|
||||
project(":forgeboot-webmvc:version").name = "forgeboot-webmvc-version-spring-boot-starter"
|
||||
@ -84,7 +85,8 @@ project(":forgeboot-webmvc:exception").name = "forgeboot-webmvc-exception-spring
|
||||
project(":forgeboot-webmvc:exception-i18n").name = "forgeboot-webmvc-exception-i18n-spring-boot-starter"
|
||||
project(":forgeboot-webmvc:dto").name = "forgeboot-webmvc-dto"
|
||||
project(":forgeboot-webmvc:validation").name = "forgeboot-webmvc-validation"
|
||||
project(":forgeboot-webmvc:spec").name = "forgeboot-webmvc-spec"
|
||||
project(":forgeboot-webmvc:spec-core").name = "forgeboot-webmvc-spec-core"
|
||||
project(":forgeboot-webmvc:spec-jpa").name = "forgeboot-webmvc-spec-jpa"
|
||||
//endregion
|
||||
|
||||
//region module core
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user