0.2.1 增加gaea.app gaea.mongo模块功能

This commit is contained in:
2020-05-16 14:49:16 +08:00
parent 69dbf4afd1
commit 12d6332d6d
57 changed files with 992 additions and 135 deletions

View File

@@ -15,31 +15,31 @@ buildscript {
}
allprojects {
group 'com.synebula'
version version
}
subprojects {
ext {
version '0.2.0'
version '0.2.1'
spring_version = "2.0.0.RELEASE"
}
group 'com.synebula'
version project.version
apply plugin: 'idea'
buildscript {
repositories {
mavenLocal()
maven { url 'http://maven.aliyuMongoRepositoryn.com/nexus/content/groups/public/' }
mavenCentral()
}
}
repositories {
mavenLocal()
maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
mavenCentral()
}
}
subprojects {
buildscript {
repositories {
mavenLocal()
maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
mavenCentral()
}
}
apply plugin: 'idea'
apply plugin: 'java'
apply plugin: 'kotlin'
apply plugin: 'maven'

View File

@@ -1,6 +1,8 @@
rootProject.name = 'gaea.project'
include 'src:gaea'
findProject(':src:gaea')?.name = 'gaea'
include 'src:gaea.domain'
findProject(':src:gaea.domain')?.name = 'gaea.domain'
include 'src:gaea.app'
findProject(':src:gaea.app')?.name = 'gaea.app'
include 'src:gaea.mongo'
findProject(':src:gaea.mongo')?.name = 'gaea.mongo'

18
src/gaea.app/build.gradle Normal file
View File

@@ -0,0 +1,18 @@
dependencies {
compile project(":src:gaea")
compile("org.springframework.boot:spring-boot-starter-web:$spring_version")
compile group: 'com.google.code.gson', name: 'gson', version: '2.8.6'
compile group: 'net.sf.dozer', name: 'dozer', version: '5.5.1'
}
publishing {
publications {
mavenJava(MavenPublication) {
group 'com.synebula'
artifactId 'gaea.app'
version "$version"
from components.java
}
}
}

View File

@@ -0,0 +1,51 @@
package com.synebula.gaea.app
import com.synebula.gaea.app.components.HttpMessage
import com.synebula.gaea.data.message.Status
import com.synebula.gaea.log.ILogger
interface IApplication {
/**
* 业务名称
*/
var name: String
/**
* 日志组件
*/
var logger: ILogger
/**
* 安全执行
*/
fun safeExecute(error: String, process: ((msg: HttpMessage) -> Unit)): HttpMessage {
val msg = HttpMessage(Status.Success)
try {
process(msg)
logger.debug("$name business execute success")
} catch (ex: Exception) {
msg.status = Status.Error
msg.message = if (error.isEmpty()) ex.message ?: "" else error
msg.data = ex.message
logger.error(ex, "$error: ${ex.message}")
}
return msg
}
/**
* 可抛出自定义异常信息的安全controller实现了异常捕获和消息组成。
*/
fun throwExecute(error: String, process: ((msg: HttpMessage) -> Unit)): HttpMessage {
val msg = HttpMessage(Status.Success)
try {
process(msg)
logger.debug("$name business execute success")
} catch (ex: Exception) {
logger.error(ex, "$error。异常消息将抛出!: ${ex.message}")
throw RuntimeException(error, ex)
}
return msg
}
}

View File

@@ -0,0 +1,56 @@
package com.synebula.gaea.app
import com.synebula.gaea.app.components.HttpMessage
import com.synebula.gaea.data.message.Status
import com.synebula.gaea.domain.service.ICommand
import com.synebula.gaea.domain.service.IService
import org.springframework.web.bind.annotation.*
/**
* 应用类接口提供向Command服务的接口
*
* @author alex
* @version 0.1
* @since 2018 18-2-8
*/
interface ICommandApp<TCommand : ICommand, TKey> : IApplication {
var service: IService<TKey>?
@PostMapping
fun add(@RequestBody command: TCommand): HttpMessage {
return this.throwExecute("${this.name}添加失败") {
if (this.service != null) {
val msg = this.service!!.add(command)
it.load(msg)
} else {
it.status = Status.Error
it.message = "没有对应服务,无法执行该操作"
}
}
}
@DeleteMapping("/{key:.+}")
fun remove(@PathVariable key: TKey): HttpMessage {
return this.throwExecute("${this.name}删除失败") {
if (this.service != null)
it.data = this.service!!.remove(key)
else {
it.status = Status.Error
it.message = "没有对应服务,无法执行该操作"
}
}
}
@PutMapping("/{key:.+}")
fun update(@PathVariable key: TKey, @RequestBody command: TCommand): HttpMessage {
return this.throwExecute("${this.name}更新失败") {
if (this.service != null)
this.service!!.update(key, command)
else {
it.status = Status.Error
it.message = "没有对应服务,无法执行该操作"
}
}
}
}

View File

@@ -0,0 +1,15 @@
package com.synebula.gaea.app
import com.synebula.gaea.data.message.Message
interface ILogin {
/**
* 定义登录方法。
*
* @param name 登录名
* @param password 登录密码
* @return StatusMessage, data 内容为 map 其中 key account中存储用户账户名称
*/
fun login(name: String, password: String): Message<Any>
}

View File

@@ -0,0 +1,62 @@
package com.synebula.gaea.app
import com.synebula.gaea.app.components.HttpMessage
import com.synebula.gaea.data.message.Status
import com.synebula.gaea.query.IQuery
import com.synebula.gaea.query.PagingParam
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestParam
/**
* 应用类接口提供向Query服务的接口
*
* @author alex
* @version 0.1
* @since 2018 18-2-8
*/
interface IQueryApp<TView, TKey> : IApplication {
/**
* 查询服务
*/
var query: IQuery<TView, TKey>?
@GetMapping("/{key:.+}")
fun get(@PathVariable key: TKey): HttpMessage {
return this.safeExecute("${this.name}获取数据失败") {
if (this.query != null)
it.data = this.query!!.get(key)
else {
it.status = Status.Error
it.message = "没有对应服务,无法执行该操作"
}
}
}
@GetMapping
fun list(@RequestParam parameters: MutableMap<String, Any>): HttpMessage {
return this.safeExecute("${this.name}获取数据失败") {
if (this.query != null)
it.data = this.query!!.list(parameters)
else {
it.status = Status.Error
it.message = "没有对应服务,无法执行该操作"
}
}
}
@GetMapping("/split/{size}/pages/{page}")
fun paging(@PathVariable page: Int, @PathVariable size: Int, @RequestParam parameters: MutableMap<String, Any>): HttpMessage {
return this.safeExecute("${this.name}获取分页数据失败") {
if (this.query != null) {
val params = PagingParam(page, size)
params.parameters = parameters
it.data = this.query!!.paging(params)
} else {
it.status = Status.Error
it.message = "没有对应服务,无法执行该操作"
}
}
}
}

View File

@@ -0,0 +1,12 @@
package com.synebula.gaea.app.components
import com.synebula.gaea.data.message.Status
import com.synebula.gaea.data.message.Message
class HttpMessage(status: Int = Status.Success) : Message<Any>(status) {
fun load(msg: Message<*>) {
this.status = msg.status
this.message = msg.message
this.data = msg.data
}
}

View File

@@ -1,24 +0,0 @@
package com.synebula.gaea.domain.repository.specifications
/**
* 逆反规约。
*
* @author alex
*
* @param <T>
* 规约对象的类型。
*/
class NotSpecification<T>
/**
* 构造一个新的逆反规约对象。
*
* @param specification
* 需要逆反的规约对象。
*/
(private val spec: ISpecification<T>) : Specification<T>() {
override fun isSatisfiedBy(obj: T): Boolean {
return !spec.isSatisfiedBy(obj)
}
}

View File

@@ -1,14 +1,15 @@
dependencies {
compile project(":src:gaea")
compile("org.springframework.boot:spring-boot-starter-data-mongodb:$spring_version")
}
publishing {
publications {
mavenJava(MavenPublication) {
group 'com.synebula'
artifactId 'gaea.domain'
version project.version
artifactId 'gaea.mongo'
version "$version"
from components.java
}
}
}
}

