refactor(router): 优化路由构建器
This commit is contained in:
parent
fa18c92a02
commit
5eccf7ceed
@ -1,5 +1,6 @@
|
||||
package app.port.aipfox
|
||||
|
||||
import app.util.openapi.OpenApiSpecGenerator
|
||||
import com.google.inject.Inject
|
||||
import com.google.inject.name.Named
|
||||
import io.vertx.core.Vertx
|
||||
@ -8,7 +9,6 @@ import io.vertx.core.json.JsonObject
|
||||
import io.vertx.ext.web.client.WebClient
|
||||
import io.vertx.ext.web.client.WebClientOptions
|
||||
import mu.KotlinLogging
|
||||
import org.aikrai.vertx.openapi.OpenApiSpecGenerator
|
||||
|
||||
class ApifoxClient @Inject constructor(
|
||||
private val vertx: Vertx,
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package org.aikrai.vertx.openapi
|
||||
package app.util.openapi
|
||||
|
||||
import cn.hutool.core.util.StrUtil
|
||||
import io.swagger.v3.core.util.Json
|
||||
@ -14,7 +14,6 @@ import io.swagger.v3.oas.models.parameters.Parameter
|
||||
import io.swagger.v3.oas.models.parameters.RequestBody
|
||||
import io.swagger.v3.oas.models.responses.ApiResponse
|
||||
import io.swagger.v3.oas.models.responses.ApiResponses
|
||||
import io.swagger.v3.oas.models.security.SecurityScheme
|
||||
import io.swagger.v3.oas.models.servers.Server
|
||||
import mu.KotlinLogging
|
||||
import org.aikrai.vertx.context.Controller
|
||||
@ -25,7 +24,6 @@ import org.aikrai.vertx.utlis.ClassUtil
|
||||
import org.reflections.Reflections
|
||||
import java.lang.reflect.Method
|
||||
import java.lang.reflect.ParameterizedType
|
||||
import java.lang.reflect.Type
|
||||
import java.sql.Date
|
||||
import java.sql.Time
|
||||
import java.sql.Timestamp
|
||||
@ -219,7 +217,9 @@ class OpenApiSpecGenerator {
|
||||
private fun buildPath(controllerPrefix: String, methodName: String): String {
|
||||
val classPath = if (controllerPrefix != "/") {
|
||||
StrUtil.toCamelCase(StrUtil.toUnderlineCase(controllerPrefix))
|
||||
} else ""
|
||||
} else {
|
||||
""
|
||||
}
|
||||
val methodPath = StrUtil.toCamelCase(StrUtil.toUnderlineCase(methodName))
|
||||
return "/$classPath/$methodPath".replace("//", "/")
|
||||
}
|
||||
@ -1,7 +1,6 @@
|
||||
package org.aikrai.vertx.context
|
||||
|
||||
import cn.hutool.core.util.StrUtil
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
import io.vertx.core.http.HttpMethod
|
||||
import io.vertx.core.json.JsonObject
|
||||
import io.vertx.ext.auth.User
|
||||
@ -10,6 +9,7 @@ import io.vertx.ext.web.RoutingContext
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.aikrai.vertx.auth.*
|
||||
import org.aikrai.vertx.auth.AuthUser.Companion.validateAuth
|
||||
import org.aikrai.vertx.config.resp.DefaultResponseHandler
|
||||
import org.aikrai.vertx.config.resp.ResponseHandlerInterface
|
||||
import org.aikrai.vertx.db.annotation.EnumValue
|
||||
@ -19,209 +19,247 @@ import org.aikrai.vertx.utlis.Meta
|
||||
import org.reflections.Reflections
|
||||
import java.lang.reflect.Method
|
||||
import java.lang.reflect.ParameterizedType
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.coroutines.Continuation
|
||||
import kotlin.reflect.KFunction
|
||||
import kotlin.reflect.full.callSuspend
|
||||
import kotlin.reflect.full.declaredFunctions
|
||||
import kotlin.reflect.jvm.javaType
|
||||
|
||||
/**
|
||||
* RouterBuilder - 基于注解控制器构建Vert.x路由的实用工具
|
||||
*
|
||||
* 该类扫描控制器类,分析其方法,并将其注册为具有适当参数绑定和授权规则的HTTP端点
|
||||
*/
|
||||
class RouterBuilder(
|
||||
private val coroutineScope: CoroutineScope,
|
||||
private val router: Router,
|
||||
private val scanPath: String? = null,
|
||||
private val responseHandler: ResponseHandlerInterface = DefaultResponseHandler()
|
||||
) {
|
||||
var anonymousPaths = ArrayList<String>()
|
||||
// 不需要认证的路径集合
|
||||
val anonymousPaths = mutableListOf<String>()
|
||||
|
||||
/**
|
||||
* 基于注解控制器类构建路由
|
||||
*
|
||||
* @param getIt 解析控制器实例的函数
|
||||
* @return 当前RouterBuilder实例(用于链式调用)
|
||||
*/
|
||||
fun build(getIt: (clazz: Class<*>) -> Any): RouterBuilder {
|
||||
// 缓存路由信息
|
||||
// 扫描并缓存控制器路由信息
|
||||
val routeInfoCache = scanControllerRoutes()
|
||||
|
||||
// 注册路由处理器
|
||||
registerRouteHandlers(routeInfoCache, getIt)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫描控制器类并提取路由信息
|
||||
*/
|
||||
private fun scanControllerRoutes(): Map<Pair<String, HttpMethod>, RouteInfo> {
|
||||
val routeInfoCache = mutableMapOf<Pair<String, HttpMethod>, RouteInfo>()
|
||||
// 获取所有 Controller 类中的公共方法
|
||||
val packagePath = scanPath ?: ClassUtil.getMainClass().packageName
|
||||
val controllerClassSet = Reflections(packagePath).getTypesAnnotatedWith(Controller::class.java)
|
||||
val controllerMethods = ClassUtil.getPublicMethods(controllerClassSet)
|
||||
|
||||
for ((classType, methods) in controllerMethods) {
|
||||
processControllerClass(classType, methods.toList(), routeInfoCache)
|
||||
}
|
||||
|
||||
return routeInfoCache
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理控制器类及其方法
|
||||
*/
|
||||
private fun processControllerClass(
|
||||
classType: Class<*>,
|
||||
methods: List<Method>,
|
||||
routeInfoCache: MutableMap<Pair<String, HttpMethod>, RouteInfo>
|
||||
) {
|
||||
val controllerAnnotation = classType.getDeclaredAnnotationsByType(Controller::class.java).firstOrNull()
|
||||
val prefixPath = controllerAnnotation?.prefix ?: ""
|
||||
val classAllowAnonymous = classType.getAnnotation(AllowAnonymous::class.java) != null
|
||||
|
||||
for (method in methods) {
|
||||
val reqPath = getReqPath(prefixPath, classType, method)
|
||||
val httpMethod = getHttpMethod(method)
|
||||
val allowAnonymous = method.getAnnotation(AllowAnonymous::class.java) != null
|
||||
if (classAllowAnonymous || allowAnonymous) anonymousPaths.add(reqPath)
|
||||
|
||||
// 处理匿名访问
|
||||
if (classAllowAnonymous || method.getAnnotation(AllowAnonymous::class.java) != null) {
|
||||
anonymousPaths.add(reqPath)
|
||||
}
|
||||
|
||||
// 提取方法元数据
|
||||
val customizeResp = method.getAnnotation(CustomizeResponse::class.java) != null
|
||||
val role = method.getAnnotation(CheckRole::class.java)
|
||||
val permissions = method.getAnnotation(CheckPermission::class.java)
|
||||
val kFunction = classType.kotlin.declaredFunctions.find { it.name == method.name }
|
||||
if (kFunction != null) {
|
||||
val parameterInfo = kFunction.parameters.mapNotNull { parameter ->
|
||||
|
||||
// 查找对应的Kotlin函数
|
||||
classType.kotlin.declaredFunctions.find { it.name == method.name }?.let { kFunction ->
|
||||
val parameterInfo = extractParameterInfo(kFunction)
|
||||
routeInfoCache[reqPath to httpMethod] = RouteInfo(
|
||||
classType, method, kFunction, parameterInfo,
|
||||
customizeResp, role, permissions, httpMethod
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从Kotlin函数中提取参数信息
|
||||
*/
|
||||
private fun extractParameterInfo(kFunction: KFunction<*>): List<ParameterInfo> {
|
||||
return kFunction.parameters.mapNotNull { parameter ->
|
||||
val javaType = parameter.type.javaType
|
||||
|
||||
// 跳过协程的Continuation参数
|
||||
if (javaType is Class<*> && Continuation::class.java.isAssignableFrom(javaType)) {
|
||||
return@mapNotNull null
|
||||
}
|
||||
parameter.name ?: return@mapNotNull null
|
||||
|
||||
// 参数必须具有名称
|
||||
val paramName = parameter.name ?: return@mapNotNull null
|
||||
|
||||
// 从D注解获取自定义参数名
|
||||
val annotation = parameter.annotations.find { it is D } as? D
|
||||
val paramName = annotation?.name?.takeIf { it.isNotBlank() } ?: parameter.name ?: ""
|
||||
val finalParamName = annotation?.name?.takeIf { it.isNotBlank() } ?: paramName
|
||||
|
||||
// 确定参数类型
|
||||
val typeClass = when (javaType) {
|
||||
is Class<*> -> javaType
|
||||
is ParameterizedType -> javaType.rawType as? Class<*>
|
||||
else -> null
|
||||
}
|
||||
} ?: parameter.type.javaType as Class<*>
|
||||
|
||||
// 处理枚举类型参数
|
||||
val isEnum = typeClass.isEnum || parameter.type.javaType.javaClass.isEnum
|
||||
val enumValueMethod = if (isEnum) {
|
||||
typeClass.methods.find { it.isAnnotationPresent(EnumValue::class.java) }
|
||||
} else null
|
||||
|
||||
val enumConstants = if (isEnum) {
|
||||
typeClass.enumConstants?.associateBy({
|
||||
enumValueMethod?.invoke(it)?.toString() ?: (it as Enum<*>).name
|
||||
}, { it })
|
||||
} else emptyMap()
|
||||
|
||||
// 检查是否是复杂类型
|
||||
val isComplex = !parameter.type.classifier.toString().startsWith("class kotlin.") &&
|
||||
!parameter.type.classifier.toString().startsWith("class io.vertx") &&
|
||||
!typeClass.isEnum &&
|
||||
!parameter.type.javaType.javaClass.isEnum &&
|
||||
parameter.type.javaType is Class<*>
|
||||
|
||||
ParameterInfo(
|
||||
name = paramName,
|
||||
type = typeClass ?: parameter.type.javaType as Class<*>,
|
||||
name = finalParamName,
|
||||
type = typeClass,
|
||||
isNullable = parameter.type.isMarkedNullable,
|
||||
isList = parameter.type.classifier == List::class,
|
||||
isComplex = !parameter.type.classifier.toString().startsWith("class kotlin.") &&
|
||||
!parameter.type.classifier.toString().startsWith("class io.vertx") &&
|
||||
!(parameter.type.javaType as Class<*>).isEnum &&
|
||||
!parameter.type.javaType.javaClass.isEnum &&
|
||||
parameter.type.javaType is Class<*>,
|
||||
isEnum = typeClass?.isEnum ?: (parameter.type.javaType as Class<*>).isEnum
|
||||
isComplex = isComplex,
|
||||
isEnum = isEnum,
|
||||
enumValueMethod = enumValueMethod,
|
||||
enumConstants = enumConstants
|
||||
)
|
||||
}
|
||||
routeInfoCache[reqPath to httpMethod] =
|
||||
RouteInfo(classType, method, kFunction, parameterInfo, customizeResp, role, permissions)
|
||||
}
|
||||
|
||||
/**
|
||||
* 为缓存的路由注册路由处理程序
|
||||
*/
|
||||
private fun registerRouteHandlers(
|
||||
routeInfoCache: Map<Pair<String, HttpMethod>, RouteInfo>,
|
||||
getIt: (clazz: Class<*>) -> Any
|
||||
) {
|
||||
routeInfoCache.forEach { (pathMethod, routeInfo) ->
|
||||
val (path, _) = pathMethod
|
||||
router.route(routeInfo.httpMethod, path).handler { ctx ->
|
||||
handleRequest(ctx, getIt, routeInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 注册路由处理器
|
||||
routeInfoCache.forEach { (path, routeInfo) ->
|
||||
router.route(routeInfo.httpMethod, path.first).handler { ctx ->
|
||||
if (ctx.user() != null) {
|
||||
val user = ctx.user() as AuthUser
|
||||
if (!user.validateAuth(routeInfo)) {
|
||||
ctx.fail(403, Meta.unauthorized("unauthorized"))
|
||||
return@handler
|
||||
/**
|
||||
* 处理传入的HTTP请求
|
||||
*/
|
||||
private fun handleRequest(ctx: RoutingContext, getIt: (clazz: Class<*>) -> Any, routeInfo: RouteInfo) {
|
||||
// 如果存在用户,检查授权
|
||||
ctx.user()?.let { user ->
|
||||
if (user is AuthUser) {
|
||||
try {
|
||||
user.validateAuth(routeInfo.role, routeInfo.permissions)
|
||||
} catch (e: Throwable) {
|
||||
ctx.fail(403, Meta.unauthorized("未授权"))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取控制器实例并执行方法
|
||||
val instance = getIt(routeInfo.classType)
|
||||
buildLambda(ctx, instance, routeInfo)
|
||||
}
|
||||
}
|
||||
return this
|
||||
executeControllerMethod(ctx, instance, routeInfo)
|
||||
}
|
||||
|
||||
private fun buildLambda(ctx: RoutingContext, instance: Any, routeInfo: RouteInfo) {
|
||||
/**
|
||||
* 在协程中执行控制器方法
|
||||
*/
|
||||
private fun executeControllerMethod(ctx: RoutingContext, instance: Any, routeInfo: RouteInfo) {
|
||||
coroutineScope.launch {
|
||||
try {
|
||||
val params = getParamsInstance(ctx, routeInfo.parameterInfo)
|
||||
val resObj = if (routeInfo.kFunction.isSuspend) {
|
||||
val params = resolveMethodParameters(ctx, routeInfo.parameterInfo)
|
||||
val result = if (routeInfo.kFunction.isSuspend) {
|
||||
routeInfo.kFunction.callSuspend(instance, *params)
|
||||
} else {
|
||||
routeInfo.kFunction.call(instance, *params)
|
||||
}
|
||||
responseHandler.normal(ctx, resObj, routeInfo.customizeResp)
|
||||
responseHandler.normal(ctx, result, routeInfo.customizeResp)
|
||||
} catch (e: Throwable) {
|
||||
responseHandler.exception(ctx, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val objectMapper = jacksonObjectMapper()
|
||||
|
||||
private fun AuthUser.validateAuth(routeInfo: RouteInfo): Boolean {
|
||||
// 如果没有权限要求,直接返回true
|
||||
if (routeInfo.role == null && routeInfo.permissions == null) return true
|
||||
// 验证角色
|
||||
val hasValidRole = routeInfo.role?.let { role ->
|
||||
val roleSet = attributes().getJsonArray("role").toSet() as Set<String>
|
||||
if (roleSet.isEmpty()) {
|
||||
false
|
||||
} else {
|
||||
val reqRoleSet = (role.value + role.type).filter { it.isNotBlank() }.toSet()
|
||||
validateSet(reqRoleSet, roleSet, role.mode)
|
||||
}
|
||||
} ?: true
|
||||
|
||||
// 验证权限
|
||||
val hasValidPermission = routeInfo.permissions?.let { permissions ->
|
||||
val permissionSet = attributes().getJsonArray("permissions").toSet() as Set<String>
|
||||
val roleSet = attributes().getJsonArray("role").toSet() as Set<String>
|
||||
if (permissionSet.isEmpty() && roleSet.isEmpty()) {
|
||||
false
|
||||
} else {
|
||||
if (permissions.orRole.isNotEmpty()) {
|
||||
val roleBoolean = validateSet(permissions.orRole.toSet(), roleSet, Mode.AND)
|
||||
if (roleBoolean) return true
|
||||
}
|
||||
val reqPermissionSet = (permissions.value + permissions.type).filter { it.isNotBlank() }.toSet()
|
||||
validateSet(reqPermissionSet, permissionSet, permissions.mode)
|
||||
}
|
||||
} ?: true
|
||||
return hasValidRole && hasValidPermission
|
||||
}
|
||||
|
||||
private fun validateSet(
|
||||
required: Set<String>,
|
||||
actual: Set<String>,
|
||||
mode: Mode
|
||||
): Boolean {
|
||||
if (required.isEmpty()) return true
|
||||
return when (mode) {
|
||||
Mode.AND -> required == actual
|
||||
Mode.OR -> required.any { it in actual }
|
||||
}
|
||||
}
|
||||
|
||||
private fun getReqPath(prefix: String, clazz: Class<*>, method: Method): String {
|
||||
var classPath = if (prefix.isNotBlank()) {
|
||||
StrUtil.toCamelCase(StrUtil.toUnderlineCase(prefix))
|
||||
} else {
|
||||
StrUtil.toCamelCase(StrUtil.toUnderlineCase(clazz.simpleName.removeSuffix("Controller")))
|
||||
}
|
||||
if (classPath == "/") classPath = ""
|
||||
val methodName = StrUtil.toCamelCase(StrUtil.toUnderlineCase(method.name))
|
||||
return "/$classPath/$methodName".replace("//", "/")
|
||||
}
|
||||
|
||||
private fun getParamsInstance(ctx: RoutingContext, paramsInfo: List<ParameterInfo>): Array<Any?> {
|
||||
/**
|
||||
* 从请求中解析方法参数
|
||||
*/
|
||||
private fun resolveMethodParameters(ctx: RoutingContext, paramsInfo: List<ParameterInfo>): Array<Any?> {
|
||||
val params = mutableListOf<Any?>()
|
||||
|
||||
// 从不同来源收集参数
|
||||
val formAttributes = ctx.request().formAttributes().associate { it.key to it.value }
|
||||
val queryParams = ctx.queryParams().entries().associate { it.key to it.value }
|
||||
val combinedParams = formAttributes + queryParams
|
||||
// 解析Body
|
||||
val bodyObj = if (!ctx.body().isEmpty) ctx.body().asJsonObject() else null
|
||||
|
||||
// 解析请求体
|
||||
val bodyObj = ctx.body().takeUnless { it.isEmpty }?.asJsonObject()
|
||||
val bodyMap = bodyObj?.map ?: emptyMap()
|
||||
|
||||
// 处理每个参数
|
||||
paramsInfo.forEach { param ->
|
||||
if (param.isList) {
|
||||
when {
|
||||
// 处理List类型参数
|
||||
param.isList -> {
|
||||
var value = ctx.queryParams().getAll(param.name)
|
||||
if (value.isEmpty() && bodyMap[param.name] != null) {
|
||||
value = (bodyMap[param.name] as Collection<*>).map { it.toString() }.toMutableList()
|
||||
value = (bodyMap[param.name] as? Collection<*>)?.map { it.toString() }?.toMutableList() ?: mutableListOf()
|
||||
}
|
||||
if (value.isEmpty() && !param.isNullable) {
|
||||
throw IllegalArgumentException("Missing required parameter: ${param.name}")
|
||||
throw IllegalArgumentException("缺少必要参数: ${param.name}")
|
||||
}
|
||||
params.add(value.ifEmpty { null })
|
||||
return@forEach
|
||||
}
|
||||
|
||||
if (param.isEnum) {
|
||||
val value = sequenceOf(
|
||||
combinedParams[param.name],
|
||||
bodyMap[param.name]
|
||||
).filterNotNull().map { it.toString() }.firstOrNull()
|
||||
|
||||
val enumValueMethod = param.type.methods.find { method ->
|
||||
method.isAnnotationPresent(EnumValue::class.java)
|
||||
}
|
||||
val enumValue = param.type.enumConstants.firstOrNull { enumConstant ->
|
||||
if (enumValueMethod != null) {
|
||||
enumValueMethod.invoke(enumConstant).toString() == value
|
||||
} else {
|
||||
(enumConstant as Enum<*>).name == value
|
||||
}
|
||||
}
|
||||
if (enumValue != null) params.add(enumValue)
|
||||
return@forEach
|
||||
// 处理枚举类型参数
|
||||
param.isEnum -> {
|
||||
val value = combinedParams[param.name] ?: bodyMap[param.name]?.toString()
|
||||
val enumValue = param.enumConstants?.get(value)
|
||||
params.add(enumValue)
|
||||
}
|
||||
|
||||
if (param.isComplex) {
|
||||
// 处理复杂对象参数
|
||||
param.isComplex -> {
|
||||
try {
|
||||
val value = sequenceOf(
|
||||
if (paramsInfo.size == 1) bodyObj else null,
|
||||
@ -229,68 +267,79 @@ class RouterBuilder(
|
||||
combinedParams[param.name]?.let { JsonObject(it) },
|
||||
bodyObj
|
||||
).filterNotNull().firstOrNull { !it.isEmpty }
|
||||
|
||||
if (value?.isEmpty == true && !param.isNullable) {
|
||||
throw IllegalArgumentException("Missing required parameter: ${param.name}")
|
||||
throw IllegalArgumentException("缺少必要参数: ${param.name}")
|
||||
}
|
||||
|
||||
params.add(if (value == null || value.isEmpty) null else JsonUtil.parseObject(value, param.type))
|
||||
return@forEach
|
||||
} catch (e: Exception) {
|
||||
throw IllegalArgumentException(e.message, e)
|
||||
}
|
||||
}
|
||||
|
||||
params.add(
|
||||
when (param.type) {
|
||||
// 处理特殊或基本类型参数
|
||||
else -> {
|
||||
params.add(when (param.type) {
|
||||
RoutingContext::class.java -> ctx
|
||||
User::class.java -> ctx.user()
|
||||
else -> {
|
||||
val bodyValue = bodyMap[param.name]
|
||||
val paramValue = bodyValue?.toString() ?: combinedParams[param.name]
|
||||
|
||||
when {
|
||||
paramValue == null -> {
|
||||
if (!param.isNullable) throw IllegalArgumentException("Missing required parameter: ${param.name}") else null
|
||||
if (!param.isNullable) {
|
||||
throw IllegalArgumentException("缺少必要参数: ${param.name}")
|
||||
} else null
|
||||
}
|
||||
|
||||
else -> {
|
||||
val value = getParamValue(paramValue.toString(), param.type)
|
||||
val value = convertStringToType(paramValue.toString(), param.type)
|
||||
if (!param.isNullable && value == null) {
|
||||
throw IllegalArgumentException("Missing required parameter: ${param.name}")
|
||||
} else {
|
||||
value
|
||||
throw IllegalArgumentException("缺少必要参数: ${param.name}")
|
||||
} else value
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
return params.toTypedArray()
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* 将字符串参数值映射到目标类型。
|
||||
*
|
||||
* @param paramValue 参数的字符串值。
|
||||
* @param type 目标 [Class] 类型。
|
||||
* @return 转换为目标类型的参数值,如果转换失败则返回 `null`。
|
||||
* 根据类和方法信息构造请求路径
|
||||
*/
|
||||
private fun getParamValue(paramValue: String, type: Class<*>): Any? {
|
||||
private fun getReqPath(prefix: String, clazz: Class<*>, method: Method): String {
|
||||
val classPath = if (prefix.isNotBlank()) {
|
||||
StrUtil.toCamelCase(StrUtil.toUnderlineCase(prefix))
|
||||
} else {
|
||||
StrUtil.toCamelCase(StrUtil.toUnderlineCase(clazz.simpleName.removeSuffix("Controller")))
|
||||
}.let { if (it == "/") "" else it }
|
||||
|
||||
val methodName = StrUtil.toCamelCase(StrUtil.toUnderlineCase(method.name))
|
||||
return "/$classPath/$methodName".replace("//", "/")
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串值转换为目标类型
|
||||
*/
|
||||
private fun convertStringToType(paramValue: String, type: Class<*>): Any? {
|
||||
return when (type) {
|
||||
String::class.java -> paramValue
|
||||
Int::class.java, Integer::class.java -> paramValue.toIntOrNull()
|
||||
Long::class.java, Long::class.java -> paramValue.toLongOrNull()
|
||||
Double::class.java, Double::class.java -> paramValue.toDoubleOrNull()
|
||||
Boolean::class.java, Boolean::class.java -> paramValue.toBoolean()
|
||||
Long::class.java, java.lang.Long::class.java -> paramValue.toLongOrNull()
|
||||
Double::class.java, java.lang.Double::class.java -> paramValue.toDoubleOrNull()
|
||||
Boolean::class.java, java.lang.Boolean::class.java -> paramValue.toBoolean()
|
||||
else -> paramValue
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 [CustomizeRequest] 注解确定给定 REST 方法的 HTTP 方法。
|
||||
*
|
||||
* @param method 目标方法。
|
||||
* @return 对应的 [HttpMethod]。
|
||||
* 确定控制器方法的HTTP方法
|
||||
*/
|
||||
fun getHttpMethod(method: Method): HttpMethod {
|
||||
val api = method.getAnnotation(CustomizeRequest::class.java)
|
||||
@ -306,33 +355,11 @@ class RouterBuilder(
|
||||
HttpMethod.POST
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将对象序列化为 JSON 表示。
|
||||
*
|
||||
* @param obj 要序列化的对象。
|
||||
* @return JSON 字符串。
|
||||
* 路由元数据数据类
|
||||
*/
|
||||
private fun serializeToJson(obj: Any?): String {
|
||||
return objectMapper.writeValueAsString(obj)
|
||||
}
|
||||
|
||||
private fun getEnumValue(enumValue: Any?): Any? {
|
||||
if (enumValue == null || !enumValue::class.java.isEnum) {
|
||||
return null // 不是枚举或为空,直接返回 null
|
||||
}
|
||||
val enumClass = enumValue::class.java
|
||||
val methods = enumClass.declaredMethods
|
||||
for (method in methods) {
|
||||
if (method.isAnnotationPresent(EnumValue::class.java)) {
|
||||
method.isAccessible = true // 如果方法是私有的,设置为可访问
|
||||
return method.invoke(enumValue) // 调用带有 @EnumValue 注解的方法
|
||||
}
|
||||
}
|
||||
return null // 没有找到带有 @EnumValue 注解的方法
|
||||
}
|
||||
}
|
||||
|
||||
private data class RouteInfo(
|
||||
val classType: Class<*>,
|
||||
val method: Method,
|
||||
@ -341,15 +368,20 @@ class RouterBuilder(
|
||||
val customizeResp: Boolean,
|
||||
val role: CheckRole? = null,
|
||||
val permissions: CheckPermission? = null,
|
||||
val httpMethod: HttpMethod = getHttpMethod(method)
|
||||
val httpMethod: HttpMethod
|
||||
)
|
||||
|
||||
/**
|
||||
* 参数元数据数据类
|
||||
*/
|
||||
private data class ParameterInfo(
|
||||
val name: String,
|
||||
val type: Class<*>,
|
||||
val isNullable: Boolean,
|
||||
val isList: Boolean,
|
||||
val isComplex: Boolean,
|
||||
val isEnum: Boolean
|
||||
val isEnum: Boolean,
|
||||
val enumValueMethod: Method? = null,
|
||||
val enumConstants: Map<String, Any>? = null
|
||||
)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user