添加文件

This commit is contained in:
2024-06-29 20:00:05 +08:00
parent 54b7cedac6
commit 48a24b99e1
53 changed files with 353 additions and 550 deletions

View File

@@ -1,3 +1,5 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
buildscript {
ext {
jvm_version = '21'
@@ -7,6 +9,7 @@ buildscript {
repositories {
mavenLocal()
maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }
maven { url 'https://maven.aliyun.com/repository/central' }
maven { url 'https://maven.aliyun.com/repository/public' }
mavenCentral()
@@ -52,10 +55,14 @@ subprojects {
sourceCompatibility = "$jvm_version"
targetCompatibility = "$jvm_version"
compileKotlin {
kotlinOptions.jvmTarget = "$jvm_version"
compilerOptions {
jvmTarget = JvmTarget.valueOf("JVM_$jvm_version")
}
}
compileTestKotlin {
kotlinOptions.jvmTarget = "$jvm_version"
compilerOptions {
jvmTarget = JvmTarget.valueOf("JVM_$jvm_version")
}
}
publishing {

View File

@@ -24,7 +24,7 @@ open class Cache<K, V>(expire: Int) : ICache<K, V> {
}
override fun add(key: K, value: V) {
this.guavaCache.put(key, value)
this.guavaCache.put(key!!, value!!)
}
/**

View File

@@ -3,10 +3,10 @@ package com.synebula.gaea.app.controller
import com.synebula.gaea.app.controller.cmd.ICommandApp
import com.synebula.gaea.app.controller.query.IQueryApp
import com.synebula.gaea.data.message.HttpMessageFactory
import com.synebula.gaea.db.query.IQuery
import com.synebula.gaea.domain.service.ICommand
import com.synebula.gaea.domain.service.IService
import com.synebula.gaea.log.ILogger
import com.synebula.gaea.query.IQuery
import org.springframework.beans.factory.annotation.Autowired
/**
@@ -17,7 +17,7 @@ import org.springframework.beans.factory.annotation.Autowired
* @param query 业务查询服务
* @param logger 日志组件
*/
open class Application<TCommand : ICommand, TView, ID>(
open class DomainApplication<TCommand : ICommand, TView, ID>(
override var name: String,
override var service: IService<ID>,
override var query: IQuery<TView, ID>,

View File

@@ -3,10 +3,10 @@ package com.synebula.gaea.app.controller
import com.synebula.gaea.app.controller.cmd.ISimpleCommandApp
import com.synebula.gaea.app.controller.query.IQueryApp
import com.synebula.gaea.data.message.HttpMessageFactory
import com.synebula.gaea.db.query.IQuery
import com.synebula.gaea.domain.model.IAggregateRoot
import com.synebula.gaea.domain.service.ISimpleService
import com.synebula.gaea.log.ILogger
import com.synebula.gaea.query.IQuery
import com.synebula.gaea.record.service.IService
import org.springframework.beans.factory.annotation.Autowired
/**
@@ -17,14 +17,13 @@ import org.springframework.beans.factory.annotation.Autowired
* @param query 业务查询服务
* @param logger 日志组件
*/
open class SimpleApplication<TRoot : IAggregateRoot<ID>, ID>(
open class RecordApplication<TRoot : IAggregateRoot<ID>, ID>(
override var name: String,
override var service: ISimpleService<TRoot, ID>,
override var service: IService<TRoot, ID>,
override var query: IQuery<TRoot, ID>,
override var logger: ILogger,
) : ISimpleCommandApp<TRoot, ID>, IQueryApp<TRoot, ID> {
@Autowired
override lateinit var httpMessageFactory: HttpMessageFactory
}

View File

@@ -4,7 +4,7 @@ import com.synebula.gaea.app.controller.IApplication
import com.synebula.gaea.data.message.HttpMessage
import com.synebula.gaea.data.message.Status
import com.synebula.gaea.domain.model.IAggregateRoot
import com.synebula.gaea.domain.service.ISimpleService
import com.synebula.gaea.record.service.IService
import com.synebula.gaea.spring.aop.annotation.Method
import org.springframework.web.bind.annotation.*
@@ -16,12 +16,13 @@ import org.springframework.web.bind.annotation.*
* @since 2020-05-15
*/
interface ISimpleCommandApp<TRoot : IAggregateRoot<ID>, ID> : IApplication {
var service: ISimpleService<TRoot, ID>
var service: IService<TRoot, ID>
@PostMapping
@Method("添加")
fun add(@RequestBody entity: TRoot): HttpMessage {
return this.httpMessageFactory.create(service.add(entity))
val id = service.add(entity)
return this.httpMessageFactory.create(id!!)
}
@PutMapping("/{id:.+}")

View File

@@ -2,7 +2,7 @@ package com.synebula.gaea.app.controller.cmd
import com.synebula.gaea.data.message.HttpMessageFactory
import com.synebula.gaea.domain.model.IAggregateRoot
import com.synebula.gaea.domain.service.ISimpleService
import com.synebula.gaea.record.service.IService
import com.synebula.gaea.log.ILogger
import org.springframework.beans.factory.annotation.Autowired
@@ -15,7 +15,7 @@ import org.springframework.beans.factory.annotation.Autowired
*/
open class SimpleCommandApp<TRoot : IAggregateRoot<ID>, ID>(
override var name: String,
override var service: ISimpleService<TRoot, ID>,
override var service: IService<TRoot, ID>,
override var logger: ILogger,
) : ISimpleCommandApp<TRoot, ID> {
@Autowired

View File

@@ -2,8 +2,8 @@ package com.synebula.gaea.app.controller.query
import com.synebula.gaea.app.controller.IApplication
import com.synebula.gaea.data.message.HttpMessage
import com.synebula.gaea.query.IQuery
import com.synebula.gaea.query.Params
import com.synebula.gaea.db.query.IQuery
import com.synebula.gaea.db.query.Params
import com.synebula.gaea.spring.aop.annotation.Method
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable

View File

@@ -1,8 +1,8 @@
package com.synebula.gaea.app.controller.query
import com.synebula.gaea.data.message.HttpMessageFactory
import com.synebula.gaea.db.query.IQuery
import com.synebula.gaea.log.ILogger
import com.synebula.gaea.query.IQuery
import org.springframework.beans.factory.annotation.Autowired
/**

View File

@@ -1,8 +1,8 @@
package com.synebula.gaea.jpa
import com.synebula.gaea.query.IQuery
import com.synebula.gaea.query.Page
import com.synebula.gaea.query.Params
import com.synebula.gaea.db.query.IQuery
import com.synebula.gaea.db.query.Page
import com.synebula.gaea.db.query.Params
import jakarta.persistence.EntityManager
import org.springframework.data.jpa.repository.support.SimpleJpaRepository
@@ -14,7 +14,7 @@ class JpaQuery<TView, ID>(override var clazz: Class<TView>, entityManager: Entit
}
override operator fun get(id: ID): TView? {
val view = this.repo.findById(id)
val view = this.repo.findById(id!!)
return if (view.isPresent) view.get() else null
}

View File

@@ -1,8 +1,8 @@
package com.synebula.gaea.jpa
import com.synebula.gaea.data.date.DateTime
import com.synebula.gaea.query.Operator
import com.synebula.gaea.query.Where
import com.synebula.gaea.db.query.Operator
import com.synebula.gaea.db.query.Where
import jakarta.persistence.criteria.*
import org.springframework.data.jpa.domain.Specification
import java.lang.reflect.Field

View File

@@ -5,13 +5,13 @@ import org.springframework.beans.factory.FactoryBean
import org.springframework.cglib.proxy.Enhancer
import org.springframework.data.repository.Repository
class JpaRepositoryFactory(
class JpaDbContextFactory(
private val beanFactory: BeanFactory,
private val interfaceType: Class<*>,
private val implBeanNames: List<String>
) : FactoryBean<Any> {
override fun getObject(): Any {
val handler: JpaRepositoryProxy<*, *, *> = JpaRepositoryProxy<Repository<Any, Any>, Any, Any>(
val handler: JpaDbContextProxy<*, *, *> = JpaDbContextProxy<Repository<Any, Any>, Any, Any>(
beanFactory,
interfaceType, implBeanNames
)

View File

@@ -26,7 +26,7 @@ import java.lang.reflect.Method
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type
class JpaRepositoryProxy<T : Repository<S, ID>?, S, ID>(
class JpaDbContextProxy<T : Repository<S, ID>?, S, ID>(
beanFactory: BeanFactory,
interfaceType: Class<*>,
implementBeanNames: List<String>?

View File

@@ -8,5 +8,5 @@ import kotlin.reflect.KClass
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
@Inherited
@Import(JpaRepositoryRegister::class)
annotation class JpaRepositoryProxyScan(val basePackages: Array<String> = [], val scanInterfaces: Array<KClass<*>> = [])
@Import(JpaDbContextRegister::class)
annotation class JpaDbContextProxyScan(val basePackages: Array<String> = [], val scanInterfaces: Array<KClass<*>> = [])

View File

@@ -24,17 +24,20 @@ import org.springframework.util.ClassUtils
import java.util.*
import java.util.stream.Collectors
class JpaRepositoryRegister : ImportBeanDefinitionRegistrar, ResourceLoaderAware, BeanClassLoaderAware,
class JpaDbContextRegister : ImportBeanDefinitionRegistrar, ResourceLoaderAware, BeanClassLoaderAware,
EnvironmentAware,
BeanFactoryAware {
private lateinit var environment: Environment
private lateinit var resourceLoader: ResourceLoader
private var classLoader: ClassLoader? = null
private var beanFactory: BeanFactory? = null
override fun registerBeanDefinitions(metadata: AnnotationMetadata, registry: BeanDefinitionRegistry) {
val attributes = AnnotationAttributes(
metadata.getAnnotationAttributes(
JpaRepositoryProxyScan::class.java.name
JpaDbContextProxyScan::class.java.name
) ?: mapOf()
)
val basePackages = attributes.getStringArray("basePackages")
@@ -55,7 +58,7 @@ class JpaRepositoryRegister : ImportBeanDefinitionRegistrar, ResourceLoaderAware
val implClazzDefinitions = scan(basePackages, arrayOf(beanClazzTypeFilter))
for (definition in implClazzDefinitions) {
definition.isAutowireCandidate = false
registry.registerBeanDefinition(Objects.requireNonNull(definition.beanClassName), definition)
registry.registerBeanDefinition(Objects.requireNonNull(definition.beanClassName!!), definition)
}
// 构建bean定义
// 1 bean参数
@@ -66,7 +69,7 @@ class JpaRepositoryRegister : ImportBeanDefinitionRegistrar, ResourceLoaderAware
builder.addConstructorArgValue(beanClazz)
builder.addConstructorArgValue(implBeanNames)
val definition = builder.rawBeanDefinition as GenericBeanDefinition
definition.beanClass = JpaRepositoryFactory::class.java
definition.beanClass = JpaDbContextFactory::class.java
definition.autowireMode = GenericBeanDefinition.AUTOWIRE_BY_TYPE
registry.registerBeanDefinition(beanClazz.name, definition)
}

View File

@@ -5,7 +5,7 @@ import com.synebula.gaea.jpa.proxy.method.resolver.AbstractMethodResolver
import com.synebula.gaea.jpa.proxy.method.resolver.DefaultMethodResolver
import com.synebula.gaea.jpa.proxy.method.resolver.FindMethodResolver
import com.synebula.gaea.jpa.proxy.method.resolver.PageMethodResolver
import com.synebula.gaea.query.Params
import com.synebula.gaea.db.query.Params
import org.springframework.data.domain.Pageable
import org.springframework.data.jpa.domain.Specification
import java.lang.reflect.InvocationTargetException

View File

@@ -1,8 +1,8 @@
package com.synebula.gaea.jpa.proxy.method.resolver
import com.synebula.gaea.jpa.toSpecification
import com.synebula.gaea.query.Order
import com.synebula.gaea.query.Params
import com.synebula.gaea.db.query.Order
import com.synebula.gaea.db.query.Params
import jakarta.persistence.EmbeddedId
import jakarta.persistence.Id
import org.springframework.data.domain.Page
@@ -10,7 +10,7 @@ import org.springframework.data.domain.PageRequest
import org.springframework.data.domain.Pageable
import org.springframework.data.domain.Sort
import java.util.*
import com.synebula.gaea.query.Page as QueryPage
import com.synebula.gaea.db.query.Page as QueryPage
/**
* 分页方法参数映射

View File

@@ -1,9 +1,9 @@
package com.synebula.gaea.mongodb
import com.synebula.gaea.data.date.DateTime
import com.synebula.gaea.query.Operator
import com.synebula.gaea.query.Order
import com.synebula.gaea.query.Where
import com.synebula.gaea.db.query.Operator
import com.synebula.gaea.db.query.Order
import com.synebula.gaea.db.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

@@ -4,11 +4,11 @@ import com.synebula.gaea.spring.autoconfig.Factory
import com.synebula.gaea.spring.autoconfig.Proxy
import org.springframework.beans.factory.BeanFactory
class MongodbRepositoryFactory(
class MongoDbContextFactory(
supertype: Class<*>,
var beanFactory: BeanFactory,
) : Factory(supertype) {
override fun createProxy(): Proxy {
return MongodbRepositoryProxy(supertype, this.beanFactory)
return MongoDbContextProxy(supertype, this.beanFactory)
}
}

View File

@@ -0,0 +1,69 @@
package com.synebula.gaea.mongodb.autoconfig
import com.synebula.gaea.db.context.IDbContext
import com.synebula.gaea.domain.repository.IRepository
import com.synebula.gaea.mongodb.db.query.MongodbQuery
import com.synebula.gaea.mongodb.repository.MongodbRepository
import com.synebula.gaea.db.query.IQuery
import com.synebula.gaea.reflect.getGenericInterface
import com.synebula.gaea.spring.autoconfig.Proxy
import org.springframework.beans.factory.BeanFactory
import org.springframework.data.mongodb.core.MongoTemplate
import java.lang.reflect.Method
class MongoDbContextProxy(
private var supertype: Class<*>, private var beanFactory: BeanFactory
) : Proxy() {
/**
* 实际的执行类
*/
private var context: Any?
init {
if (this.supertype.interfaces.any { it == IDbContext::class.java }) {
this.context = beanFactory.getBean(IDbContext::class.java)
if (context == null) {
val constructor = IDbContext::class.java.getConstructor(Class::class.java, MongoTemplate::class.java)
this.context = constructor.newInstance(this.beanFactory.getBean(MongoTemplate::class.java))
}
} else {
// 判断接口类型
val clazz: Class<*> // 代理服务类型
val interfaceClazz: Class<*> // 代理服务接口
if (this.supertype.interfaces.any { it == IQuery::class.java }) {
clazz = MongodbQuery::class.java
interfaceClazz = IQuery::class.java
} else {
clazz = MongodbRepository::class.java
interfaceClazz = IRepository::class.java
}
val constructor = clazz.getConstructor(Class::class.java, MongoTemplate::class.java)
this.context = constructor.newInstance(
this.supertype.getGenericInterface(interfaceClazz)!!.actualTypeArguments[0],
this.beanFactory.getBean(MongoTemplate::class.java)
)
}
}
/**
* 执行代理方法
*
* @param proxy 代理对象
* @param method 需要执行的方法
* @param args 参数列表
* @return 方法执行结果
*/
override fun exec(proxy: Any, method: Method, args: Array<Any>): Any? {
try {
val proxyMethod: Method = this.context!!.javaClass.getMethod(method.name, *method.parameterTypes)
return proxyMethod.invoke(this.context, *args)
} catch (ex: NoSuchMethodException) {
throw NoSuchMethodException("method [${method.toGenericString()}] not implements in class [${this.context!!.javaClass}], you must implements interface [${this.supertype.name}] ")
}
}
}

View File

@@ -1,7 +1,8 @@
package com.synebula.gaea.mongodb.autoconfig
import com.synebula.gaea.db.context.IDbContext
import com.synebula.gaea.db.query.IQuery
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
@@ -9,20 +10,20 @@ import org.springframework.beans.factory.support.GenericBeanDefinition
import org.springframework.core.annotation.AnnotationAttributes
import org.springframework.core.type.AnnotationMetadata
class MongodbRepositoryRegister : Register() {
class MongoDbContextRegister : Register() {
override fun scan(metadata: AnnotationMetadata): Map<String, BeanDefinition> {
val result = mutableMapOf<String, BeanDefinition>()
// 获取注解参数信息:basePackages
val attributes = AnnotationAttributes(
metadata.getAnnotationAttributes(
MongodbRepositoryScan::class.java.name
MongoDbRepositoryScan::class.java.name
) ?: mapOf()
)
val basePackages = attributes.getStringArray("basePackages")
val beanDefinitions = this.doScan(
basePackages,
arrayOf(this.interfaceFilter(arrayOf(IRepository::class.java, IQuery::class.java)))
arrayOf(this.interfaceFilter(arrayOf(IDbContext::class.java, IQuery::class.java, IRepository::class.java)))
)
beanDefinitions.forEach { beanDefinition ->
// 获取实际的bean类型
@@ -44,7 +45,7 @@ class MongodbRepositoryRegister : Register() {
builder.addConstructorArgValue(beanClazz)
builder.addConstructorArgValue(this._beanFactory)
val definition = builder.rawBeanDefinition as GenericBeanDefinition
definition.beanClass = MongodbRepositoryFactory::class.java
definition.beanClass = MongoDbContextFactory::class.java
definition.autowireMode = GenericBeanDefinition.AUTOWIRE_BY_TYPE
result[beanClazz.name] = definition
}
@@ -59,7 +60,7 @@ class MongodbRepositoryRegister : Register() {
builder.addConstructorArgValue(this._beanFactory)
builder.addConstructorArgValue(emptyArray<String>())
val definition = builder.rawBeanDefinition as GenericBeanDefinition
definition.beanClass = MongodbRepositoryFactory::class.java
definition.beanClass = MongoDbContextFactory::class.java
definition.autowireMode = GenericBeanDefinition.AUTOWIRE_BY_TYPE
result[IRepository::class.java.name] = definition
}

View File

@@ -8,5 +8,5 @@ import java.lang.annotation.Inherited
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
@Inherited
@Import(MongodbRepositoryRegister::class)
annotation class MongodbRepositoryScan(val basePackages: Array<String> = [])
@Import(MongoDbContextRegister::class)
annotation class MongoDbRepositoryScan(val basePackages: Array<String> = [])

View File

@@ -1,55 +0,0 @@
package com.synebula.gaea.mongodb.autoconfig
import com.synebula.gaea.domain.repository.IRepository
import com.synebula.gaea.mongodb.query.MongodbQuery
import com.synebula.gaea.mongodb.repository.MongodbRepository
import com.synebula.gaea.query.IQuery
import com.synebula.gaea.reflect.getGenericInterface
import com.synebula.gaea.spring.autoconfig.Proxy
import org.springframework.beans.factory.BeanFactory
import org.springframework.data.mongodb.core.MongoTemplate
import java.lang.reflect.Method
class MongodbRepositoryProxy(
private var supertype: Class<*>, private var beanFactory: BeanFactory
) : Proxy() {
private var mongodbRepo: Any
init {
// 判断接口类型
val clazz: Class<*> // 代理服务类型
val interfaceClazz: Class<*> // 代理服务接口
if (this.supertype.interfaces.any { it == IRepository::class.java }) {
clazz = MongodbRepository::class.java
interfaceClazz = IRepository::class.java
} else {
clazz = MongodbQuery::class.java
interfaceClazz = IQuery::class.java
}
val constructor = clazz.getConstructor(Class::class.java, MongoTemplate::class.java)
this.mongodbRepo = constructor.newInstance(
this.supertype.getGenericInterface(interfaceClazz)!!.actualTypeArguments[0],
this.beanFactory.getBean(MongoTemplate::class.java)
)
}
/**
* 执行代理方法
*
* @param proxy 代理对象
* @param method 需要执行的方法
* @param args 参数列表
* @return 方法执行结果
*/
override fun exec(proxy: Any, method: Method, args: Array<Any>): Any? {
try {
val proxyMethod: Method = this.mongodbRepo.javaClass.getMethod(method.name, *method.parameterTypes)
return proxyMethod.invoke(this.mongodbRepo, *args)
} catch (ex: NoSuchMethodException) {
throw NoSuchMethodException("method [${method.toGenericString()}] not implements in class [${this.mongodbRepo.javaClass}], you must implements interface [${this.supertype.name}] ")
}
}
}

View File

@@ -0,0 +1,50 @@
package com.synebula.gaea.mongodb.db.context
import com.synebula.gaea.db.IEntity
import com.synebula.gaea.db.context.IDbContext
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
class MongodbContext(
protected var template: MongoTemplate
) : IDbContext {
override fun <TEntity : IEntity<ID>, ID> add(entity: TEntity, clazz: Class<TEntity>) {
this.template.save(entity)
}
override fun <TEntity : IEntity<ID>, ID> add(entities: List<TEntity>, clazz: Class<TEntity>) {
this.template.insert(entities, clazz)
}
override fun <TEntity : IEntity<ID>, ID> remove(id: ID, clazz: Class<TEntity>) {
this.template.remove(whereId(id), clazz)
}
override fun <TEntity : IEntity<ID>, ID> get(id: ID, clazz: Class<TEntity>): TEntity? {
return this.template.findOne(whereId(id), clazz)
}
override fun <TEntity : IEntity<ID>, ID> update(entity: TEntity, clazz: Class<TEntity>) {
this.template.save(entity)
}
override fun <TEntity : IEntity<ID>, ID> update(entities: List<TEntity>, clazz: Class<TEntity>) {
this.template.save(entities)
}
override fun <TEntity : IEntity<ID>, ID> count(params: Map<String, String>?, clazz: Class<TEntity>): Int {
val query = Query()
return this.template.count(query.where(params, clazz), clazz).toInt()
}
override val isCommitted=true
override fun commit() {
}
override fun rollback() {
}
}

View File

@@ -1,24 +1,20 @@
package com.synebula.gaea.mongodb.query
package com.synebula.gaea.mongodb.db.query
import com.synebula.gaea.ext.firstCharLowerCase
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 com.synebula.gaea.db.query.IQuery
import com.synebula.gaea.db.query.Page
import com.synebula.gaea.db.query.Params
import com.synebula.gaea.db.query.Table
import com.synebula.gaea.reflect.fieldNames
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) :
IQuery<TView, ID> {

View File

@@ -1,23 +0,0 @@
package com.synebula.gaea.mongodb.query
import com.synebula.gaea.query.IQuery
import com.synebula.gaea.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

@@ -1,88 +0,0 @@
package com.synebula.gaea.mongodb.query
import com.synebula.gaea.ext.firstCharLowerCase
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.Table
import com.synebula.gaea.reflect.fieldNames
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 MongodbUniversalQuery(var template: MongoTemplate) : IUniversalQuery {
/**
* 使用View解析是collection时是否校验存在默认不校验
*/
var validViewCollection = false
override fun <TView, ID> get(id: ID, clazz: Class<TView>): TView? {
return this.template.findOne(whereId(id), clazz, this.collection(clazz))
}
override fun <TView> list(params: Map<String, String>?, clazz: Class<TView>): List<TView> {
val fields = this.fields(clazz)
val query = Query()
query.where(params, clazz)
query.select(fields)
return this.find(query, clazz)
}
override fun <TView> count(params: Map<String, String>?, clazz: Class<TView>): Int {
val query = Query()
return this.template.count(query.where(params, clazz), this.collection(clazz)).toInt()
}
override fun <TView> paging(params: Params, clazz: Class<TView>): Page<TView> {
val query = Query()
val fields = this.fields(clazz)
val result = Page<TView>(params.page, params.size)
result.total = this.count(params.parameters, clazz)
//如果总数和索引相同,说明该页没有数据,直接跳到上一页
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 <TView> range(field: String, params: List<Any>, clazz: Class<TView>): List<TView> {
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> {
return clazz.fieldNames().toTypedArray()
}
/**
* 获取collection
*/
fun <TView> collection(clazz: Class<TView>): String {
val table = clazz.getDeclaredAnnotation(Table::class.java)
return if (table != null) table.name
else {
val name = clazz.simpleName.removeSuffix("View").firstCharLowerCase()
if (!validViewCollection || this.template.collectionExists(name)) name
else throw RuntimeException("找不到名为[${clazz.name}]的集合")
}
}
}

View File

@@ -1,61 +0,0 @@
package com.synebula.gaea.mongodb.repository
import com.synebula.gaea.domain.model.IAggregateRoot
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
/**
* 实现ITypedRepository的Mongodb仓储类
* @param repo MongodbRepo对象
*/
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)
}
override fun <TAggregateRoot : IAggregateRoot<ID>, ID> get(
id: ID,
clazz: Class<TAggregateRoot>,
): TAggregateRoot? {
return this.repo.findOne(whereId(id), clazz)
}
override fun <TAggregateRoot : IAggregateRoot<ID>, ID> update(
root: TAggregateRoot,
clazz: Class<TAggregateRoot>,
) {
this.repo.save(root)
}
/**
* 更新多个个对象。
*
* @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(
roots: List<TAggregateRoot>,
clazz: Class<TAggregateRoot>,
) {
this.repo.insert(roots, clazz)
}
override fun <TAggregateRoot> count(params: Map<String, String>?, clazz: Class<TAggregateRoot>): Int {
val query = Query()
return this.repo.count(query.where(params, clazz), clazz).toInt()
}
}

View File

@@ -5,7 +5,6 @@ import com.synebula.gaea.data.serialization.json.IJsonSerializer
class HttpMessage(private var serializer: IJsonSerializer) : DataMessage<Any>() {
constructor(data: Any, serializer: IJsonSerializer) : this(serializer) {
this.data = data
}

View File

@@ -1,4 +1,4 @@
package com.synebula.gaea.domain.model
package com.synebula.gaea.db
/**
* 继承本接口说明对象为实体类型

View File

@@ -0,0 +1,66 @@
package com.synebula.gaea.db.context
import com.synebula.gaea.db.IEntity
/**
* 继承自IUnitOfWork表示实现了工作单元模式的上下文接口。
*
* @author alex
*/
interface IDbContext : IUnitOfWork {
/**
* 插入单个对象。
*
* @param entity 需要插入的对象。
* @return 返回原对象如果对象ID为自增则补充自增ID。
*/
fun <TEntity : IEntity<ID>, ID> add(entity: TEntity, clazz: Class<TEntity>)
/**
* 插入多个个对象。
*
* @param entities 需要插入的对象。
*/
fun <TEntity : IEntity<ID>, ID> add(entities: List<TEntity>, clazz: Class<TEntity>)
/**
* 更新对象。
*
* @param entity 需要更新的对象。
* @return
*/
fun <TEntity : IEntity<ID>, ID> update(entity: TEntity, clazz: Class<TEntity>)
/**
* 更新多个个对象。
*
* @param entities 需要更新的对象。
*/
fun <TEntity : IEntity<ID>, ID> update(entities: List<TEntity>, clazz: Class<TEntity>)
/**
* 通过id删除该条数据
*
* @param id id
* @param clazz 操作数据的类型
*/
fun <TEntity : IEntity<ID>, ID> remove(id: ID, clazz: Class<TEntity>)
/**
* 根据ID获取对象。
*
* @param id id
* @param clazz 操作数据的类型
* @return 聚合根
*/
fun <TEntity : IEntity<ID>, ID> get(id: ID, clazz: Class<TEntity>): TEntity?
/**
* 根据条件查询符合条件记录的数量
*
* @param params 查询条件。
* @return int
*/
fun <TEntity : IEntity<ID>, ID> count(params: Map<String, String>?, clazz: Class<TEntity>): Int
}

View File

@@ -1,4 +1,4 @@
package com.synebula.gaea.domain.repository.context
package com.synebula.gaea.db.context
/**
* 表示所有继承于该接口的类型都是Unit Of Work的一种实现

View File

@@ -1,4 +1,4 @@
package com.synebula.gaea.query
package com.synebula.gaea.db.query
/**
* 查询基接口, 其中方法都指定了查询的视图类型

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
package com.synebula.gaea.query
package com.synebula.gaea.db.query
/**
* 分页数据

View File

@@ -1,4 +1,4 @@
package com.synebula.gaea.query
package com.synebula.gaea.db.query
/**
* class 分页参数信息

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
package com.synebula.gaea.domain.event
import com.synebula.gaea.data.message.IEvent
import com.synebula.gaea.domain.model.IAggregateRoot
import com.synebula.gaea.db.IEntity
class AfterRemoveEvent<T : IAggregateRoot<I>, I>(var id: I? = null) : IEvent
class AfterRemoveEvent<T : IEntity<I>, I>(var id: I? = null) : IEvent

View File

@@ -1,6 +1,7 @@
package com.synebula.gaea.domain.event
import com.synebula.gaea.data.message.IEvent
import com.synebula.gaea.db.IEntity
import com.synebula.gaea.domain.model.IAggregateRoot
class BeforeRemoveEvent<T : IAggregateRoot<I>, I>(var id: I? = null) : IEvent
class BeforeRemoveEvent<T : IEntity<I>, I>(var id: I? = null) : IEvent

View File

@@ -1,5 +1,5 @@
package com.synebula.gaea.domain.model
abstract class AggregateRoot<ID> : Entity<ID>(), IAggregateRoot<ID> {
override var alive: Boolean = true
override var avalible: Boolean = true
}

View File

@@ -1,3 +1,5 @@
package com.synebula.gaea.domain.model
import com.synebula.gaea.db.IEntity
abstract class Entity<ID> : IEntity<ID>

View File

@@ -1,5 +1,7 @@
package com.synebula.gaea.domain.model
import com.synebula.gaea.db.IEntity
/**
* 继承本接口,说明对象为聚合根。
*
@@ -10,5 +12,5 @@ interface IAggregateRoot<ID> : IEntity<ID> {
/**
* 实体对象是否有效。
*/
var alive: Boolean
var avalible: Boolean
}

View File

@@ -1,7 +0,0 @@
package com.synebula.gaea.domain.model
/**
* 继承本接口,说明对象为值类型。
* @author alex
*/
interface IValue

View File

@@ -1,65 +0,0 @@
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, String>?, clazz: Class<TAggregateRoot>): Int
}

View File

@@ -1,30 +0,0 @@
package com.synebula.gaea.domain.repository.context
import com.synebula.gaea.domain.model.IAggregateRoot
/**
* 继承自IUnitOfWork表示实现了工作单元模式的上下文接口。
*
* @author alex
*/
interface IContext : IUnitOfWork {
/**
* 将指定的聚合根标注为“新建”状态。
* @param obj 聚合根
*/
fun <T : IAggregateRoot<ID>, ID> add(obj: T)
/**
* 将指定的聚合根标注为“更改”状态。
*
* @param obj 聚合根
*/
fun <T : IAggregateRoot<ID>, ID> update(obj: T)
/**
* 将指定的聚合根标注为“删除”状态。
*
* @param obj 聚合根
*/
fun <T : IAggregateRoot<ID>, ID> remove(obj: T)
}

View File

@@ -1,67 +0,0 @@
package com.synebula.gaea.domain.service
import com.synebula.gaea.bus.IBus
import com.synebula.gaea.data.message.DataMessage
import com.synebula.gaea.domain.event.AfterRemoveEvent
import com.synebula.gaea.domain.event.BeforeRemoveEvent
import com.synebula.gaea.domain.model.IAggregateRoot
import com.synebula.gaea.domain.repository.IRepository
import com.synebula.gaea.log.ILogger
/**
* 依赖了IRepository仓储借口的服务实现类 GenericsService
* 该类依赖仓储接口 @see IGenericsRepository, 需要显式提供聚合根的class对象
*
* @param repository 仓储对象
* @param clazz 聚合根类对象
* @param logger 日志组件
* @author alex
* @version 0.1
* @since 2020-05-17
*/
open class SimpleService<TRoot : IAggregateRoot<ID>, ID>(
protected open var clazz: Class<TRoot>,
protected open var repository: IRepository<TRoot, ID>,
override var logger: ILogger,
protected open var bus: IBus<Any>? = null
) : ISimpleService<TRoot, ID> {
override fun add(root: TRoot): DataMessage<ID> {
val msg = DataMessage<ID>()
this.repository.add(root)
msg.data = root.id
return msg
}
override fun update(id: ID, root: TRoot) {
root.id = id
this.repository.update(root)
}
override fun remove(id: ID) {
val beforeRemoveEvent = BeforeRemoveEvent<TRoot, ID>(id)
this.bus?.publish(beforeRemoveEvent.topic(this.clazz), beforeRemoveEvent)
this.repository.remove(id)
val afterRemoveEvent = AfterRemoveEvent<TRoot, ID>(id)
this.bus?.publish(afterRemoveEvent.topic(this.clazz), afterRemoveEvent)
}
/**
* 增加对象
*
* @param roots 增加对象命令列表
*/
override fun add(roots: List<TRoot>) {
this.repository.add(roots)
}
/**
* 批量更新对象
*
* @param roots 更新对象命令列表
*/
override fun update(roots: List<TRoot>) {
this.repository.update(roots)
}
}

View File

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

View File

@@ -1,49 +0,0 @@
package com.synebula.gaea.query
/**
* 查询基接口, 其中方法都指定了查询的视图类型。
*
* @author alex
*/
interface IUniversalQuery {
/**
* 根据Key获取对象。
*
* @param id 对象Key。
* @return 视图结果
*/
fun <TView, ID> get(id: ID, clazz: Class<TView>): TView?
/**
* 根据实体类条件查询所有符合条件记录
*
* @param params 查询条件。
* @return 视图列表
*/
fun <TView> list(params: Map<String, String>?, clazz: Class<TView>): List<TView>
/**
* 根据条件查询符合条件记录的数量
*
* @param params 查询条件。
* @return 数量
*/
fun <TView> count(params: Map<String, String>?, clazz: Class<TView>): Int
/**
* 根据实体类条件查询所有符合条件记录(分页查询)
*
* @param params 分页条件
* @return 分页数据
*/
fun <TView> paging(params: Params, clazz: Class<TView>): Page<TView>
/**
* 查询条件范围内数据。
* @param field 查询字段
* @param params 查询条件
*
* @return 视图列表
*/
fun <TView> range(field: String, params: List<Any>, clazz: Class<TView>): List<TView>
}

View File

@@ -0,0 +1,5 @@
package com.synebula.gaea.record.model
import com.synebula.gaea.db.IEntity
interface IRecord<ID> : IEntity<ID>

View File

@@ -1,4 +1,4 @@
package com.synebula.gaea.domain.record
package com.synebula.gaea.record.model
import java.util.*

View File

@@ -1,7 +1,7 @@
package com.synebula.gaea.domain.service
package com.synebula.gaea.record.service
import com.synebula.gaea.data.message.DataMessage
import com.synebula.gaea.domain.model.IAggregateRoot
import com.synebula.gaea.db.IEntity
import com.synebula.gaea.log.ILogger
@@ -11,7 +11,7 @@ import com.synebula.gaea.log.ILogger
* @version 0.0.1
* @since 2016年9月18日 下午2:23:15
*/
interface ISimpleService<TAggregateRoot : IAggregateRoot<ID>, ID> {
interface IService<Entity : IEntity<ID>, ID> {
/**
* 日志组件
*/
@@ -20,31 +20,31 @@ interface ISimpleService<TAggregateRoot : IAggregateRoot<ID>, ID> {
/**
* 增加对象
*
* @param root 增加对象命令
* @param entity 增加对象命令
*/
fun add(root: TAggregateRoot): DataMessage<ID>
fun add(entity: Entity): ID?
/**
* 增加对象
*
* @param roots 增加对象命令列表
* @param entities 增加对象命令列表
*/
fun add(roots: List<TAggregateRoot>)
fun add(entities: List<Entity>)
/**
* 更新对象
*
* @param id 对象ID
* @param root 更新对象命令
* @param entity 更新对象命令
*/
fun update(id: ID, root: TAggregateRoot)
fun update(id: ID, entity: Entity)
/**
* 批量更新对象
*
* @param roots 更新对象命令列表
* @param entities 更新对象命令列表
*/
fun update(roots: List<TAggregateRoot>)
fun update(entities: List<Entity>)
/**
* 增加对象

View File

@@ -0,0 +1,65 @@
package com.synebula.gaea.record.service
import com.synebula.gaea.bus.IBus
import com.synebula.gaea.data.message.DataMessage
import com.synebula.gaea.db.context.IDbContext
import com.synebula.gaea.domain.event.AfterRemoveEvent
import com.synebula.gaea.domain.event.BeforeRemoveEvent
import com.synebula.gaea.log.ILogger
import com.synebula.gaea.record.model.IRecord
/**
* 依赖了IRepository仓储借口的服务实现类 GenericsService
* 该类依赖仓储接口 @see IGenericsRepository, 需要显式提供聚合根的class对象
*
* @param context 仓储对象
* @param clazz 聚合根类对象
* @param logger 日志组件
* @author alex
* @version 0.1
* @since 2020-05-17
*/
open class Service<TEntity : IRecord<ID>, ID>(
protected open var clazz: Class<TEntity>,
protected open var context: IDbContext,
protected open var bus: IBus<Any>? = null,
override var logger: ILogger
) : IService<TEntity, ID> {
override fun add(entity: TEntity): ID? {
this.context.add(entity, clazz)
return entity.id
}
override fun update(id: ID, entity: TEntity) {
entity.id = id
this.context.update(entity, clazz)
}
override fun remove(id: ID) {
val beforeRemoveEvent = BeforeRemoveEvent<TEntity, ID>(id)
this.bus?.publish(beforeRemoveEvent.topic(this.clazz), beforeRemoveEvent)
this.context.remove(id, clazz)
val afterRemoveEvent = AfterRemoveEvent<TEntity, ID>(id)
this.bus?.publish(afterRemoveEvent.topic(this.clazz), afterRemoveEvent)
}
/**
* 增加对象
*
* @param entitys 增加对象命令列表
*/
override fun add(entitys: List<TEntity>) {
this.context.add(entitys, clazz)
}
/**
* 批量更新对象
*
* @param entitys 更新对象命令列表
*/
override fun update(entitys: List<TEntity>) {
this.context.update(entitys, clazz)
}
}