View File

@@ -0,0 +1,133 @@
package com.synebula.gaea.query
import org.springframework.data.domain.Sort
import org.springframework.data.mongodb.core.MongoTemplate
import org.springframework.data.mongodb.core.query.Criteria
import org.springframework.data.mongodb.core.query.Query
import org.springframework.data.mongodb.core.query.isEqualTo
import java.lang.reflect.Field
import java.lang.reflect.ParameterizedType
open class MongoQuery<TView>(var collection: String, var repo: MongoTemplate) : IQuery<TView, String> {
@Suppress("UNCHECKED_CAST")
protected val viewClass: Class<TView> = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class<TView>
private val _systemClass = arrayOf(
"String",
"Date",
"Int",
"Double",
"Float",
"BigDecimal",
"Decimal")
override fun list(params: Map<String, Any>?): List<TView> {
val viewFields = this.viewFields()
val query = Query()
this.where(query, params)
this.select(query, viewFields.toTypedArray())
return this.repo.find(query, this.viewClass, this.collection)
}
override fun count(params: Map<String, Any>?): Int {
val query = Query()
return this.repo.count(where(query, params), this.collection).toInt()
}
override fun paging(params: PagingParam): PagingData<TView> {
val viewFields = this.viewFields()
val result = PagingData<TView>(1, 10)
result.size = params.size
result.page = params.page
val query = Query()
this.where(query, params.parameters)
result.total = this.repo.count(query, this.collection).toInt()
this.select(query, viewFields.toTypedArray())
query.with(order(params.orderBy))
query.skip(params.index).limit(params.size)
result.data = this.repo.find(query, this.viewClass, this.collection)
return result
}
override fun get(key: String): TView? {
return this.repo.findOne(Query.query(Criteria.where("_id").isEqualTo(key))
, this.viewClass, this.collection)
}
protected fun viewFields(): List<String> {
return traversalFields(viewClass.declaredFields)
}
private fun traversalFields(fields: Array<Field>): List<String> {
val names = mutableListOf<String>()
fields.forEach { field ->
names.add(field.name)
if (!field.type.isPrimitive
&& !field.type.isArray
&& !this._systemClass.contains(field.type.simpleName))
names.addAll(this.traversalFields(field.type.declaredFields).map { "${field.name}.$it" })
}
return names
}
protected open fun where(query: Query, params: Map<String, Any>?): Query {
val criteria = Criteria()
if (params != null) {
for (param in params) {
val value = this.convertFieldValueType(param.key, param.value)
criteria.and(param.key).isEqualTo(value)
}
}
return query.addCriteria(criteria)
}
protected fun convertFieldValueType(key: String, value: Any): Any? {
val getter = this.viewClass.getMethod("get${key.substring(0, 1).toUpperCase()}${key.substring(1)}")
return this.convertClass(getter.returnType, value.toString())
}
protected open fun select(query: Query, fields: Array<String>): Query {
fields.forEach {
query.fields().include(it)
}
return query
}
protected open fun order(orders: MutableMap<String, OrderType>?): Sort {
val orderList = mutableListOf<Sort.Order>()
orders?.forEach() {
orderList.add(Sort.Order(Sort.Direction.valueOf(it.value.name), it.key))
}
return if (orderList.size == 0)
Sort.by("_id")
else
Sort.by(orderList)
}
private fun convertClass(type: Class<*>, value: String): Any? {
if (!type.isPrimitive) { // 判断基本类型
if (type == String::class.java) { // 如果是string则直接返回
return value
}
// 如果不为null 则通过反射实例一个对象返回
return if ("" == value) null else type.getConstructor(String::class.java).newInstance(value)
}
// 下面处理基本类型,返回包装类
return when (type.name) {
"int" -> Integer.parseInt(value)
"byte" -> java.lang.Byte.parseByte(value)
"boolean" -> java.lang.Boolean.parseBoolean(value)
"double" -> java.lang.Double.parseDouble(value)
"float" -> java.lang.Float.parseFloat(value)
"long" -> java.lang.Long.parseLong(value)
"short" -> java.lang.Short.parseShort(value)
else -> value
}
}
}

