refactor(core): 移除单例注解和优化异常处理
refactor(core): 优化QueryWrapperImpl类结构和缓存逻辑
This commit is contained in:
parent
c3cb7fae37
commit
098fa02ca6
@ -37,7 +37,7 @@ data class RespBean(
|
||||
}
|
||||
|
||||
fun failure(code: Int, message: String, data: Any? = null): RespBean {
|
||||
return RespBean(HttpStatus.ERROR, message, data)
|
||||
return RespBean(code, message, data)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -26,7 +26,7 @@ class JwtAuthenticationHandler(
|
||||
tokenService.verifyToken(user)
|
||||
event.setUser(user)
|
||||
event.next()
|
||||
} catch (e: Exception) {
|
||||
} catch (e: Throwable) {
|
||||
event.fail(401, Meta.unauthorized(e.message ?: "token"))
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,7 +48,7 @@ class ResponseHandler: ResponseHandlerInterface {
|
||||
}
|
||||
|
||||
// 业务异常处理
|
||||
override suspend fun exception(ctx: RoutingContext, e: Exception) {
|
||||
override suspend fun exception(ctx: RoutingContext, e: Throwable) {
|
||||
logger.error { "${ctx.request().uri()}: ${e.stackTraceToString()}" }
|
||||
val resObj = when(e) {
|
||||
is Meta -> {
|
||||
|
||||
@ -3,11 +3,9 @@ package app.domain.account
|
||||
import app.base.domain.auth.modle.AccountRoleDTO
|
||||
import app.domain.account.modle.AccountRoleAccessDTO
|
||||
import com.google.inject.Inject
|
||||
import com.google.inject.Singleton
|
||||
import io.vertx.sqlclient.SqlClient
|
||||
import org.aikrai.vertx.db.RepositoryImpl
|
||||
|
||||
@Singleton
|
||||
class AccountRepositoryImpl @Inject constructor(
|
||||
sqlClient: SqlClient
|
||||
) : RepositoryImpl<Long, Account>(sqlClient), AccountRepository {
|
||||
|
||||
@ -64,9 +64,9 @@ class WebVerticle @Inject constructor(
|
||||
rootRouter.route("/api" + "*").subRouter(router)
|
||||
router.route()
|
||||
.handler(corsHandler)
|
||||
.failureHandler(errorHandler)
|
||||
.handler(BodyHandler.create())
|
||||
.handler(logHandler)
|
||||
.failureHandler(errorHandler)
|
||||
|
||||
val authHandler = JwtAuthenticationHandler(coroutineScope, tokenService, context, snowflake)
|
||||
router.route("/*").handler(authHandler)
|
||||
@ -92,13 +92,13 @@ class WebVerticle @Inject constructor(
|
||||
if (failure != null) {
|
||||
logger.error { "${ctx.request().uri()}: ${failure.stackTraceToString()}" }
|
||||
val resObj = when (failure) {
|
||||
is Meta -> RespBean.failure("${failure.name}:${failure.message}", failure.data)
|
||||
is Meta -> RespBean.failure(ctx.statusCode(),"${failure.name}:${failure.message}", failure.data)
|
||||
else -> RespBean.failure("${failure.javaClass.simpleName}${if (failure.message != null) ":${failure.message}" else ""}")
|
||||
}
|
||||
val resStr = JsonUtil.toJsonStr(resObj)
|
||||
ctx.put("responseData", resStr)
|
||||
ctx.response()
|
||||
.setStatusCode(if (ctx.statusCode() != 200) ctx.statusCode() else 500)
|
||||
.setStatusCode(ctx.statusCode())
|
||||
.putHeader(HttpHeaders.CONTENT_TYPE, "application/json; charset=utf-8")
|
||||
.end(resStr)
|
||||
} else {
|
||||
|
||||
@ -23,7 +23,7 @@ class DefaultResponseHandler: ResponseHandlerInterface {
|
||||
.end(resStr)
|
||||
}
|
||||
|
||||
override suspend fun exception(ctx: RoutingContext, e: Exception) {
|
||||
override suspend fun exception(ctx: RoutingContext, e: Throwable) {
|
||||
logger.error { "${ctx.request().uri()}: ${ctx.failure().stackTraceToString()}" }
|
||||
val failure = ctx.failure()
|
||||
if (failure == null) {
|
||||
|
||||
@ -4,5 +4,5 @@ import io.vertx.ext.web.RoutingContext
|
||||
|
||||
interface ResponseHandlerInterface {
|
||||
suspend fun normal(ctx: RoutingContext, responseData: Any?, customizeResponse: Boolean = false)
|
||||
suspend fun exception(ctx: RoutingContext, e: Exception)
|
||||
suspend fun exception(ctx: RoutingContext, e: Throwable)
|
||||
}
|
||||
@ -110,7 +110,7 @@ class RouterBuilder(
|
||||
routeInfo.kFunction.call(instance, *params)
|
||||
}
|
||||
responseHandler.normal(ctx, resObj, routeInfo.customizeResp)
|
||||
} catch (e: Exception) {
|
||||
} catch (e: Throwable) {
|
||||
responseHandler.exception(ctx, e)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,45 +1,27 @@
|
||||
package org.aikrai.vertx.db
|
||||
|
||||
import cn.hutool.core.util.StrUtil
|
||||
import io.vertx.kotlin.coroutines.coAwait
|
||||
import io.vertx.sqlclient.Row
|
||||
import io.vertx.sqlclient.SqlClient
|
||||
import io.vertx.sqlclient.templates.SqlTemplate
|
||||
import mu.KotlinLogging
|
||||
import org.aikrai.vertx.db.annotation.TableField
|
||||
import org.aikrai.vertx.db.annotation.TableName
|
||||
import org.aikrai.vertx.jackson.JsonUtil
|
||||
import org.aikrai.vertx.utlis.Meta
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Modifier
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
import kotlin.reflect.KProperty1
|
||||
|
||||
class QueryWrapperImpl<T : Any>(
|
||||
private val clazz: Class<T>
|
||||
private val clazz: Class<T>,
|
||||
private val tableName: String,
|
||||
private val fieldMappings: Map<String, String>,
|
||||
) : QueryWrapper<T> {
|
||||
var sqlClient: SqlClient? = null
|
||||
|
||||
private val logger = KotlinLogging.logger { }
|
||||
private val conditions = CopyOnWriteArrayList<QueryCondition>()
|
||||
private val sqlMap = ConcurrentHashMap<String, String>()
|
||||
|
||||
private val fields: List<Field> = clazz.declaredFields.filter {
|
||||
!it.isAnnotationPresent(Transient::class.java) &&
|
||||
!Modifier.isStatic(it.modifiers) &&
|
||||
!it.isSynthetic
|
||||
}.onEach { it.isAccessible = true }
|
||||
|
||||
private val fieldMappings: Map<String, String> = fields.associate { field ->
|
||||
val fieldAnnotation = field.getAnnotation(TableField::class.java)
|
||||
val fieldName = fieldAnnotation?.value?.takeIf { it.isNotBlank() }
|
||||
?: StrUtil.toUnderlineCase(field.name)
|
||||
field.name to fieldName
|
||||
}
|
||||
|
||||
private val tableName: String = clazz.getAnnotation(TableName::class.java)?.value?.takeIf { it.isNotBlank() }
|
||||
?: StrUtil.toUnderlineCase(clazz.simpleName)
|
||||
|
||||
override fun select(vararg columns: String): QueryWrapper<T> {
|
||||
conditions.add(
|
||||
QueryCondition(
|
||||
|
||||
@ -28,35 +28,65 @@ import kotlin.reflect.KProperty1
|
||||
open class RepositoryImpl<TId, TEntity : Any>(
|
||||
private val sqlClient: SqlClient
|
||||
) : Repository<TId, TEntity> {
|
||||
companion object {
|
||||
// classInfoCache
|
||||
private val fieldsCache = ConcurrentHashMap<String, List<Field>>()
|
||||
private val fieldMappingCache = ConcurrentHashMap<String, Map<String, String>>()
|
||||
private val idFieldCache = ConcurrentHashMap<String, Field>()
|
||||
private val idFieldNameCache = ConcurrentHashMap<String, String>()
|
||||
private val tableNameCache = ConcurrentHashMap<String, String>()
|
||||
// sqlCache
|
||||
private val baseSqlCache = ConcurrentHashMap<String, ConcurrentHashMap<String, String>>()
|
||||
private val queryClientCache = ConcurrentHashMap<String, Any>()
|
||||
}
|
||||
|
||||
private val logger = KotlinLogging.logger {}
|
||||
private val clazz: Class<TEntity> = (this::class.java.genericSuperclass as ParameterizedType)
|
||||
.actualTypeArguments[1] as Class<TEntity>
|
||||
private val sqlMap = ConcurrentHashMap<String, ConcurrentHashMap<String, String>>()
|
||||
private val querySqlMap = ConcurrentHashMap<String, Any>()
|
||||
|
||||
// 缓存字段和映射
|
||||
private val fields: List<Field> = clazz.declaredFields.filter {
|
||||
!Modifier.isStatic(it.modifiers) &&
|
||||
!it.isSynthetic &&
|
||||
!it.isAnnotationPresent(Transient::class.java)
|
||||
}.onEach { it.isAccessible = true }
|
||||
|
||||
private val fieldMappings: Map<String, String> = fields.associate { field ->
|
||||
val fieldAnnotation = field.getAnnotation(TableField::class.java)
|
||||
val fieldName = fieldAnnotation?.value?.takeIf { it.isNotBlank() }
|
||||
?: StrUtil.toUnderlineCase(field.name)
|
||||
field.name to fieldName
|
||||
private val fields: List<Field> by lazy {
|
||||
fieldsCache.getOrPut(clazz.simpleName) {
|
||||
clazz.declaredFields.filter {
|
||||
!Modifier.isStatic(it.modifiers) &&
|
||||
!it.isSynthetic &&
|
||||
!it.isAnnotationPresent(Transient::class.java)
|
||||
}.onEach { it.isAccessible = true }
|
||||
}
|
||||
}
|
||||
|
||||
private val idField: Field =
|
||||
clazz.declaredFields.find { it.isAnnotationPresent(TableId::class.java) }?.also { it.isAccessible = true }
|
||||
?: throw IllegalArgumentException("No @Id field found in ${clazz.simpleName}")
|
||||
private val fieldMappings: Map<String, String> by lazy {
|
||||
fieldMappingCache.getOrPut(clazz.simpleName) {
|
||||
fields.associate { field ->
|
||||
val fieldAnnotation = field.getAnnotation(TableField::class.java)
|
||||
val fieldName = fieldAnnotation?.value?.takeIf { it.isNotBlank() }
|
||||
?: StrUtil.toUnderlineCase(field.name)
|
||||
field.name to fieldName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val idFieldName: String = idField.getAnnotation(TableField::class.java)?.value?.takeIf { it.isNotBlank() }
|
||||
?: StrUtil.toUnderlineCase(idField.name)
|
||||
private val idField: Field by lazy {
|
||||
idFieldCache.getOrPut(clazz.simpleName) {
|
||||
clazz.declaredFields.find { it.isAnnotationPresent(TableId::class.java) }
|
||||
?.also { it.isAccessible = true }
|
||||
?: throw IllegalArgumentException("No @Id field in ${clazz.simpleName}")
|
||||
}
|
||||
}
|
||||
|
||||
private val tableName: String = clazz.getAnnotation(TableName::class.java)?.value?.takeIf { it.isNotBlank() }
|
||||
?: StrUtil.toUnderlineCase(clazz.simpleName)
|
||||
private val idFieldName: String by lazy {
|
||||
idFieldNameCache.getOrPut(clazz.simpleName) {
|
||||
idField.getAnnotation(TableField::class.java)?.value?.takeIf { it.isNotBlank() }
|
||||
?: StrUtil.toUnderlineCase(idField.name)
|
||||
}
|
||||
}
|
||||
|
||||
private val tableName: String by lazy {
|
||||
tableNameCache.getOrPut(clazz.simpleName) {
|
||||
clazz.getAnnotation(TableName::class.java)?.value?.takeIf { it.isNotBlank() }
|
||||
?: StrUtil.toUnderlineCase(clazz.simpleName)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun create(t: TEntity): Int {
|
||||
try {
|
||||
@ -287,8 +317,8 @@ open class RepositoryImpl<TId, TEntity : Any>(
|
||||
suspend fun queryBuilder(qClazz: Class<Any>? = null): QueryWrapper<TEntity> {
|
||||
val qClass = qClazz ?: clazz
|
||||
val connection = getConnection()
|
||||
val queryWrapper = querySqlMap.getOrPut(qClass.simpleName) {
|
||||
QueryWrapperImpl(qClass)
|
||||
val queryWrapper = queryClientCache.getOrPut(qClass.simpleName) {
|
||||
QueryWrapperImpl(qClass, tableName, fieldMappings)
|
||||
} as QueryWrapperImpl<TEntity>
|
||||
queryWrapper.sqlClient = connection
|
||||
return queryWrapper
|
||||
@ -308,7 +338,7 @@ open class RepositoryImpl<TId, TEntity : Any>(
|
||||
|
||||
// 通用获取或创建 SQL 模板的方法
|
||||
private fun getOrCreateSql(tableName: String, key: String, sqlProvider: () -> String): String {
|
||||
val tableSqlMap = sqlMap.computeIfAbsent(tableName) { ConcurrentHashMap() }
|
||||
val tableSqlMap = baseSqlCache.getOrPut(tableName) { ConcurrentHashMap() }
|
||||
return tableSqlMap.getOrPut(key, sqlProvider)
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user