diff --git a/vertx-demo/src/main/kotlin/app/config/RespBean.kt b/vertx-demo/src/main/kotlin/app/config/RespBean.kt index ffedea7..955e20e 100644 --- a/vertx-demo/src/main/kotlin/app/config/RespBean.kt +++ b/vertx-demo/src/main/kotlin/app/config/RespBean.kt @@ -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) } diff --git a/vertx-demo/src/main/kotlin/app/config/auth/JwtAuthenticationHandler.kt b/vertx-demo/src/main/kotlin/app/config/auth/JwtAuthenticationHandler.kt index b87c85e..89938a1 100644 --- a/vertx-demo/src/main/kotlin/app/config/auth/JwtAuthenticationHandler.kt +++ b/vertx-demo/src/main/kotlin/app/config/auth/JwtAuthenticationHandler.kt @@ -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")) } } diff --git a/vertx-demo/src/main/kotlin/app/config/auth/ResponseHandler.kt b/vertx-demo/src/main/kotlin/app/config/auth/ResponseHandler.kt index 2674550..e0331f9 100644 --- a/vertx-demo/src/main/kotlin/app/config/auth/ResponseHandler.kt +++ b/vertx-demo/src/main/kotlin/app/config/auth/ResponseHandler.kt @@ -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 -> { diff --git a/vertx-demo/src/main/kotlin/app/domain/account/AccountRepositoryImpl.kt b/vertx-demo/src/main/kotlin/app/domain/account/AccountRepositoryImpl.kt index 452efb8..7bb7c61 100644 --- a/vertx-demo/src/main/kotlin/app/domain/account/AccountRepositoryImpl.kt +++ b/vertx-demo/src/main/kotlin/app/domain/account/AccountRepositoryImpl.kt @@ -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(sqlClient), AccountRepository { diff --git a/vertx-demo/src/main/kotlin/app/verticle/WebVerticle.kt b/vertx-demo/src/main/kotlin/app/verticle/WebVerticle.kt index 1fe10d6..ea8ea68 100644 --- a/vertx-demo/src/main/kotlin/app/verticle/WebVerticle.kt +++ b/vertx-demo/src/main/kotlin/app/verticle/WebVerticle.kt @@ -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 { diff --git a/vertx-fw/src/main/kotlin/org/aikrai/vertx/config/resp/DefaultResponseHandler.kt b/vertx-fw/src/main/kotlin/org/aikrai/vertx/config/resp/DefaultResponseHandler.kt index db1e501..9863cd8 100644 --- a/vertx-fw/src/main/kotlin/org/aikrai/vertx/config/resp/DefaultResponseHandler.kt +++ b/vertx-fw/src/main/kotlin/org/aikrai/vertx/config/resp/DefaultResponseHandler.kt @@ -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) { diff --git a/vertx-fw/src/main/kotlin/org/aikrai/vertx/config/resp/ResponseHandlerInterface.kt b/vertx-fw/src/main/kotlin/org/aikrai/vertx/config/resp/ResponseHandlerInterface.kt index a390172..2a26c82 100644 --- a/vertx-fw/src/main/kotlin/org/aikrai/vertx/config/resp/ResponseHandlerInterface.kt +++ b/vertx-fw/src/main/kotlin/org/aikrai/vertx/config/resp/ResponseHandlerInterface.kt @@ -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) } \ No newline at end of file diff --git a/vertx-fw/src/main/kotlin/org/aikrai/vertx/context/RouterBuilder.kt b/vertx-fw/src/main/kotlin/org/aikrai/vertx/context/RouterBuilder.kt index cf14518..91d332e 100644 --- a/vertx-fw/src/main/kotlin/org/aikrai/vertx/context/RouterBuilder.kt +++ b/vertx-fw/src/main/kotlin/org/aikrai/vertx/context/RouterBuilder.kt @@ -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) } } diff --git a/vertx-fw/src/main/kotlin/org/aikrai/vertx/db/QueryWrapperImpl.kt b/vertx-fw/src/main/kotlin/org/aikrai/vertx/db/QueryWrapperImpl.kt index d2681fe..2d50acb 100644 --- a/vertx-fw/src/main/kotlin/org/aikrai/vertx/db/QueryWrapperImpl.kt +++ b/vertx-fw/src/main/kotlin/org/aikrai/vertx/db/QueryWrapperImpl.kt @@ -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( - private val clazz: Class + private val clazz: Class, + private val tableName: String, + private val fieldMappings: Map, ) : QueryWrapper { var sqlClient: SqlClient? = null + private val logger = KotlinLogging.logger { } private val conditions = CopyOnWriteArrayList() private val sqlMap = ConcurrentHashMap() - private val fields: List = clazz.declaredFields.filter { - !it.isAnnotationPresent(Transient::class.java) && - !Modifier.isStatic(it.modifiers) && - !it.isSynthetic - }.onEach { it.isAccessible = true } - - private val fieldMappings: Map = 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 { conditions.add( QueryCondition( diff --git a/vertx-fw/src/main/kotlin/org/aikrai/vertx/db/RepositoryImpl.kt b/vertx-fw/src/main/kotlin/org/aikrai/vertx/db/RepositoryImpl.kt index c02e6ec..9ec6cae 100644 --- a/vertx-fw/src/main/kotlin/org/aikrai/vertx/db/RepositoryImpl.kt +++ b/vertx-fw/src/main/kotlin/org/aikrai/vertx/db/RepositoryImpl.kt @@ -28,35 +28,65 @@ import kotlin.reflect.KProperty1 open class RepositoryImpl( private val sqlClient: SqlClient ) : Repository { + companion object { + // classInfoCache + private val fieldsCache = ConcurrentHashMap>() + private val fieldMappingCache = ConcurrentHashMap>() + private val idFieldCache = ConcurrentHashMap() + private val idFieldNameCache = ConcurrentHashMap() + private val tableNameCache = ConcurrentHashMap() + // sqlCache + private val baseSqlCache = ConcurrentHashMap>() + private val queryClientCache = ConcurrentHashMap() + } + private val logger = KotlinLogging.logger {} private val clazz: Class = (this::class.java.genericSuperclass as ParameterizedType) .actualTypeArguments[1] as Class - private val sqlMap = ConcurrentHashMap>() - private val querySqlMap = ConcurrentHashMap() // 缓存字段和映射 - private val fields: List = clazz.declaredFields.filter { - !Modifier.isStatic(it.modifiers) && - !it.isSynthetic && - !it.isAnnotationPresent(Transient::class.java) - }.onEach { it.isAccessible = true } - - private val fieldMappings: Map = 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 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 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( suspend fun queryBuilder(qClazz: Class? = null): QueryWrapper { 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 queryWrapper.sqlClient = connection return queryWrapper @@ -308,7 +338,7 @@ open class RepositoryImpl( // 通用获取或创建 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) }