View File

@@ -0,0 +1,35 @@
package com.synebula.gaea.repository
import com.synebula.gaea.domain.model.IAggregateRoot
import com.synebula.gaea.domain.repository.ITypedRepository
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.data.mongodb.core.MongoTemplate
import org.springframework.data.mongodb.core.query.Criteria
import org.springframework.data.mongodb.core.query.Query
import org.springframework.data.mongodb.core.query.isEqualTo
import org.springframework.stereotype.Repository
@Repository
abstract class MongoRepository<TAggregateRoot : IAggregateRoot<String>> : ITypedRepository<TAggregateRoot, String> {
@Autowired
private lateinit var repo: MongoTemplate
override fun remove(id: String, clazz: Class<TAggregateRoot>) {
this.repo.remove(queryId(id), clazz)
}
override fun get(id: String, clazz: Class<TAggregateRoot>): TAggregateRoot {
return this.repo.findOne(queryId(id), clazz) as TAggregateRoot
}
override fun update(obj: TAggregateRoot) {
this.repo.save(obj)
}
override fun add(obj: TAggregateRoot) {
this.repo.save(obj)
}
protected fun queryId(id: String): Query = Query(Criteria("_id").isEqualTo(id))
}

View File

@@ -2,9 +2,9 @@ publishing {
publications {
mavenJava(MavenPublication) {
group 'com.synebula'
artifactId 'gaea.data'
version project.version
artifactId 'gaea'
version "$version"
from components.java
}
}
}
}

