feat:1.7 重构 service query 的组织模式

This commit is contained in:
2024-09-30 22:55:02 +08:00
parent de8fc0256f
commit 99877eddcc
17 changed files with 108 additions and 116 deletions

View File

@@ -22,7 +22,7 @@ buildscript {
subprojects { subprojects {
group 'com.synebula' group 'com.synebula'
version '1.6.0' version '1.7.0'
buildscript { buildscript {
repositories { repositories {
@@ -66,16 +66,21 @@ subprojects {
} }
publishing { publishing {
// repositories { repositories {
// maven { maven {
// allowInsecureProtocol = true name = "Gitea"
// url = "$nexus_url" url = uri("https://git.synebula.com/api/packages/alex/maven")
// credentials {
// username = "$nexus_usr" credentials(HttpHeaderCredentials) {
// password = "$nexus_pwd" name = "Authorization"
// } value = "token 1b9a13c1c75832c2f82beba8c8db340364eff7b1"
// } }
// }
authentication {
header(HttpHeaderAuthentication)
}
}
}
publications { publications {
mavenJava(MavenPublication) { mavenJava(MavenPublication) {

View File

@@ -20,8 +20,9 @@ import org.springframework.beans.factory.annotation.Autowired
open class DomainApplication<TCommand : ICommand, TView, ID>( open class DomainApplication<TCommand : ICommand, TView, ID>(
override var name: String, override var name: String,
override var service: IService<ID>, override var service: IService<ID>,
override var query: IQuery<TView, ID>, override var query: IQuery,
override var logger: ILogger, override var clazz: Class<TView>,
override var logger: ILogger
) : ICommandApp<TCommand, ID>, IQueryApp<TView, ID> { ) : ICommandApp<TCommand, ID>, IQueryApp<TView, ID> {
@Autowired @Autowired

View File

@@ -20,7 +20,8 @@ import org.springframework.beans.factory.annotation.Autowired
open class RecordApplication<TRoot : IAggregateRoot<ID>, ID>( open class RecordApplication<TRoot : IAggregateRoot<ID>, ID>(
override var name: String, override var name: String,
override var service: IService<TRoot, ID>, override var service: IService<TRoot, ID>,
override var query: IQuery<TRoot, ID>, override var query: IQuery,
override var clazz: Class<TRoot>,
override var logger: ILogger, override var logger: ILogger,
) : ISimpleCommandApp<TRoot, ID>, IQueryApp<TRoot, ID> { ) : ISimpleCommandApp<TRoot, ID>, IQueryApp<TRoot, ID> {

View File

@@ -13,12 +13,14 @@ interface IQueryApp<TView, ID> : IApplication {
/** /**
* 查询服务 * 查询服务
*/ */
var query: IQuery<TView, ID> var query: IQuery
var clazz: Class<TView>
@Method("获取数据") @Method("获取数据")
@GetMapping("/{id:.+}") @GetMapping("/{id:.+}")
fun get(@PathVariable id: ID): HttpMessage { fun get(@PathVariable id: ID): HttpMessage {
val data = this.query.get(id) val data = this.query.get(id, clazz)
val msg = this.httpMessageFactory.create() val msg = this.httpMessageFactory.create()
msg.data = data msg.data = data
return msg return msg
@@ -27,7 +29,7 @@ interface IQueryApp<TView, ID> : IApplication {
@Method("获取列表数据") @Method("获取列表数据")
@GetMapping @GetMapping
fun list(@RequestParam params: LinkedHashMap<String, String>): HttpMessage { fun list(@RequestParam params: LinkedHashMap<String, String>): HttpMessage {
val data = this.query.list(params) val data = this.query.list(params, clazz)
return this.httpMessageFactory.create(data) return this.httpMessageFactory.create(data)
} }
@@ -39,7 +41,7 @@ interface IQueryApp<TView, ID> : IApplication {
@RequestParam parameters: LinkedHashMap<String, String> @RequestParam parameters: LinkedHashMap<String, String>
): HttpMessage { ): HttpMessage {
val params = Params(page, size, parameters) val params = Params(page, size, parameters)
val data = this.query.paging(params) val data = this.query.paging(params, clazz)
return this.httpMessageFactory.create(data) return this.httpMessageFactory.create(data)
} }
} }

View File

@@ -14,7 +14,8 @@ import org.springframework.beans.factory.annotation.Autowired
*/ */
open class QueryApp<TView, ID>( open class QueryApp<TView, ID>(
override var name: String, override var name: String,
override var query: IQuery<TView, ID>, override var query: IQuery,
override var clazz: Class<TView>,
override var logger: ILogger, override var logger: ILogger,
) : IQueryApp<TView, ID> { ) : IQueryApp<TView, ID> {

View File

@@ -3,18 +3,20 @@ package com.synebula.gaea.jpa
import com.synebula.gaea.db.query.IQuery import com.synebula.gaea.db.query.IQuery
import com.synebula.gaea.db.query.Page import com.synebula.gaea.db.query.Page
import com.synebula.gaea.db.query.Params import com.synebula.gaea.db.query.Params
import com.synebula.gaea.jpa.proxy.method.resolver.PageMethodResolver
import jakarta.persistence.EntityManager import jakarta.persistence.EntityManager
import org.springframework.data.domain.Pageable
import org.springframework.data.jpa.domain.Specification
import org.springframework.data.jpa.repository.support.SimpleJpaRepository import org.springframework.data.jpa.repository.support.SimpleJpaRepository
class JpaQuery<TView, ID>(override var clazz: Class<TView>, entityManager: EntityManager) : IQuery<TView, ID> { @Suppress("UNCHECKED_CAST")
protected var repo: SimpleJpaRepository<TView, ID> class JpaQuery(protected var entityManager: EntityManager) : IQuery {
protected var repos = mutableMapOf<Class<*>, SimpleJpaRepository<*, *>>()
init {
repo = SimpleJpaRepository<TView, ID>(clazz, entityManager)
}
override operator fun get(id: ID): TView? { override operator fun <TView, ID> get(id: ID, clazz: Class<TView>): TView? {
val view = this.repo.findById(id!!) val repo = this.getJpaRepository(clazz)
val view = repo.findById(id!!)
return if (view.isPresent) view.get() else null return if (view.isPresent) view.get() else null
} }
@@ -25,9 +27,10 @@ class JpaQuery<TView, ID>(override var clazz: Class<TView>, entityManager: Entit
* @param params 查询条件。 * @param params 查询条件。
* @return 视图列表 * @return 视图列表
*/ */
override fun list(params: Map<String, String>?): List<TView> { override fun <TView> list(params: Map<String, String>?, clazz: Class<TView>): List<TView> {
// method proxy in JpaRepositoryProxy [SimpleJpaRepository] val repo = this.getJpaRepository(clazz)
return emptyList() val spec = params?.toSpecification(clazz) as Specification<TView>
return repo.findAll(spec)
} }
/** /**
@@ -36,9 +39,10 @@ class JpaQuery<TView, ID>(override var clazz: Class<TView>, entityManager: Entit
* @param params 查询条件。 * @param params 查询条件。
* @return 数量 * @return 数量
*/ */
override fun count(params: Map<String, String>?): Int { override fun <TView> count(params: Map<String, String>?, clazz: Class<TView>): Long {
// method proxy in JpaRepositoryProxy [SimpleJpaRepository] val repo = this.getJpaRepository(clazz)
return -1 val spec = params?.toSpecification(clazz) as Specification<TView>
return repo.count(spec)
} }
/** /**
@@ -47,9 +51,11 @@ class JpaQuery<TView, ID>(override var clazz: Class<TView>, entityManager: Entit
* @param params 分页条件 * @param params 分页条件
* @return 分页数据 * @return 分页数据
*/ */
override fun paging(params: Params): Page<TView> { override fun <TView> paging(params: Params, clazz: Class<TView>): Page<TView> {
// method proxy in JpaRepositoryProxy [SimpleJpaRepository] val repo = this.getJpaRepository(clazz)
return Page() val p = PageMethodResolver("findAll", clazz).mappingArguments(arrayOf(params))
val page = repo.findAll(p[0] as Specification<TView>, p[1] as Pageable)
return Page(page.number + 1, page.size, page.totalElements, page.content)
} }
/** /**
@@ -59,9 +65,18 @@ class JpaQuery<TView, ID>(override var clazz: Class<TView>, entityManager: Entit
* *
* @return 视图列表 * @return 视图列表
*/ */
override fun range(field: String, params: List<Any>): List<TView> { override fun <TView> range(field: String, params: List<Any>, clazz: Class<TView>): List<TView> {
// method proxy in JpaRepositoryProxy [SimpleJpaRepository] // method proxy in JpaRepositoryProxy [SimpleJpaRepository]
return emptyList() return emptyList()
} }
private fun <TView> getJpaRepository(clazz: Class<TView>): SimpleJpaRepository<TView, in Any> {
if (this.repos.isNotEmpty() && this.repos.containsKey(clazz)) {
return this.repos[clazz] as SimpleJpaRepository<TView, Any>
} else {
val r = SimpleJpaRepository<TView, Any>(clazz, entityManager)
this.repos[clazz] = r
return r
}
}
} }

View File

@@ -0,0 +1,17 @@
package com.synebula.gaea.jpa
import com.synebula.gaea.domain.model.IAggregateRoot
import com.synebula.gaea.domain.repository.IRepository
import com.synebula.gaea.domain.repository.IRepositoryFactory
import jakarta.persistence.EntityManager
class JpaRepositoryFactory(private var entityManager: EntityManager) : IRepositoryFactory {
override fun createRawRepository(clazz: Class<*>): IRepository<*, *> {
val constructor = JpaRepository::class.java.getConstructor(Class::class.java, EntityManager::class.java)
return constructor.newInstance(clazz, this.entityManager)
}
override fun <T : IAggregateRoot<I>, I> createRepository(clazz: Class<T>): IRepository<T, I> {
return JpaRepository(clazz, this.entityManager)
}
}

View File

@@ -51,6 +51,6 @@ class PageMethodResolver(targetMethodName: String, clazz: Class<*>) : AbstractMe
val page = result as Page<*> val page = result as Page<*>
// Page 页面从0开始 [com.synebula.gaea.query.Page as QueryPage] // Page 页面从0开始 [com.synebula.gaea.query.Page as QueryPage]
return QueryPage(page.number + 1, page.size, page.totalElements.toInt(), page.content) return QueryPage(page.number + 1, page.size, page.totalElements, page.content)
} }
} }

View File

@@ -2,7 +2,7 @@ package com.synebula.gaea.mongodb.autoconfig
import com.synebula.gaea.db.context.IDbContext import com.synebula.gaea.db.context.IDbContext
import com.synebula.gaea.domain.repository.IRepository import com.synebula.gaea.domain.repository.IRepository
import com.synebula.gaea.mongodb.db.query.MongodbQuery import com.synebula.gaea.mongodb.db.MongodbQuery
import com.synebula.gaea.mongodb.repository.MongodbRepository import com.synebula.gaea.mongodb.repository.MongodbRepository
import com.synebula.gaea.db.query.IQuery import com.synebula.gaea.db.query.IQuery
import com.synebula.gaea.reflect.getGenericInterface import com.synebula.gaea.reflect.getGenericInterface

View File

@@ -1,4 +1,4 @@
package com.synebula.gaea.mongodb.db.context package com.synebula.gaea.mongodb.db
import com.synebula.gaea.db.IEntity import com.synebula.gaea.db.IEntity
import com.synebula.gaea.db.context.IDbContext import com.synebula.gaea.db.context.IDbContext

View File

@@ -1,4 +1,4 @@
package com.synebula.gaea.mongodb.db.query package com.synebula.gaea.mongodb.db
import com.synebula.gaea.ext.firstCharLowerCase import com.synebula.gaea.ext.firstCharLowerCase
@@ -15,19 +15,22 @@ import org.springframework.data.mongodb.core.MongoTemplate
import org.springframework.data.mongodb.core.query.Criteria import org.springframework.data.mongodb.core.query.Criteria
import org.springframework.data.mongodb.core.query.Query import org.springframework.data.mongodb.core.query.Query
open class MongodbQuery<TView, ID>(override var clazz: Class<TView>, var template: MongoTemplate) : /**
IQuery<TView, ID> { * 实现IQuery的Mongodb查询类
* @param template MongodbRepo对象
*/
open class MongodbQuery(var template: MongoTemplate) : IQuery {
/** /**
* 使用View解析是collection时是否校验存在默认不校验 * 使用View解析是collection时是否校验存在默认不校验
*/ */
var validViewCollection = false var validViewCollection = false
override fun get(id: ID): TView? { override fun <TView, ID> get(id: ID, clazz: Class<TView>): TView? {
return this.template.findOne(whereId(id), clazz, this.collection(clazz)) return this.template.findOne(whereId(id), clazz, this.collection(clazz))
} }
override fun list(params: Map<String, String>?): List<TView> { override fun <TView> list(params: Map<String, String>?, clazz: Class<TView>): List<TView> {
val fields = this.fields(clazz) val fields = this.fields(clazz)
val query = Query() val query = Query()
query.where(params, clazz) query.where(params, clazz)
@@ -35,16 +38,16 @@ open class MongodbQuery<TView, ID>(override var clazz: Class<TView>, var templat
return this.find(query, clazz) return this.find(query, clazz)
} }
override fun count(params: Map<String, String>?): Int { override fun <TView> count(params: Map<String, String>?, clazz: Class<TView>): Long {
val query = Query() val query = Query()
return this.template.count(query.where(params, clazz), this.collection(clazz)).toInt() return this.template.count(query.where(params, clazz), this.collection(clazz))
} }
override fun paging(params: Params): Page<TView> { override fun <TView> paging(params: Params, clazz: Class<TView>): Page<TView> {
val query = Query() val query = Query()
val fields = this.fields(clazz) val fields = this.fields(clazz)
val result = Page<TView>(params.page, params.size) val result = Page<TView>(params.page, params.size)
result.total = this.count(params.parameters) result.total = this.count(params.parameters, clazz)
//如果总数和索引相同,说明该页没有数据,直接跳到上一页 //如果总数和索引相同,说明该页没有数据,直接跳到上一页
if (result.total == result.index) { if (result.total == result.index) {
params.page -= 1 params.page -= 1
@@ -58,11 +61,11 @@ open class MongodbQuery<TView, ID>(override var clazz: Class<TView>, var templat
return result return result
} }
override fun range(field: String, params: List<Any>): List<TView> { override fun <TView> range(field: String, params: List<Any>, clazz: Class<TView>): List<TView> {
return this.find(Query.query(Criteria.where(field).`in`(params)), clazz) return this.find(Query.query(Criteria.where(field).`in`(params)), clazz)
} }
protected fun find(query: Query, clazz: Class<TView>): List<TView> { protected fun <TView> find(query: Query, clazz: Class<TView>): List<TView> {
return this.template.find(query, clazz, this.collection(clazz)) return this.template.find(query, clazz, this.collection(clazz))
} }

View File

@@ -1,23 +0,0 @@
package com.synebula.gaea.mongodb.db.query
import com.synebula.gaea.db.query.IQuery
import com.synebula.gaea.db.query.IQueryFactory
import org.springframework.data.mongodb.core.MongoTemplate
class MongodbQueryFactory(var template: MongoTemplate) : IQueryFactory {
/**
* 创建IQuery接口类型
*/
override fun createRawQuery(clazz: Class<*>): IQuery<*, *> {
val constructor = MongodbQuery::class.java.getConstructor(Class::class.java, MongoTemplate::class.java)
return constructor.newInstance(clazz, this.template)
}
/**
* 创建IQuery接口类型
*/
override fun <T, I> createQuery(clazz: Class<T>): IQuery<T, I> {
return MongodbQuery(clazz, template)
}
}

View File

@@ -13,12 +13,3 @@ dependencies {
api("org.springframework.boot:spring-boot-starter-aop:$spring_version") api("org.springframework.boot:spring-boot-starter-aop:$spring_version")
} }
publishing {
publications {
publish(MavenPublication) {
from components.java
}
}
}

View File

@@ -5,27 +5,22 @@ package com.synebula.gaea.db.query
* *
* @author alex * @author alex
*/ */
interface IQuery<TView, ID> { interface IQuery {
/**
* 仓储的视图类
*/
var clazz: Class<TView>
/** /**
* 根据Key获取对象。 * 根据Key获取对象。
* *
* @param id 对象Key。 * @param id 对象Key。
* @return 视图结果 * @return 视图结果
*/ */
fun get(id: ID): TView? fun <TView, ID> get(id: ID, clazz: Class<TView>): TView?
/** /**
* 根据实体类条件查询所有符合条件记录 * 根据实体类条件查询所有符合条件记录
*` *
* @param params 查询条件。 * @param params 查询条件。
* @return 视图列表 * @return 视图列表
*/ */
fun list(params: Map<String, String>?): List<TView> fun <TView> list(params: Map<String, String>?, clazz: Class<TView>): List<TView>
/** /**
* 根据条件查询符合条件记录的数量 * 根据条件查询符合条件记录的数量
@@ -33,7 +28,7 @@ interface IQuery<TView, ID> {
* @param params 查询条件。 * @param params 查询条件。
* @return 数量 * @return 数量
*/ */
fun count(params: Map<String, String>?): Int fun <TView> count(params: Map<String, String>?, clazz: Class<TView>): Long
/** /**
* 根据实体类条件查询所有符合条件记录(分页查询) * 根据实体类条件查询所有符合条件记录(分页查询)
@@ -41,7 +36,7 @@ interface IQuery<TView, ID> {
* @param params 分页条件 * @param params 分页条件
* @return 分页数据 * @return 分页数据
*/ */
fun paging(params: Params): Page<TView> fun <TView> paging(params: Params, clazz: Class<TView>): Page<TView>
/** /**
* 查询条件范围内数据。 * 查询条件范围内数据。
@@ -50,5 +45,5 @@ interface IQuery<TView, ID> {
* *
* @return 视图列表 * @return 视图列表
*/ */
fun range(field: String, params: List<Any>): List<TView> fun <TView> range(field: String, params: List<Any>, clazz: Class<TView>): List<TView>
} }

View File

@@ -1,17 +0,0 @@
package com.synebula.gaea.db.query
/**
* Query 工厂接口。 定义了Query的创建方法。
*/
interface IQueryFactory {
/**
* 创建原始类型的IQuery接口类型
*/
fun createRawQuery(clazz: Class<*>): IQuery<*, *>
/**
* 创建指定类型的IQuery接口类型
*/
fun <T, I> createQuery(clazz: Class<T>): IQuery<T, I>
}

View File

@@ -13,13 +13,13 @@ data class Page<T>(var page: Int = 0, var size: Int = 0) {
/** /**
* 总数据量。 * 总数据量。
*/ */
var total: Int = 0 var total: Long = 0
/** /**
* 数据索引从0开始。表示数据在总量的第几条。index = (page - 1) * size * 数据索引从0开始。表示数据在总量的第几条。index = (page - 1) * size
*/ */
val index: Int val index: Long
get() = (page - 1) * size get() = (page - 1) * size.toLong()
/** /**
* 结果数据。 * 结果数据。
@@ -36,7 +36,7 @@ data class Page<T>(var page: Int = 0, var size: Int = 0) {
* @param data 结果数据。 * @param data 结果数据。
*/ */
constructor(page: Int, size: Int, total: Int, data: List<T>) : this(page, size) { constructor(page: Int, size: Int, total: Long, data: List<T>) : this(page, size) {
this.page = page this.page = page
this.size = size this.size = size
this.total = total this.total = total

View File

@@ -24,9 +24,10 @@ open class Service<TRoot : IAggregateRoot<ID>, ID>(
protected open var clazz: Class<TRoot>, protected open var clazz: Class<TRoot>,
protected open var repository: IRepository<TRoot, ID>, protected open var repository: IRepository<TRoot, ID>,
protected open var mapper: IObjectMapper, protected open var mapper: IObjectMapper,
protected open var bus: IBus<Any>? = null
) : IService<ID> { ) : IService<ID> {
protected open var bus: IBus<Any>? = null
/** /**
* 增加对象 * 增加对象
* *