1.1.0 add service / repository / query spring auto config function

This commit is contained in:
2022-08-18 14:35:01 +08:00
parent b7cfd0a7f9
commit 07684e814d
42 changed files with 1001 additions and 272 deletions

View File

@@ -1,6 +1,6 @@
buildscript {
ext {
kotlin_version = '1.7.0'
kotlin_version = '1.6.10'
spring_version = "2.7.0"
}
@@ -17,7 +17,7 @@ buildscript {
subprojects {
group 'com.synebula'
version '1.0.0'
version '1.1.0'
buildscript {
repositories {

View File

@@ -1,4 +1,8 @@
rootProject.name = 'gaea'
include 'src:gaea'
include 'src:gaea.app'
include 'src:gaea.mongo'
include 'src:gaea.mongodb'
include 'src:gaea.spring'
include 'src:gaea.spring'
findProject(':src:gaea.spring')?.name = 'gaea.spring'

View File

@@ -8,6 +8,8 @@ apply plugin: 'kotlin-spring'
dependencies {
api project(":src:gaea")
api project(":src:gaea.spring")
api("org.springframework.boot:spring-boot-starter-web:$spring_version")
api("org.springframework.boot:spring-boot-starter-aop:$spring_version")
api("org.springframework.boot:spring-boot-starter-mail:$spring_version")

View File

@@ -13,16 +13,14 @@ import javax.annotation.Resource
* 联合服务同时实现了ICommandApp和IQueryApp接口
*
* @param name 业务名称
* @param clazz 试图业务对象
* @param service 业务domain服务
* @param query 业务查询服务
* @param logger 日志组件
*/
open class Application<TCommand : ICommand, TView, ID>(
override var name: String,
override var clazz: Class<TView>,
override var service: IService<ID>,
override var query: IQuery,
override var query: IQuery<TView, ID>,
override var logger: ILogger,
) : ICommandApp<TCommand, ID>, IQueryApp<TView, ID> {

View File

@@ -13,16 +13,14 @@ import javax.annotation.Resource
* 简单的服务, 取消了Command对象
*
* @param name 业务名称
* @param clazz 业务对象类型
* @param service 业务domain服务
* @param query 业务查询服务
* @param logger 日志组件
*/
open class SimpleApplication<TRoot : IAggregateRoot<ID>, ID>(
override var name: String,
override var clazz: Class<TRoot>,
override var service: ISimpleService<TRoot, ID>,
override var query: IQuery,
override var query: IQuery<TRoot, ID>,
override var logger: ILogger,
) : ISimpleCommandApp<TRoot, ID>, IQueryApp<TRoot, ID> {

View File

@@ -0,0 +1,15 @@
package com.synebula.gaea.app.autoconfig.service
import com.synebula.gaea.spring.autoconfig.Factory
import com.synebula.gaea.spring.autoconfig.Proxy
import org.springframework.beans.factory.BeanFactory
class ServiceFactory(
supertype: Class<*>,
var beanFactory: BeanFactory,
var implementBeanNames: Array<String> = arrayOf()
) : Factory(supertype) {
override fun createProxy(): Proxy {
return ServiceProxy(supertype, this.beanFactory, this.implementBeanNames)
}
}

View File

@@ -0,0 +1,56 @@
package com.synebula.gaea.app.autoconfig.service
import com.synebula.gaea.data.serialization.IObjectMapper
import com.synebula.gaea.domain.repository.IRepository
import com.synebula.gaea.domain.service.IService
import com.synebula.gaea.domain.service.Service
import com.synebula.gaea.domain.service.ServiceDependency
import com.synebula.gaea.spring.autoconfig.Proxy
import org.springframework.beans.factory.BeanFactory
import java.io.InvalidClassException
import java.lang.reflect.Method
class ServiceProxy(
private var supertype: Class<*>, private var beanFactory: BeanFactory, implementBeanNames: Array<String> = arrayOf()
) : Proxy() {
private var service: IService<*>
init {
// 如果没有实现类, 使用Service类代理
if (implementBeanNames.isEmpty()) {
// 如果没有实现类并且没有ServiceDependency注解, 则抛出异常
if (!this.supertype.declaredAnnotations.any { it.annotationClass == ServiceDependency::class }) {
throw InvalidClassException(
"interface ${this.supertype.name} must has implementation class or annotation by ${ServiceDependency::class.qualifiedName}"
)
}
val serviceDependency = this.supertype.getDeclaredAnnotation(ServiceDependency::class.java)
val repo = this.beanFactory.getBean(serviceDependency.repo.java)
val mapper = this.beanFactory.getBean(IObjectMapper::class.java)
val constructor = Service::class.java.getConstructor(
Class::class.java, IRepository::class.java, IObjectMapper::class.java
)
this.service = constructor.newInstance(serviceDependency.clazz.java, repo, mapper)
} else {
this.service = this.beanFactory.getBean(implementBeanNames[0]) as IService<*>
}
}
/**
* 执行代理方法
*
* @param proxy 代理对象
* @param method 需要执行的方法
* @param args 参数列表
* @return 方法执行结果
*/
override fun exec(proxy: Any, method: Method, args: Array<Any>): Any? {
try {
val proxyMethod = this.service.javaClass.getDeclaredMethod(method.name, *method.parameterTypes)
return proxyMethod.invoke(this.service, *args)
} catch (ex: NoSuchMethodException) {
throw NoSuchMethodException("method [${method.toGenericString()}] not implements in class [${this.service::class.java}], you must implements interface [${this.supertype.name}] ")
}
}
}

View File

@@ -0,0 +1,50 @@
package com.synebula.gaea.app.autoconfig.service
import com.synebula.gaea.domain.service.IService
import com.synebula.gaea.spring.autoconfig.Register
import org.springframework.beans.factory.config.BeanDefinition
import org.springframework.beans.factory.support.BeanDefinitionBuilder
import org.springframework.beans.factory.support.GenericBeanDefinition
import org.springframework.core.annotation.AnnotationAttributes
import org.springframework.core.type.AnnotationMetadata
class ServiceRegister : Register() {
override fun scan(metadata: AnnotationMetadata): Map<String, BeanDefinition> {
val result = mutableMapOf<String, BeanDefinition>()
// 获取注解参数信息:basePackages
val attributes = AnnotationAttributes(
metadata.getAnnotationAttributes(
ServiceScan::class.java.name
) ?: mapOf()
)
val basePackages = attributes.getStringArray("basePackages")
val beanDefinitions = this.doScan(basePackages, arrayOf(this.interfaceFilter(arrayOf(IService::class.java))))
beanDefinitions.forEach { beanDefinition ->
// 获取实际的bean类型
val beanClazz: Class<*> = try {
Class.forName(beanDefinition.beanClassName)
} catch (e: ClassNotFoundException) {
throw e
}
// 尝试获取实际继承类型
val implBeanDefinitions = this.doScan(basePackages, arrayOf(this.interfaceFilter(arrayOf(beanClazz))))
implBeanDefinitions.forEach {
it.isAutowireCandidate = false
result[it.beanClassName!!] = it
}
// 构造BeanDefinition
val builder = BeanDefinitionBuilder.genericBeanDefinition(beanClazz)
builder.addConstructorArgValue(beanClazz)
builder.addConstructorArgValue(this._beanFactory)
builder.addConstructorArgValue(implBeanDefinitions.map { it.beanClassName })
val definition = builder.rawBeanDefinition as GenericBeanDefinition
definition.beanClass = ServiceFactory::class.java
definition.autowireMode = GenericBeanDefinition.AUTOWIRE_BY_TYPE
result[beanClazz.name] = definition
}
return result
}
}

View File

@@ -0,0 +1,12 @@
package com.synebula.gaea.app.autoconfig.service
import org.springframework.context.annotation.Import
import java.lang.annotation.Inherited
@Target(AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
@Inherited
@Import(ServiceRegister::class)
annotation class ServiceScan(val basePackages: Array<String> = [])

View File

@@ -13,17 +13,12 @@ interface IQueryApp<TView, ID> : IApplication {
/**
* 查询服务
*/
var query: IQuery
/**
* 查询的View类型
*/
var clazz: Class<TView>
var query: IQuery<TView, ID>
@Method("获取数据")
@GetMapping("/{id:.+}")
fun get(@PathVariable id: ID): HttpMessage {
val data = this.query.get(id, clazz)
val data = this.query.get(id)
val msg = HttpMessage()
msg.data = data
return msg
@@ -32,19 +27,19 @@ interface IQueryApp<TView, ID> : IApplication {
@Method("获取列表数据")
@GetMapping
fun list(@RequestParam params: LinkedHashMap<String, Any>): HttpMessage {
val data = this.query.list(params, clazz)
val data = this.query.list(params)
return HttpMessage(data)
}
@Method("获取分页数据")
@GetMapping("/segments/{size}/pages/{page}")
@GetMapping("/size/{size}/pages/{page}")
fun paging(
@PathVariable size: Int,
@PathVariable page: Int,
@RequestParam parameters: LinkedHashMap<String, Any>
): HttpMessage {
val params = Params(page, size, parameters)
val data = this.query.paging(params, clazz)
val data = this.query.paging(params)
return HttpMessage(data)
}
}

View File

@@ -12,7 +12,6 @@ import com.synebula.gaea.query.IQuery
*/
open class QueryApp<TView, ID>(
override var name: String,
override var clazz: Class<TView>,
override var query: IQuery,
override var query: IQuery<TView, ID>,
override var logger: ILogger,
) : IQueryApp<TView, ID>

View File

@@ -1,5 +1,6 @@
dependencies {
api project(":src:gaea")
api project(":src:gaea.spring")
api("org.springframework.boot:spring-boot-starter-data-mongodb:$spring_version")
}

View File

@@ -1,9 +1,9 @@
package com.synebula.gaea.mongo
package com.synebula.gaea.mongodb
import com.synebula.gaea.data.date.DateTime
import com.synebula.gaea.query.annotation.Where
import com.synebula.gaea.query.type.Operator
import com.synebula.gaea.query.type.Order
import com.synebula.gaea.query.Operator
import com.synebula.gaea.query.Order
import com.synebula.gaea.query.Where
import org.springframework.data.domain.Sort
import org.springframework.data.mongodb.core.query.Criteria
import org.springframework.data.mongodb.core.query.Query

View File

@@ -0,0 +1,15 @@
package com.synebula.gaea.mongodb.autoconfig
import com.synebula.gaea.spring.autoconfig.Factory
import com.synebula.gaea.spring.autoconfig.Proxy
import org.springframework.beans.factory.BeanFactory
class MongodbRepoFactory(
supertype: Class<*>,
var beanFactory: BeanFactory,
var implementBeanNames: Array<String> = arrayOf()
) : Factory(supertype) {
override fun createProxy(): Proxy {
return MongodbRepoProxy(supertype, this.beanFactory, this.implementBeanNames)
}
}

View File

@@ -0,0 +1,84 @@
package com.synebula.gaea.mongodb.autoconfig
import com.synebula.gaea.domain.repository.IRepository
import com.synebula.gaea.log.ILogger
import com.synebula.gaea.mongodb.query.MongodbQuery
import com.synebula.gaea.mongodb.repository.MongodbRepository
import com.synebula.gaea.query.IQuery
import com.synebula.gaea.spring.autoconfig.Proxy
import org.springframework.beans.factory.BeanFactory
import org.springframework.data.mongodb.core.MongoTemplate
import java.io.InvalidClassException
import java.lang.reflect.Method
import java.lang.reflect.ParameterizedType
class MongodbRepoProxy(
private var supertype: Class<*>, private var beanFactory: BeanFactory, implementBeanNames: Array<String> = arrayOf()
) : Proxy() {
private var repo: IRepository<*, *>? = null
private var query: IQuery<*, *>? = null
init {
if (this.supertype.interfaces.any { it == IRepository::class.java }) {
// 如果是IRepository子接口
if (implementBeanNames.isEmpty()) {
val genericInterfaces = this.supertype.genericInterfaces.find {
it.typeName.startsWith(IRepository::class.java.typeName)
}!!
val constructor = MongodbRepository::class.java.getConstructor(
Class::class.java, MongoTemplate::class.java
)
this.repo = constructor.newInstance(
(genericInterfaces as ParameterizedType).actualTypeArguments[0],
this.beanFactory.getBean(MongoTemplate::class.java)
)
} else {
this.repo = this.beanFactory.getBean(implementBeanNames[0]) as IRepository<*, *>
}
} else {
// 否则是IQuery子接口
if (implementBeanNames.isEmpty()) {
val genericInterfaces = this.supertype.genericInterfaces.find {
it.typeName.startsWith(IQuery::class.java.typeName)
}!!
val constructor = MongodbQuery::class.java.getConstructor(
Class::class.java, MongoTemplate::class.java, ILogger::class.java
)
this.query = constructor.newInstance(
(genericInterfaces as ParameterizedType).actualTypeArguments[0],
this.beanFactory.getBean(MongoTemplate::class.java),
this.beanFactory.getBean(ILogger::class.java),
)
} else {
this.query = this.beanFactory.getBean(implementBeanNames[0]) as IQuery<*, *>
}
}
}
/**
* 执行代理方法
*
* @param proxy 代理对象
* @param method 需要执行的方法
* @param args 参数列表
* @return 方法执行结果
*/
override fun exec(proxy: Any, method: Method, args: Array<Any>): Any? {
val proxyClazz = if (this.repo != null) {
this.repo!!.javaClass
} else if (this.query != null) {
this.query!!.javaClass
} else
throw InvalidClassException("class ${this.supertype.name} property repo and query are both null")
try {
val proxyMethod: Method = proxyClazz.getDeclaredMethod(method.name, *method.parameterTypes)
return proxyMethod.invoke(this.repo, *args)
} catch (ex: NoSuchMethodException) {
throw NoSuchMethodException("method [${method.toGenericString()}] not implements in class [${proxyClazz}], you must implements interface [${this.supertype.name}] ")
}
}
}

View File

@@ -0,0 +1,54 @@
package com.synebula.gaea.mongodb.autoconfig
import com.synebula.gaea.domain.repository.IRepository
import com.synebula.gaea.query.IQuery
import com.synebula.gaea.spring.autoconfig.Register
import org.springframework.beans.factory.config.BeanDefinition
import org.springframework.beans.factory.support.BeanDefinitionBuilder
import org.springframework.beans.factory.support.GenericBeanDefinition
import org.springframework.core.annotation.AnnotationAttributes
import org.springframework.core.type.AnnotationMetadata
class MongodbRepoRegister : Register() {
override fun scan(metadata: AnnotationMetadata): Map<String, BeanDefinition> {
val result = mutableMapOf<String, BeanDefinition>()
// 获取注解参数信息:basePackages
val attributes = AnnotationAttributes(
metadata.getAnnotationAttributes(
MongodbRepoScan::class.java.name
) ?: mapOf()
)
val basePackages = attributes.getStringArray("basePackages")
val beanDefinitions = this.doScan(
basePackages,
arrayOf(this.interfaceFilter(arrayOf(IRepository::class.java, IQuery::class.java)))
)
beanDefinitions.forEach { beanDefinition ->
// 获取实际的bean类型
val beanClazz: Class<*> = try {
Class.forName(beanDefinition.beanClassName)
} catch (ex: ClassNotFoundException) {
throw ex
}
// 尝试获取实际继承类型
val implBeanDefinitions = this.doScan(basePackages, arrayOf(this.interfaceFilter(arrayOf(beanClazz))))
implBeanDefinitions.forEach {
it.isAutowireCandidate = false
result[it.beanClassName!!] = it
}
// 构造BeanDefinition
val builder = BeanDefinitionBuilder.genericBeanDefinition(beanClazz)
builder.addConstructorArgValue(beanClazz)
builder.addConstructorArgValue(this._beanFactory)
builder.addConstructorArgValue(implBeanDefinitions.map { it.beanClassName })
val definition = builder.rawBeanDefinition as GenericBeanDefinition
definition.beanClass = MongodbRepoFactory::class.java
definition.autowireMode = GenericBeanDefinition.AUTOWIRE_BY_TYPE
result[beanClazz.name] = definition
}
return result
}
}

View File

@@ -0,0 +1,12 @@
package com.synebula.gaea.mongodb.autoconfig
import org.springframework.context.annotation.Import
import java.lang.annotation.Inherited
@Target(AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
@Inherited
@Import(MongodbRepoRegister::class)
annotation class MongodbRepoScan(val basePackages: Array<String> = [])

View File

@@ -0,0 +1,102 @@
package com.synebula.gaea.mongodb.query
import com.synebula.gaea.ext.fieldNames
import com.synebula.gaea.ext.firstCharLowerCase
import com.synebula.gaea.log.ILogger
import com.synebula.gaea.mongodb.order
import com.synebula.gaea.mongodb.select
import com.synebula.gaea.mongodb.where
import com.synebula.gaea.mongodb.whereId
import com.synebula.gaea.query.IQuery
import com.synebula.gaea.query.Page
import com.synebula.gaea.query.Params
import com.synebula.gaea.query.Table
import org.springframework.data.mongodb.core.MongoTemplate
import org.springframework.data.mongodb.core.query.Criteria
import org.springframework.data.mongodb.core.query.Query
/**
* 实现IQuery的Mongodb查询类
* @param template MongodbRepo对象
*/
open class MongodbQuery<TView, ID>(override var clazz: Class<TView>, var template: MongoTemplate, var logger: ILogger) :
IQuery<TView, ID> {
/**
* 使用View解析是collection时是否校验存在默认不校验
*/
var validViewCollection = false
override fun get(id: ID): TView? {
return this.template.findOne(whereId(id), clazz, this.collection(clazz))
}
override fun list(params: Map<String, Any>?): List<TView> {
val fields = this.fields(clazz)
val query = Query()
query.where(params, clazz)
query.select(fields)
return this.find(query, clazz)
}
override fun count(params: Map<String, Any>?): Int {
val query = Query()
return this.template.count(query.where(params, clazz), this.collection(clazz)).toInt()
}
override fun paging(params: Params): Page<TView> {
val query = Query()
val fields = this.fields(clazz)
val result = Page<TView>(params.page, params.size)
result.total = this.count(params.parameters)
//如果总数和索引相同,说明该页没有数据,直接跳到上一页
if (result.total == result.index) {
params.page -= 1
result.page -= 1
}
query.select(fields)
query.where(params.parameters, clazz)
query.with(order(params.orders))
query.skip(params.index).limit(params.size)
result.data = this.find(query, clazz)
return result
}
override fun range(field: String, params: List<Any>): List<TView> {
return this.find(Query.query(Criteria.where(field).`in`(params)), clazz)
}
protected fun find(query: Query, clazz: Class<TView>): List<TView> {
return this.template.find(query, clazz, this.collection(clazz))
}
protected fun fields(clazz: Class<TView>): Array<String> {
val fields = mutableListOf<String>()
fields.addAll(clazz.fieldNames())
var parent = clazz.superclass
while (parent != Any::class.java) {
fields.addAll(clazz.superclass.fieldNames())
parent = parent.superclass
}
return fields.toTypedArray()
}
/**
* 获取collection
*/
protected fun collection(clazz: Class<TView>): String {
val table: Table? = clazz.getDeclaredAnnotation(
Table::class.java
)
return if (table != null) return table.name
else {
this.logger.info(this, "视图类没有标记[Collection]注解无法获取Collection名称。尝试使用View<${clazz.name}>名称解析集合")
val name = clazz.simpleName.removeSuffix("View").firstCharLowerCase()
if (!validViewCollection || this.template.collectionExists(name)) name
else {
throw RuntimeException("找不到名为[${clazz.name}]的集合")
}
}
}
}

View File

@@ -1,16 +1,17 @@
package com.synebula.gaea.mongo.query
package com.synebula.gaea.mongodb.query
import com.synebula.gaea.ext.fieldNames
import com.synebula.gaea.ext.firstCharLowerCase
import com.synebula.gaea.log.ILogger
import com.synebula.gaea.mongo.order
import com.synebula.gaea.mongo.select
import com.synebula.gaea.mongo.where
import com.synebula.gaea.mongo.whereId
import com.synebula.gaea.query.IQuery
import com.synebula.gaea.mongodb.order
import com.synebula.gaea.mongodb.select
import com.synebula.gaea.mongodb.where
import com.synebula.gaea.mongodb.whereId
import com.synebula.gaea.query.IUniversalQuery
import com.synebula.gaea.query.Page
import com.synebula.gaea.query.Params
import com.synebula.gaea.query.annotation.Table
import com.synebula.gaea.query.Table
import org.springframework.data.mongodb.core.MongoTemplate
import org.springframework.data.mongodb.core.query.Criteria
import org.springframework.data.mongodb.core.query.Query
@@ -19,8 +20,7 @@ import org.springframework.data.mongodb.core.query.Query
* 实现IQuery的Mongodb查询类
* @param template MongodbRepo对象
*/
open class MongodbQuery(var template: MongoTemplate, var logger: ILogger) : IQuery {
open class MongodbUniversalQuery(var template: MongoTemplate, var logger: ILogger) : IUniversalQuery {
/**
* 使用View解析是collection时是否校验存在默认不校验
@@ -36,7 +36,7 @@ open class MongodbQuery(var template: MongoTemplate, var logger: ILogger) : IQue
val query = Query()
query.where(params, clazz)
query.select(fields)
return this.template.find(query, clazz, this.collection(clazz))
return this.find(query, clazz)
}
override fun <TView> count(params: Map<String, Any>?, clazz: Class<TView>): Int {
@@ -58,12 +58,16 @@ open class MongodbQuery(var template: MongoTemplate, var logger: ILogger) : IQue
query.where(params.parameters, clazz)
query.with(order(params.orders))
query.skip(params.index).limit(params.size)
result.data = this.template.find(query, clazz, this.collection(clazz))
result.data = this.find(query, clazz)
return result
}
override fun <TView> range(field: String, params: List<Any>, clazz: Class<TView>): List<TView> {
return this.template.find(Query.query(Criteria.where(field).`in`(params)), clazz, this.collection(clazz))
return this.find(Query.query(Criteria.where(field).`in`(params)), clazz)
}
protected fun <TView> find(query: Query, clazz: Class<TView>): List<TView> {
return this.template.find(query, clazz, this.collection(clazz))
}
fun <TView> fields(clazz: Class<TView>): Array<String> {

View File

@@ -0,0 +1,47 @@
package com.synebula.gaea.mongodb.repository
import com.synebula.gaea.domain.model.IAggregateRoot
import com.synebula.gaea.domain.repository.IRepository
import com.synebula.gaea.mongodb.where
import com.synebula.gaea.mongodb.whereId
import org.springframework.data.mongodb.core.MongoTemplate
import org.springframework.data.mongodb.core.query.Query
/**
* 实现[IRepository]的Mongodb仓储类
* @param repo MongodbRepo对象
*/
open class MongodbRepository<TAggregateRoot : IAggregateRoot<ID>, ID>(
override var clazz: Class<TAggregateRoot>,
protected var repo: MongoTemplate
) : IRepository<TAggregateRoot, ID> {
override fun add(obj: TAggregateRoot) {
this.repo.save(obj)
}
override fun add(list: List<TAggregateRoot>) {
this.repo.insert(list, clazz)
}
override fun remove(id: ID) {
this.repo.remove(whereId(id), clazz)
}
override fun get(id: ID): TAggregateRoot? {
return this.repo.findOne(whereId(id), clazz)
}
override fun update(obj: TAggregateRoot) {
this.repo.save(obj)
}
override fun update(list: List<TAggregateRoot>) {
this.repo.save(list)
}
override fun <TAggregateRoot> count(params: Map<String, Any>?): Int {
val query = Query()
return this.repo.count(query.where(params, clazz), clazz).toInt()
}
}

View File

@@ -1,9 +1,9 @@
package com.synebula.gaea.mongo.repository
package com.synebula.gaea.mongodb.repository
import com.synebula.gaea.domain.model.IAggregateRoot
import com.synebula.gaea.domain.repository.IRepository
import com.synebula.gaea.mongo.where
import com.synebula.gaea.mongo.whereId
import com.synebula.gaea.domain.repository.IUniversalRepository
import com.synebula.gaea.mongodb.where
import com.synebula.gaea.mongodb.whereId
import org.springframework.data.mongodb.core.MongoTemplate
import org.springframework.data.mongodb.core.query.Query
@@ -11,7 +11,7 @@ import org.springframework.data.mongodb.core.query.Query
* 实现ITypedRepository的Mongodb仓储类
* @param repo MongodbRepo对象
*/
open class MongodbRepository(private var repo: MongoTemplate) : IRepository {
open class MongodbUniversalRepository(private var repo: MongoTemplate) : IUniversalRepository {
override fun <TAggregateRoot : IAggregateRoot<ID>, ID> remove(id: ID, clazz: Class<TAggregateRoot>) {
this.repo.remove(whereId(id), clazz)
@@ -25,21 +25,33 @@ open class MongodbRepository(private var repo: MongoTemplate) : IRepository {
}
override fun <TAggregateRoot : IAggregateRoot<ID>, ID> update(
obj: TAggregateRoot,
root: TAggregateRoot,
clazz: Class<TAggregateRoot>,
) {
this.repo.save(obj)
this.repo.save(root)
}
override fun <TAggregateRoot : IAggregateRoot<ID>, ID> add(obj: TAggregateRoot, clazz: Class<TAggregateRoot>) {
this.repo.save(obj)
/**
* 更新多个个对象
*
* @param roots 需要更新的对象
*/
override fun <TAggregateRoot : IAggregateRoot<ID>, ID> update(
roots: List<TAggregateRoot>,
clazz: Class<TAggregateRoot>
) {
this.repo.save(roots)
}
override fun <TAggregateRoot : IAggregateRoot<ID>, ID> add(root: TAggregateRoot, clazz: Class<TAggregateRoot>) {
this.repo.save(root)
}
override fun <TAggregateRoot : IAggregateRoot<ID>, ID> add(
obj: List<TAggregateRoot>,
roots: List<TAggregateRoot>,
clazz: Class<TAggregateRoot>,
) {
this.repo.insert(obj, clazz)
this.repo.insert(roots, clazz)
}
override fun <TAggregateRoot> count(params: Map<String, Any>?, clazz: Class<TAggregateRoot>): Int {

View File

@@ -0,0 +1,22 @@
buildscript {
dependencies {
classpath("org.jetbrains.kotlin:kotlin-allopen:$kotlin_version")
}
}
apply plugin: 'kotlin-spring'
dependencies {
implementation project(":src:gaea")
implementation("org.springframework.boot:spring-boot-starter-web:$spring_version")
implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.6'
}
publishing {
publications {
publish(MavenPublication) {
from components.java
}
}
}

View File

@@ -0,0 +1,44 @@
package com.synebula.gaea.spring.autoconfig
import org.springframework.beans.factory.FactoryBean
import org.springframework.cglib.proxy.Enhancer
import java.lang.reflect.Proxy as JdkProxy
/**
* 代理生成工厂
*
* @param supertype 需要被代理的父类型
* @param proxyType 代理类型:JDK 或 CGLIB
*/
abstract class Factory(
protected val supertype: Class<*>,
protected val proxyType: ProxyType = ProxyType.Cglib
) : FactoryBean<Any> {
override fun getObject(): Any {
val handler: Proxy = this.createProxy()
//JDK 方式代理代码, 暂时选用cglib
val proxy: Any = if (proxyType == ProxyType.JDK) {
JdkProxy.newProxyInstance(
this.supertype.classLoader, arrayOf(this.supertype), handler
)
} else { //cglib代理
val enhancer = Enhancer()
enhancer.setSuperclass(supertype)
enhancer.setCallback(handler)
enhancer.create()
}
return proxy
}
override fun getObjectType(): Class<*> {
return supertype
}
override fun isSingleton(): Boolean {
return true
}
abstract fun createProxy(): Proxy
}

View File

@@ -0,0 +1,43 @@
package com.synebula.gaea.spring.autoconfig
import org.springframework.cglib.proxy.MethodInterceptor
import org.springframework.cglib.proxy.MethodProxy
import java.lang.reflect.InvocationHandler
import java.lang.reflect.Method
abstract class Proxy : MethodInterceptor, InvocationHandler {
/**
* JDK 方式代理代码
*/
@Throws(Throwable::class)
override fun invoke(proxy: Any, method: Method, args: Array<Any>): Any? {
return if (Any::class.java == method.declaringClass) {
method.invoke(this, *args)
} else {
exec(proxy, method, args)
}
}
/**
* 暂时选用cglib 方式代理代码
*/
@Throws(Throwable::class)
override fun intercept(proxy: Any, method: Method, args: Array<Any>, methodProxy: MethodProxy): Any? {
return if (Any::class.java == method.declaringClass) {
methodProxy.invoke(this, args)
} else {
exec(proxy, method, args)
}
}
/**
* 执行代理方法
*
* @param proxy 代理对象
* @param method 需要执行的方法
* @param args 参数列表
* @return 方法执行结果
*/
abstract fun exec(proxy: Any, method: Method, args: Array<Any>): Any?
}

View File

@@ -0,0 +1,3 @@
package com.synebula.gaea.spring.autoconfig
enum class ProxyType { JDK, Cglib }

View File

@@ -0,0 +1,109 @@
package com.synebula.gaea.spring.autoconfig
import org.springframework.beans.BeansException
import org.springframework.beans.factory.BeanClassLoaderAware
import org.springframework.beans.factory.BeanFactory
import org.springframework.beans.factory.BeanFactoryAware
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition
import org.springframework.beans.factory.config.BeanDefinition
import org.springframework.beans.factory.support.BeanDefinitionRegistry
import org.springframework.context.EnvironmentAware
import org.springframework.context.ResourceLoaderAware
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar
import org.springframework.core.env.Environment
import org.springframework.core.io.ResourceLoader
import org.springframework.core.type.AnnotationMetadata
import org.springframework.core.type.classreading.MetadataReader
import org.springframework.core.type.classreading.MetadataReaderFactory
import org.springframework.core.type.filter.TypeFilter
import org.springframework.util.ClassUtils
import java.util.*
abstract class Register : ImportBeanDefinitionRegistrar, ResourceLoaderAware, BeanClassLoaderAware,
EnvironmentAware, BeanFactoryAware {
protected var _classLoader: ClassLoader? = null
protected var _environment: Environment? = null
protected var _resourceLoader: ResourceLoader? = null
protected var _beanFactory: BeanFactory? = null
override fun registerBeanDefinitions(metadata: AnnotationMetadata, registry: BeanDefinitionRegistry) {
val beanDefinitions = this.scan(metadata)
beanDefinitions.forEach { registry.registerBeanDefinition(it.key, it.value) }
}
abstract fun scan(metadata: AnnotationMetadata): Map<String, BeanDefinition>
/**
* 根据过滤器扫描直接包下bean
*
* @param packages 指定的扫描包
* @param filters 过滤器
* @return 扫描后的bean定义
*/
protected fun doScan(packages: Array<String>?, filters: Array<TypeFilter>): List<BeanDefinition> {
val scanner: ClassPathScanningCandidateComponentProvider =
object : ClassPathScanningCandidateComponentProvider() {
override fun isCandidateComponent(beanDefinition: AnnotatedBeanDefinition): Boolean {
try {
val metadata = beanDefinition.metadata
val target = ClassUtils.forName(metadata.className, _classLoader)
return !target.isAnnotation
} catch (ignored: Exception) {
}
return false
}
}
scanner.environment = _environment!!
scanner.resourceLoader = _resourceLoader!!
for (filter in filters) {
scanner.addIncludeFilter(filter)
}
val beanDefinitions: MutableList<BeanDefinition> = LinkedList()
for (basePackage in packages!!) {
beanDefinitions.addAll(scanner.findCandidateComponents(basePackage))
}
return beanDefinitions
}
/**
* 获取指定接口的类型过滤器
*
* @param interfaces 需要过滤的父接口类型
* @param onlyInterface 是否只获取接口类型
* @return 类型过滤器
*/
protected fun interfaceFilter(interfaces: Array<Class<*>>, onlyInterface: Boolean = false): TypeFilter {
return TypeFilter { metadataReader: MetadataReader, _: MetadataReaderFactory? ->
// 如果只获取接口类型且当前类型非接口 直接返回
if (onlyInterface && !metadataReader.annotationMetadata.isInterface)
return@TypeFilter false
var matched = false
val interfaceNames = metadataReader.classMetadata.interfaceNames
// 如果当前类型继承接口有任一需要过滤的接口则说明复合条件
for (interfaceName in interfaceNames) {
matched = interfaces.any { clazz -> clazz.name == interfaceName }
}
matched
}
}
override fun setResourceLoader(resourceLoader: ResourceLoader) {
this._resourceLoader = resourceLoader
}
override fun setBeanClassLoader(classLoader: ClassLoader) {
this._classLoader = classLoader
}
override fun setEnvironment(environment: Environment) {
this._environment = environment
}
@Throws(BeansException::class)
override fun setBeanFactory(beanFactory: BeanFactory) {
this._beanFactory = beanFactory
}
}

View File

@@ -6,22 +6,29 @@ import com.synebula.gaea.domain.model.IAggregateRoot
* 定义了提供增删改的仓储接口。
* 本接口泛型放置到方法上并需要显式提供聚合根的class对象
*/
interface IRepository {
interface IRepository<TAggregateRoot : IAggregateRoot<ID>, ID> {
/**
* 仓储的对象类
*/
var clazz: Class<TAggregateRoot>
/**
* 插入单个对象。
*
* @param obj 需要插入的对象。
* @return 返回原对象如果对象ID为自增则补充自增ID。
*/
fun <TAggregateRoot : IAggregateRoot<ID>, ID> add(obj: TAggregateRoot, clazz: Class<TAggregateRoot>)
fun add(obj: TAggregateRoot)
/**
* 插入多个个对象。
*
* @param obj 需要插入的对象。
* @param list 需要插入的对象。
* @return 返回原对象如果对象ID为自增则补充自增ID。
*/
fun <TAggregateRoot : IAggregateRoot<ID>, ID> add(obj: List<TAggregateRoot>, clazz: Class<TAggregateRoot>)
fun add(list: List<TAggregateRoot>)
/**
* 更新对象。
@@ -29,24 +36,30 @@ interface IRepository {
* @param obj 需要更新的对象。
* @return
*/
fun <TAggregateRoot : IAggregateRoot<ID>, ID> update(obj: TAggregateRoot, clazz: Class<TAggregateRoot>)
fun update(obj: TAggregateRoot)
/**
* 更新多个个对象。
*
* @param list 需要新的对象。
*/
fun update(list: List<TAggregateRoot>)
/**
* 通过id删除该条数据
*
* @param id id
* @param clazz 操作数据的类型
* @param id 对象ID。
* @return
*/
fun <TAggregateRoot : IAggregateRoot<ID>, ID> remove(id: ID, clazz: Class<TAggregateRoot>)
fun remove(id: ID)
/**
* 根据ID获取对象。
*
* @param id id
* @param clazz 操作数据的类型
* @return 聚合根
* @param id 对象ID。
* @return
*/
fun <TAggregateRoot : IAggregateRoot<ID>, ID> get(id: ID, clazz: Class<TAggregateRoot>): TAggregateRoot?
fun get(id: ID): TAggregateRoot?
/**
@@ -55,5 +68,7 @@ interface IRepository {
* @param params 查询条件。
* @return int
*/
fun <TAggregateRoot> count(params: Map<String, Any>?, clazz: Class<TAggregateRoot>): Int
fun <TAggregateRoot> count(params: Map<String, Any>?): Int
}

View File

@@ -1,61 +0,0 @@
package com.synebula.gaea.domain.repository
import com.synebula.gaea.domain.model.IAggregateRoot
/**
* 继承本接口表示对象为仓储类。
* 定义了提供增删改的仓储接口。
* 本接口泛型定义在类上方法中不需要显式提供聚合根的class对象class对象作为类的成员变量声明。
*
* @param TAggregateRoot 聚合根类型
* @author alex
*/
interface ISpecificRepository<TAggregateRoot : IAggregateRoot<ID>, ID> {
/**
* 仓储的对象类
*/
var clazz: Class<TAggregateRoot>?
/**
* 插入单个对象。
*
* @param obj 需要插入的对象。
* @return 返回原对象如果对象ID为自增则补充自增ID。
*/
fun add(obj: TAggregateRoot)
/**
* 更新对象。
*
* @param obj 需要更新的对象。
* @return
*/
fun update(obj: TAggregateRoot)
/**
* 通过id删除该条数据
*
* @param id 对象ID。
* @return
*/
fun remove(id: ID)
/**
* 根据ID获取对象。
*
* @param id 对象ID。
* @return
*/
fun get(id: ID): TAggregateRoot
/**
* 根据条件查询符合条件记录的数量
*
* @param params 查询条件。
* @return int
*/
fun <TAggregateRoot> count(params: Map<String, Any>?): Int
}

View File

@@ -0,0 +1,65 @@
package com.synebula.gaea.domain.repository
import com.synebula.gaea.domain.model.IAggregateRoot
/**
* 定义了提供增删改的仓储接口。
* 本接口泛型放置到方法上并需要显式提供聚合根的class对象
*/
interface IUniversalRepository {
/**
* 插入单个对象。
*
* @param root 需要插入的对象。
* @return 返回原对象如果对象ID为自增则补充自增ID。
*/
fun <TAggregateRoot : IAggregateRoot<ID>, ID> add(root: TAggregateRoot, clazz: Class<TAggregateRoot>)
/**
* 插入多个个对象。
*
* @param roots 需要插入的对象。
*/
fun <TAggregateRoot : IAggregateRoot<ID>, ID> add(roots: List<TAggregateRoot>, clazz: Class<TAggregateRoot>)
/**
* 更新对象。
*
* @param root 需要更新的对象。
* @return
*/
fun <TAggregateRoot : IAggregateRoot<ID>, ID> update(root: TAggregateRoot, clazz: Class<TAggregateRoot>)
/**
* 更新多个个对象。
*
* @param roots 需要更新的对象。
*/
fun <TAggregateRoot : IAggregateRoot<ID>, ID> update(roots: List<TAggregateRoot>, clazz: Class<TAggregateRoot>)
/**
* 通过id删除该条数据
*
* @param id id
* @param clazz 操作数据的类型
*/
fun <TAggregateRoot : IAggregateRoot<ID>, ID> remove(id: ID, clazz: Class<TAggregateRoot>)
/**
* 根据ID获取对象。
*
* @param id id
* @param clazz 操作数据的类型
* @return 聚合根
*/
fun <TAggregateRoot : IAggregateRoot<ID>, ID> get(id: ID, clazz: Class<TAggregateRoot>): TAggregateRoot?
/**
* 根据条件查询符合条件记录的数量
*
* @param params 查询条件。
* @return int
*/
fun <TAggregateRoot> count(params: Map<String, Any>?, clazz: Class<TAggregateRoot>): Int
}

View File

@@ -1,8 +1,6 @@
package com.synebula.gaea.domain.service
import com.synebula.gaea.data.message.DataMessage
import com.synebula.gaea.data.message.StatusMessage
import com.synebula.gaea.log.ILogger
/**
@@ -12,27 +10,39 @@ import com.synebula.gaea.log.ILogger
* @since 2016年9月18日 下午2:23:15
*/
interface IService<ID> {
/**
* 日志组件。
*/
var logger: ILogger
/**
* 增加对象
*
* @param command 增加对象命令
*/
fun add(command: ICommand): DataMessage<ID>
/**
* 增加对象
*
* @param commands 增加对象命令列表
*/
fun add(commands: List<ICommand>)
/**
* 更新对象
*
* @param id 对象ID
* @param command 更新对象命令
*/
fun update(id: ID, command: ICommand)
/**
* 批量更新对象
*
* @param commands 更新对象命令列表
*/
fun update(commands: List<ICommand>)
/**
* 增加对象
* @param id 对象ID
*/
fun remove(id: ID)
/**
* 添加一个删除对象前执行监听器。
* @param key 监听器标志。
* @param func 监听方法。
*/
fun addBeforeRemoveListener(key: String, func: (id: ID) -> StatusMessage)
/**
* 移除一个删除对象前执行监听器。
* @param key 监听器标志。
*/
fun removeBeforeRemoveListener(key: String)
}

View File

@@ -1,7 +1,6 @@
package com.synebula.gaea.domain.service
import com.synebula.gaea.data.message.DataMessage
import com.synebula.gaea.data.message.StatusMessage
import com.synebula.gaea.domain.model.IAggregateRoot
import com.synebula.gaea.log.ILogger
@@ -18,22 +17,38 @@ interface ISimpleService<TAggregateRoot : IAggregateRoot<ID>, ID> {
*/
var logger: ILogger
/**
* 增加对象
*
* @param root 增加对象命令
*/
fun add(root: TAggregateRoot): DataMessage<ID>
/**
* 增加对象
*
* @param roots 增加对象命令列表
*/
fun add(roots: List<TAggregateRoot>)
/**
* 更新对象
*
* @param id 对象ID
* @param root 更新对象命令
*/
fun update(id: ID, root: TAggregateRoot)
/**
* 批量更新对象
*
* @param roots 更新对象命令列表
*/
fun update(roots: List<TAggregateRoot>)
/**
* 增加对象
* @param id 对象ID
*/
fun remove(id: ID)
/**
* 添加一个删除对象前执行监听器。
* @param key 监听器标志。
* @param func 监听方法。
*/
fun addBeforeRemoveListener(key: String, func: (id: ID) -> StatusMessage)
/**
* 移除一个删除对象前执行监听器。
* @param key 监听器标志。
*/
fun removeBeforeRemoveListener(key: String)
}

View File

@@ -1,78 +1,80 @@
package com.synebula.gaea.domain.service
import com.synebula.gaea.data.message.DataMessage
import com.synebula.gaea.data.message.StatusMessage
import com.synebula.gaea.data.serialization.IObjectMapper
import com.synebula.gaea.domain.model.IAggregateRoot
import com.synebula.gaea.domain.repository.IRepository
import com.synebula.gaea.log.ILogger
/**
* 依赖了IRepository仓储借口的服务实现类 Service
* 该类依赖仓储接口 @see IRepository, 需要显式提供聚合根的class对象
* 依赖了IRepository仓储借口的服务实现类 GenericsService
* 该类依赖仓储接口 @see IGenericsRepository, 需要显式提供聚合根的class对象
*
* @param repository 仓储对象
* @param clazz 聚合根类对象
* @param deserializer 对象转换组件
* @param logger 日志组件
* @param repo 仓储对象
* @param mapper 对象转换组件
* @author alex
* @version 0.1
* @since 2020-05-17
*/
open class Service<TAggregateRoot : IAggregateRoot<ID>, ID>(
protected open var clazz: Class<TAggregateRoot>,
protected open var repository: IRepository,
protected open var deserializer: IObjectMapper,
override var logger: ILogger,
open class Service<TRoot : IAggregateRoot<ID>, ID>(
protected open var clazz: Class<TRoot>,
protected open var repo: IRepository<TRoot, ID>,
protected open var mapper: IObjectMapper,
) : IService<ID> {
/**
* 删除对象前执行监听器。
*/
protected val beforeRemoveListeners = mutableMapOf<String, (id: ID) -> StatusMessage>()
/**
* 添加一个删除对象前执行监听器。
* @param key 监听器标志。
* @param func 监听方法。
* 增加对象
*
* @param command 增加对象命令
*/
override fun addBeforeRemoveListener(key: String, func: (id: ID) -> StatusMessage) {
this.beforeRemoveListeners[key] = func
}
/**
* 移除一个删除对象前执行监听器。
* @param key 监听器标志。
*/
override fun removeBeforeRemoveListener(key: String) {
this.beforeRemoveListeners.remove(key)
}
override fun add(command: ICommand): DataMessage<ID> {
val msg = DataMessage<ID>()
val root = this.deserialize(command)
this.repository.add(root, this.clazz)
val root = this.map(command)
this.repo.add(root)
msg.data = root.id
return msg
}
override fun update(id: ID, command: ICommand) {
val root = this.deserialize(command)
root.id = id
this.repository.update(root, this.clazz)
/**
* 增加对象
*
* @param commands 增加对象命令列表
*/
override fun add(commands: List<ICommand>) {
val roots = commands.map { this.map(it) }
this.repo.add(roots)
}
/**
* 更新对象
*
* @param id 对象ID
* @param command 更新对象命令
*/
override fun update(id: ID, command: ICommand) {
val root = this.map(command)
root.id = id
this.repo.update(root)
}
/**
* 批量更新对象
*
* @param commands 更新对象命令列表
*/
override fun update(commands: List<ICommand>) {
val roots = commands.map { this.map(it) }
this.repo.update(roots)
}
/**
* 增加对象
* @param id 对象ID
*/
override fun remove(id: ID) {
val functions = this.beforeRemoveListeners.values
var msg: StatusMessage
for (func in functions) {
msg = func(id)
if (!msg.success()) {
throw IllegalStateException(msg.message)
}
}
this.repository.remove(id, this.clazz)
this.repo.remove(id)
}
/**
@@ -81,9 +83,9 @@ open class Service<TAggregateRoot : IAggregateRoot<ID>, ID>(
* @param command 需要转换的命令
* @return 聚合根
*/
protected open fun deserialize(command: ICommand): TAggregateRoot {
protected open fun map(command: ICommand): TRoot {
try {
return deserializer.deserialize(command, this.clazz)
return mapper.deserialize(command, this.clazz)
} catch (ex: Exception) {
throw RuntimeException("command not match aggregate root", ex)
}

View File

@@ -0,0 +1,16 @@
package com.synebula.gaea.domain.service
import com.synebula.gaea.domain.model.IAggregateRoot
import com.synebula.gaea.domain.repository.IRepository
import kotlin.reflect.KClass
/**
* 声明服务的依赖项,若服务没有实现类则可以根据依赖项自动组装服务。
*
* @param clazz 依赖的聚合根类型
* @param repo 依赖的[IRepository]类型
*/
annotation class ServiceDependency(
val clazz: KClass<out IAggregateRoot<*>>,
val repo: KClass<out IRepository<*, *>>,
)

View File

@@ -1,15 +1,14 @@
package com.synebula.gaea.domain.service
import com.synebula.gaea.data.message.DataMessage
import com.synebula.gaea.data.message.StatusMessage
import com.synebula.gaea.domain.model.IAggregateRoot
import com.synebula.gaea.domain.repository.IRepository
import com.synebula.gaea.log.ILogger
/**
* 依赖了IRepository仓储借口的服务实现类 Service
* 该类依赖仓储接口 @see IRepository, 需要显式提供聚合根的class对象
* 依赖了IRepository仓储借口的服务实现类 GenericsService
* 该类依赖仓储接口 @see IGenericsRepository, 需要显式提供聚合根的class对象
*
* @param repository 仓储对象
* @param clazz 聚合根类对象
@@ -20,53 +19,41 @@ import com.synebula.gaea.log.ILogger
*/
open class SimpleService<TAggregateRoot : IAggregateRoot<ID>, ID>(
protected open var clazz: Class<TAggregateRoot>,
protected open var repository: IRepository,
protected open var repository: IRepository<TAggregateRoot, ID>,
override var logger: ILogger,
) : ISimpleService<TAggregateRoot, ID> {
/**
* 删除对象前执行监听器。
*/
protected val beforeRemoveListeners = mutableMapOf<String, (id: ID) -> StatusMessage>()
/**
* 添加一个删除对象前执行监听器。
* @param key 监听器标志。
* @param func 监听方法。
*/
override fun addBeforeRemoveListener(key: String, func: (id: ID) -> StatusMessage) {
this.beforeRemoveListeners[key] = func
}
/**
* 移除一个删除对象前执行监听器。
* @param key 监听器标志。
*/
override fun removeBeforeRemoveListener(key: String) {
this.beforeRemoveListeners.remove(key)
}
override fun add(root: TAggregateRoot): DataMessage<ID> {
val msg = DataMessage<ID>()
this.repository.add(root, this.clazz)
this.repository.add(root)
msg.data = root.id
return msg
}
override fun update(id: ID, root: TAggregateRoot) {
root.id = id
this.repository.update(root, this.clazz)
this.repository.update(root)
}
override fun remove(id: ID) {
val functions = this.beforeRemoveListeners.values
var msg: StatusMessage
for (func in functions) {
msg = func(id)
if (!msg.success()) {
throw IllegalStateException(msg.message)
this.repository.remove(id)
}
/**
* 增加对象
*
* @param roots 增加对象命令列表
*/
override fun add(roots: List<TAggregateRoot>) {
this.repository.add(roots)
}
this.repository.remove(id, this.clazz)
/**
* 批量更新对象
*
* @param roots 更新对象命令列表
*/
override fun update(roots: List<TAggregateRoot>) {
this.repository.update(roots)
}
}

View File

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

View File

@@ -1,18 +1,18 @@
package com.synebula.gaea.query
/**
* 查询基接口
* 本接口泛型定义在类上方法中不需要显式提供聚合根的class对象class对象作为类的成员变量声明
* 查询基接口, 其中方法都指定了查询的视图类型
*
* @author alex
*/
interface ISpecificQuery<TView> {
interface IUniversalQuery {
/**
* 根据Key获取对象
*
* @param id 对象Key
* @return 视图结果
*/
fun <TView, ID> get(id: ID): TView?
fun <TView, ID> get(id: ID, clazz: Class<TView>): TView?
/**
* 根据实体类条件查询所有符合条件记录
@@ -20,7 +20,7 @@ interface ISpecificQuery<TView> {
* @param params 查询条件
* @return 视图列表
*/
fun <TView> list(params: Map<String, Any>?): List<TView>
fun <TView> list(params: Map<String, Any>?, clazz: Class<TView>): List<TView>
/**
* 根据条件查询符合条件记录的数量
@@ -28,7 +28,7 @@ interface ISpecificQuery<TView> {
* @param params 查询条件
* @return 数量
*/
fun <TView> count(params: Map<String, Any>?): Int
fun <TView> count(params: Map<String, Any>?, clazz: Class<TView>): Int
/**
* 根据实体类条件查询所有符合条件记录分页查询
@@ -36,7 +36,7 @@ interface ISpecificQuery<TView> {
* @param params 分页条件
* @return 分页数据
*/
fun <TView> paging(params: Params): Page<TView>
fun <TView> paging(params: Params, clazz: Class<TView>): Page<TView>
/**
* 查询条件范围内数据
@@ -45,5 +45,5 @@ interface ISpecificQuery<TView> {
*
* @return 视图列表
*/
fun <TView> range(field: String, params: List<Any>): List<TView>
fun <TView> range(field: String, params: List<Any>, clazz: Class<TView>): List<TView>
}

View File

@@ -1,4 +1,4 @@
package com.synebula.gaea.query.type
package com.synebula.gaea.query
enum class Operator {
/**

View File

@@ -1,4 +1,4 @@
package com.synebula.gaea.query.type
package com.synebula.gaea.query
/**
* class OrderType

View File

@@ -1,7 +1,5 @@
package com.synebula.gaea.query
import com.synebula.gaea.query.type.Order
/**
* class 分页参数信息
*

View File

@@ -1,3 +1,3 @@
package com.synebula.gaea.query.annotation
package com.synebula.gaea.query
annotation class Table(val name: String = "")

View File

@@ -1,6 +1,4 @@
package com.synebula.gaea.query.annotation
import com.synebula.gaea.query.type.Operator
package com.synebula.gaea.query
/**
* 字段注解规定字段的查询方式

View File

@@ -1,7 +1,5 @@
package com.synebula.gaea.reflect
import com.synebula.gaea.bus.SubscriberRegistry
object Types {
/**
* 获取类的所有父类型。
@@ -9,15 +7,15 @@ object Types {
fun supertypes(clazz: Class<*>): Set<Class<*>> {
val supertypes = mutableSetOf<Class<*>>()
supertypes.add(clazz)
if (clazz.superclass != null)
supertypes.addAll(SubscriberRegistry.flattenHierarchy(clazz.superclass))
if (clazz.interfaces.isNotEmpty()) {
supertypes.addAll(clazz.interfaces.map { SubscriberRegistry.flattenHierarchy(it) }.reduce { r, c ->
supertypes.addAll(clazz.interfaces.map { supertypes(it) }.reduce { r, c ->
val all = r.toMutableSet()
all.addAll(c)
all
})
}
if (clazz.superclass != null)
supertypes.addAll(supertypes(clazz.superclass))
return supertypes
}
}