View File

@@ -1,15 +1,47 @@
package com.synebula.gaea.data.message
import java.util.Date
import java.util.*
open class Message<T> {
/**
*
* 用来统一Http返回消息类型通常使用json格式传递
*
* @param status http编码。200成功400错误500异常
* @tparam T 消息数据类型
*/
open class Message<T>(var status: Int = Status.Success) {
/**
* 传递的业务数据
*/
var data: T? = null
/**
* 附带提示消息
*/
var message = ""
/**
* 消息时间戳
*/
val timestamp: Long = Date().time
constructor(data: T) : this(Status.Success) {
this.data = data
}
constructor(status: Int, message: String) : this(status) {
this.message = message
}
constructor(status: Int, data: T, message: String) : this(status) {
this.data = data
this.message = message
}
open fun from(other: Message<T>) {
this.status = other.status
this.data = other.data
this.message = other.message
}
}

View File

@@ -0,0 +1,18 @@
package com.synebula.gaea.data.message
object Status {
/**
* 成功
*/
val Success = 200
/**
* 失败
*/
val Failure = 400
/**
* 错误
*/
val Error = 500
}

View File

@@ -1,37 +0,0 @@
package com.synebula.gaea.data.message.http
import com.synebula.gaea.data.message.Message
/**
*
* 用来统一Http返回消息类型通常使用json格式传递
*
* @param status http编码。200成功400错误500异常
* @tparam T 消息数据类型
*/
class HttpMessage<T>(var status: Int = HttpStatus.Success.code) : Message<T>() {
/**
* 附带提示消息
*/
var message = ""
constructor(data: T) : this(HttpStatus.Success.code) {
this.data = data
}
constructor(status: Int, message: String) : this(status) {
this.message = message
}
constructor(status: Int, data: T, message: String) : this(status) {
this.data = data
this.message = message
}
fun from(other: HttpMessage<T>) {
this.status = other.status
this.data = other.data
this.message = message
}
}

View File

@@ -1,36 +0,0 @@
package com.synebula.gaea.data.message.http
/**
* 状态类型。
*
* @author alex
* @version 0.0.1
* @since 2016年9月6日 下午3:27:55
*/
enum class HttpStatus(val code: Int) {
/**
* 成功
*/
Success(200),
/**
* 失败
*/
Failure(400),
/**
* 错误
*/
Error(500);
companion object {
fun valueOf(code: Int): HttpStatus {
return when (code) {
200 -> HttpStatus.Success
400 -> HttpStatus.Failure
else -> HttpStatus.Error
}
}
}
}

View File

@@ -9,7 +9,7 @@ interface ITypedRepository<TAggregateRoot : IAggregateRoot<TKey>, TKey> {
* @param obj 需要插入的对象
* @return 返回原对象如果对象ID为自增则补充自增ID
*/
fun add(obj: TAggregateRoot): Unit
fun add(obj: TAggregateRoot)
/**
* 更新对象
@@ -17,7 +17,7 @@ interface ITypedRepository<TAggregateRoot : IAggregateRoot<TKey>, TKey> {
* @param obj 需要更新的对象
* @return
*/
fun update(obj: TAggregateRoot): Unit
fun update(obj: TAggregateRoot)
/**
* 通过id删除该条数据
@@ -25,7 +25,7 @@ interface ITypedRepository<TAggregateRoot : IAggregateRoot<TKey>, TKey> {
* @param id id
* @param clazz 操作数据的类型
*/
fun remove(id: TKey, clazz: Class<TAggregateRoot>): Unit
fun remove(id: TKey, clazz: Class<TAggregateRoot>)
/**
* 根据ID获取对象

View File

@@ -0,0 +1,19 @@
package com.synebula.gaea.domain.repository.specifications
/**
* 逆反规约。
*
* @author alex
*
* @param <T> 规约对象的类型。
*
* @param spec 需要逆反的规约对象。
*
*/
class NotSpecification<T>(private val spec: ISpecification<T>) : Specification<T>() {
override fun isSatisfiedBy(obj: T): Boolean {
return !spec.isSatisfiedBy(obj)
}
}

View File

@@ -1,7 +1,7 @@
package com.synebula.gaea.domain.service
import com.synebula.gaea.data.IObjectConverter
import com.synebula.gaea.data.message.http.HttpMessage
import com.synebula.gaea.data.message.Message
import com.synebula.gaea.domain.model.complex.IComplexAggregateRoot
import com.synebula.gaea.domain.repository.IComplexRepository
import com.synebula.gaea.log.ILogger
@@ -18,8 +18,8 @@ open class ComplexService<TAggregateRoot : IComplexAggregateRoot<TKey, TSecond>,
protected var converter: IObjectConverter, protected var aggregateRootClass: Class<TAggregateRoot>)
: IComplexService<TKey, TSecond> {
override fun add(command: ICommand): HttpMessage<Pair<TKey, TSecond>> {
val msg = HttpMessage<Pair<TKey, TSecond>>()
override fun add(command: ICommand): Message<Pair<TKey, TSecond>> {
val msg = Message<Pair<TKey, TSecond>>()
val root = this.convert(command)
repository.add(root)
msg.data = Pair<TKey, TSecond>(root.id, root.secondary)

View File

@@ -1,6 +1,6 @@
package com.synebula.gaea.domain.service
import com.synebula.gaea.data.message.http.HttpMessage
import com.synebula.gaea.data.message.Message
/**
* class IFlatService
@@ -11,7 +11,7 @@ import com.synebula.gaea.data.message.http.HttpMessage
*/
interface IComplexService<TKey, TSecond> {
fun add(command: ICommand): HttpMessage<Pair<TKey, TSecond>>
fun add(command: ICommand): Message<Pair<TKey, TSecond>>
fun update(key: TKey, secondary: TSecond, command: ICommand)

View File

@@ -1,6 +1,6 @@
package com.synebula.gaea.domain.service
import com.synebula.gaea.data.message.http.HttpMessage
import com.synebula.gaea.data.message.Message
import com.synebula.gaea.log.ILogger
@@ -16,7 +16,7 @@ interface IService<TKey> {
*/
var logger: ILogger
fun add(command: ICommand): HttpMessage<TKey>
fun add(command: ICommand): Message<TKey>
fun update(key: TKey, command: ICommand)

View File

@@ -1,7 +1,7 @@
package com.synebula.gaea.domain.service
import com.synebula.gaea.data.IObjectConverter
import com.synebula.gaea.data.message.http.HttpMessage
import com.synebula.gaea.data.message.Message
import com.synebula.gaea.domain.model.IAggregateRoot
import com.synebula.gaea.domain.repository.IRepository
import com.synebula.gaea.log.ILogger
@@ -20,8 +20,8 @@ open class Service<TAggregateRoot : IAggregateRoot<TKey>, TKey>
protected var converter: IObjectConverter,
protected var aggregateRootClass: Class<TAggregateRoot>) : IService<TKey> {
override fun add(command: ICommand): HttpMessage<TKey> {
val msg = HttpMessage<TKey>()
override fun add(command: ICommand): Message<TKey> {
val msg = Message<TKey>()
val root = this.convert(command)
repository.add(root)
msg.data = root.id

View File

@@ -0,0 +1,23 @@
package com.synebula.gaea.io.scan
/**
*
* @author alex
* @version 0.0.1
* @since 2016年9月20日 上午10:50:06
*/
object ClassLoaderContext {
/**
* 获得class loader<br></br>
* 若当前线程class loader不存在取当前类的class loader
*
* @return 类加载器
*/
fun get(): ClassLoader {
var classLoader: ClassLoader? = Thread.currentThread().contextClassLoader
if (classLoader == null) {
classLoader = ClassLoaderContext::class.java.classLoader
}
return classLoader!!
}
}

View File

@@ -0,0 +1,49 @@
package com.synebula.gaea.io.scan
import java.io.IOException
import java.net.URL
import java.util.Enumeration
import java.util.HashSet
/**
*
* @author alex
* @version 0.0.1
* @since 2016年9月20日 下午2:59:47
*/
object ClassPath {
/**
* 获得Java ClassPath路径
* @return 获得Java ClassPath路径不包括 jre
*/
fun get(): Array<String> {
val paths = System.getProperty("java.class.path")
val separator = System.getProperty("path.separator")
return paths.split(separator.toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
}
/**
* 获得ClassPath
*
* @param packageName 包名称
* @return ClassPath路径字符串集合
*/
fun get(packageName: String): Array<String> {
val paths = HashSet<String>()
var path = packageName.replace(".", "/")
// 判断路径最后一个字符是不是"/",如果不是加上
path = if (path.lastIndexOf("/") != path.length - 1) "$path/" else path
var resources: Enumeration<URL>? = null
try {
resources = ClassLoaderContext.get().getResources(path)
} catch (e: IOException) {
}
while (resources!!.hasMoreElements()) {
paths.add(resources.nextElement().path)
}
return paths.toTypedArray()
}
}

View File

@@ -0,0 +1,202 @@
package com.synebula.gaea.io.scan
import java.io.File
import java.io.FileFilter
import java.io.UnsupportedEncodingException
import java.net.URLDecoder
import java.nio.charset.Charset
import java.util.Collections
import java.util.HashSet
import java.util.LinkedList
import java.util.jar.JarFile
/**
* 包扫描组件
* @author alex
* @version 0.0.1
* @since 2016年9月20日 下午2:56:50
*
* @param packageName 扫描的包名
*/
class ClassScanner(private var packageName: String) {
/**
* 类过滤器列表
*/
private var classFilters: Array<out IClassFilter>? = null
/**
* 扫描的类
*/
private val classes: MutableSet<Class<*>> = HashSet()
/**
* 文件过滤器
*/
private val fileFilter = FileFilter { file -> file.isDirectory || file.name.endsWith(".class") || file.name.endsWith(".jar") }
/**
* 构造方法。
*
* @param packageName 需要扫描的包名。
* @param classFilter
*/
constructor(packageName: String, vararg classFilter: IClassFilter) : this(packageName) {
this.classFilters = classFilter
}
/**
* 开始扫描。
*
* @return
*/
fun scan(): Collection<Class<*>> {
// 如果类集合不为空,先清空。
if (classes.isNotEmpty())
classes.clear()
var paths = ClassPath.get(packageName)// 先扫描当前类路径下文件
this.scanPath(paths)
if (classes.isEmpty()) {// 若当前类路径下文件没有,扫描java路径
paths = ClassPath.get()
this.scanPath(paths)
}
return classes
}
/*
* Private
*
*/
/**
* 填充满足条件的class 填充到 classes<br></br>
* 同时会判断给定的路径是否为Jar包内的路径如果是则扫描此Jar包
*
* @param paths Class文件路径或者所在目录Jar包路径
*/
private fun scanPath(paths: Array<String>) {
for (path in paths) {
try {
// 路径编码防止由于路径中空格和中文导致的Jar找不到
val realPath = URLDecoder.decode(path, Charset.defaultCharset().name())
val files = scanDirectory(realPath)
for (file in files) {
val fileName = file.toString()
if (fileName.contains(".jar") && !fileName.endsWith(".class"))
scanJar(file)
else if (fileName.endsWith(".class"))
scanClass(realPath, file)
}
} catch (e: UnsupportedEncodingException) {
}
}
}
/**
* 扫描文件,过滤添加类文件。
*
* @param path 扫描的磁盘路径
*/
private fun scanDirectory(path: String): Collection<File> {
var realPath = path
val files = LinkedList<File>()
val index = realPath.lastIndexOf(".jar")
if (index != -1) {// 首先判path是不是jar包下如果是说明当前path是文件
// jar文件
realPath = realPath.substring(0, index + 4)// 截取jar路径 [xxx/xxx.jar]
if (realPath.startsWith("file:"))
realPath = realPath.substring(5) // 去掉文件前缀[file:]
files.add(File(realPath))
} else {// 否则扫描文件夹下文件
val directory = LinkedList<File>()
directory.add(File(realPath))
var list: Array<File>?
var file: File
while (directory.size != 0) {
file = directory.poll()
list = file.listFiles(fileFilter)
if (list!!.isNotEmpty()) {
for (item in list) {
if (item.isDirectory)
directory.add(item)
else
files.add(item)
}
}
}
}
return files
}
/**
* 扫描jar文件过滤添加类文件。
*
* @param file 扫描的jar文件
*/
private fun scanJar(file: File) {
try {
val jar = JarFile(file)
val entries = jar.entries()
val list = Collections.list(entries)
for (entry in list) {
if (entry.name.endsWith(".class")) {
val className = entry.name.replace("/", ".").replace(".class", "")
filterClass(className)
}
}
jar.close()
} catch (ex: Throwable) {
}
}
/**
* 扫描.class类文件过滤添加类文件。
*
* @param path 路径
* @param file 文件
*/
private fun scanClass(path: String, file: File) {
var realPath = path
if (!realPath.endsWith(File.separator)) {
realPath += File.separator
}
var absolutePath = file.absolutePath
if (packageName.isEmpty())
absolutePath = absolutePath.substring(realPath.length)
val filePathWithDot = absolutePath.replace(File.separator, ".")
val subIndex = filePathWithDot.indexOf(packageName)
if (subIndex != -1) {
val endIndex = filePathWithDot.lastIndexOf(".class")
val className = filePathWithDot.substring(subIndex, endIndex)
filterClass(className)
}
}
/**
* 过滤符合要求的类,添加到结果列表中。
*
* @param className 类名
*/
private fun filterClass(className: String) {
if (className.startsWith(packageName)) {
try {
val clazz = Class.forName(className, false, ClassLoaderContext.get())
if (classFilters == null)
classes.add(clazz)
else {
for (iClassFilter in classFilters!!) {
if (iClassFilter.accept(clazz))
classes.add(clazz)
}
}
} catch (ex: Throwable) {
}
}
}
}

View File

@@ -0,0 +1,11 @@
package com.synebula.gaea.io.scan
/**
* 类过滤器,用于过滤不需要加载的类<br></br>
* @author alex
* @version 0.0.1
* @since 2016年9月18日 下午4:41:29
*/
interface IClassFilter {
fun accept(clazz: Class<*>): Boolean
}

View File

@@ -0,0 +1,42 @@
package com.synebula.gaea.query
/**
* 查询基接口。
*
* @author wxf
*/
interface IComplexQuery<TView, TKey, TSecond> {
/**
* 根据Key获取对象。
*
* @param key 对象Key。
* @return
*/
fun get(key: TKey, secondary: TSecond): TView
/**
* 根据实体类条件查询所有符合条件记录
*
* @param parameters 查询条件。
* @return list
*/
fun list(parameters: Map<String, Any>): List<TView>
/**
* 根据条件查询符合条件记录的数量
*
* @param parameters 查询条件。
* @return int
*/
fun count(parameters: Map<String, Any>): Int
/**
* 根据实体类条件查询所有符合条件记录(分页查询)
*
* @param param 分页条件
* @return
*/
fun paging(param: PagingParam): PagingData<TView>
}

View File

@@ -0,0 +1,42 @@
package com.synebula.gaea.query
/**
* 查询基接口。
*
* @author alex
*/
interface IQuery<TView, TKey> {
/**
* 根据Key获取对象。
*
* @param key 对象Key。
* @return
*/
fun get(key: TKey): TView?
/**
* 根据实体类条件查询所有符合条件记录
*
* @param params 查询条件。
* @return list
*/
fun list(params: Map<String, Any>?): List<TView>
/**
* 根据条件查询符合条件记录的数量
*
* @param params 查询条件。
* @return int
*/
fun count(params: Map<String, Any>?): Int
/**
* 根据实体类条件查询所有符合条件记录(分页查询)
*
* @param params 分页条件
* @return 分页数据
*/
fun paging(params: PagingParam): PagingData<TView>
}

View File

@@ -0,0 +1,20 @@
package com.synebula.gaea.query
/**
* class OrderType
*
* @author alex
* @version 0.1
* @since 2018 18-2-6
*/
enum class OrderType {
/**
* 升序排列
*/
ASC,
/**
* 降序排序
*/
DESC
}

View File

@@ -0,0 +1,67 @@
package com.synebula.gaea.query
/**
* 分页数据。
* 真实数据行无后台遍历需求,直接使用object类型表示即可.
*
* @author alex
*/
class PagingData<T> {
/**
* 页码从1开始。
*/
var page: Int = 0
/**
* 每页数据量。
*/
var size: Int = 0
/**
* 总数据量。
*/
var total: Int = 0
/**
* 数据索引从0开始。表示数据在总量的第几条。index = (page - 1) * size
*/
var index: Int
get() = (page - 1) * size
/**
* 结果数据。
*/
var data = listOf<T>()
/**
* 数据构造。
*
* @param page 页码从1开始。
* @param size 每页数据量。
*/
constructor(page: Int, size: Int) : super() {
this.page = page
this.size = size
this.index = (page - 1) * size + 1
}
/**
* 数据构造。
*
* @param page 页码从1开始。
* @param size 每页数据量。
* @param total 总数据量。
* @param data 结果数据。
*/
constructor(page: Int, size: Int, total: Int, data: List<T>) : super() {
this.page = page
this.size = size
this.total = total
this.index = (page - 1) * size + 1
this.data = data
}
}

View File

@@ -0,0 +1,44 @@
package com.synebula.gaea.query
/**
* class PagingParam
*
* @author alex
* @version 0.1
* @since 2018 18-2-5
*/
data class PagingParam(var page: Int = 1, var size: Int = 10) {
/**
* 数据索引从0开始。表示数据在总量的第几条。index = (page - 1) * size
*/
var index: Long = 0
get() = (page.toLong() - 1) * size.toLong()
private set
/**
* 排序条件。
*/
var orderBy: MutableMap<String, OrderType> = hashMapOf()
/**
* 查询条件。
*/
var parameters: MutableMap<String, Any> = hashMapOf()
/**
* 添加查询条件
*/
fun addParameter(field: String, value: Any): PagingParam {
parameters[field] = value
return this
}
/**
* 添加排序条件
*/
fun addOrderBy(field: String, type: OrderType = OrderType.ASC): PagingParam {
orderBy[field] = type
return this
}
}