diff --git a/web/src/main/kotlin/cn/tursom/web/router/RoutedHttpHandler.kt b/web/src/main/kotlin/cn/tursom/web/router/RoutedHttpHandler.kt index 279af84..a024b87 100644 --- a/web/src/main/kotlin/cn/tursom/web/router/RoutedHttpHandler.kt +++ b/web/src/main/kotlin/cn/tursom/web/router/RoutedHttpHandler.kt @@ -16,6 +16,7 @@ import org.slf4j.LoggerFactory import java.io.File import java.io.RandomAccessFile import java.lang.reflect.Method +import kotlin.reflect.KCallable /** * 自动添加路径映射的处理器 @@ -97,44 +98,54 @@ open class RoutedHttpHandler( } protected fun insertMapping(obj: Any, method: Method) { + val mapping = obj::class.java.getAnnotation(Mapping::class.java)?.route ?: arrayOf("") method.annotations.forEach { annotation -> log?.info("method route {} annotation {}", method, annotation) val (routes, router) = getRoutes(annotation) ?: return@forEach log?.info("method route {} mapped to {}", method, routes) routes.forEach { route -> - router[safeRoute(route)] = if (method.parameterTypes.isEmpty()) { - obj to when { - method.getAnnotation(Html::class.java) != null -> { content -> - method(obj)?.let { result -> finishHtml(result, content) } - } - method.getAnnotation(Text::class.java) != null -> { content -> - method(obj)?.let { result -> finishText(result, content) } - } - method.getAnnotation(Json::class.java) != null -> { content -> - method(obj)?.let { result -> finishJson(result, content) } - } - else -> { content -> - method(obj)?.let { result -> autoReturn(result, content) } - } - } - } else obj to when (method.returnType) { - Void::class.java -> { content -> method(obj, content) } - Void.TYPE -> { content -> method(obj, content) } - Unit::class.java -> { content -> method(obj, content) } - else -> when { - method.getAnnotation(Html::class.java) != null -> { content -> - method(obj, content)?.let { result -> finishHtml(result, content) } - } - method.getAnnotation(Text::class.java) != null -> { content -> - method(obj, content)?.let { result -> finishText(result, content) } - } - method.getAnnotation(Json::class.java) != null -> { content -> - method(obj, content)?.let { result -> finishJson(result, content) } - } - else -> { content -> - method(obj, content)?.let { result -> autoReturn(result, content) } - } - } + if (mapping.isEmpty()) { + addRouter(obj, method, route, router) + } else mapping.forEach { + val base = safeRoute(it) + addRouter(obj, method, base + route, router) + } + } + } + } + + fun addRouter(obj: Any, method: Method, route: String, router: Router Unit>>) { + router[safeRoute(route)] = if (method.parameterTypes.isEmpty()) { + obj to when { + method.getAnnotation(Html::class.java) != null -> { content -> + method(obj)?.let { result -> finishHtml(result, content) } + } + method.getAnnotation(Text::class.java) != null -> { content -> + method(obj)?.let { result -> finishText(result, content) } + } + method.getAnnotation(Json::class.java) != null -> { content -> + method(obj)?.let { result -> finishJson(result, content) } + } + else -> { content -> + method(obj)?.let { result -> autoReturn(result, content) } + } + } + } else obj to when (method.returnType) { + Void::class.java -> { content -> method(obj, content) } + Void.TYPE -> { content -> method(obj, content) } + Unit::class.java -> { content -> method(obj, content) } + else -> when { + method.getAnnotation(Html::class.java) != null -> { content -> + method(obj, content)?.let { result -> finishHtml(result, content) } + } + method.getAnnotation(Text::class.java) != null -> { content -> + method(obj, content)?.let { result -> finishText(result, content) } + } + method.getAnnotation(Json::class.java) != null -> { content -> + method(obj, content)?.let { result -> finishJson(result, content) } + } + else -> { content -> + method(obj, content)?.let { result -> autoReturn(result, content) } } } } @@ -231,15 +242,25 @@ open class RoutedHttpHandler( null } + fun T.repeatUntil(state: (T) -> Boolean, block: (T) -> T): T { + var result = this + while (state(result)) { + result = block(result) + } + return result + } + fun safeRoute(route: String) = ( if (route.startsWith('/')) route else "/$route").let { if (it.endsWith('/')) it.dropLast(1) else it - } + }.repeatUntil({ it.contains("//") }) { it.replace("//", "/") } fun autoReturn(result: Any, content: HttpContent) { log?.debug("{}: autoReturn: {}", content.clientIp, result) when (result) { is String -> content.finishText(result.toByteArray()) + is StringBuilder -> content.finishText(result.toString().toByteArray()) + is StringBuffer -> content.finishText(result.toString().toByteArray()) is ByteArray -> content.finishText(result) is File -> { content.autoContextType(result.name) diff --git a/web/web-coroutine/build.gradle b/web/web-coroutine/build.gradle new file mode 100644 index 0000000..2c7209e --- /dev/null +++ b/web/web-coroutine/build.gradle @@ -0,0 +1,7 @@ +dependencies { + implementation project(":web") + api project(":json") + api group: 'org.slf4j', name: 'slf4j-api', version: '1.7.29' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.1' + compile group: 'org.jetbrains.kotlin', name: 'kotlin-reflect', version: '1.3.61' +} \ No newline at end of file diff --git a/web/web-coroutine/src/main/kotlin/cn/tursom/web/router/AsyncRoutedHttpHandler.kt b/web/web-coroutine/src/main/kotlin/cn/tursom/web/router/AsyncRoutedHttpHandler.kt index a15feea..27a523c 100644 --- a/web/web-coroutine/src/main/kotlin/cn/tursom/web/router/AsyncRoutedHttpHandler.kt +++ b/web/web-coroutine/src/main/kotlin/cn/tursom/web/router/AsyncRoutedHttpHandler.kt @@ -80,51 +80,62 @@ open class AsyncRoutedHttpHandler( } } - @Suppress("UNCHECKED_CAST") protected fun insertMapping(obj: Any, method: KCallable<*>) { + val mapping = obj::class.java.getAnnotation(Mapping::class.java)?.route ?: arrayOf("") method.annotations.forEach { annotation -> log?.info("method route {} annotation {}", method, annotation) val (routes, router) = getAsyncRoutes(annotation) ?: return@forEach log?.info("method route {} mapped to {}", method, routes) routes.forEach { route -> - router[safeRoute(route)] = if (method.parameters.size == 1) { - obj to when { - method.findAnnotation() != null -> { content -> - (method as suspend Any.() -> Any?)(obj)?.let { result -> finishHtml(result, content) } - } - method.findAnnotation() != null -> { content -> - (method as suspend Any.() -> Any?)(obj)?.let { result -> finishText(result, content) } - } - method.findAnnotation() != null -> { content -> - (method as suspend Any.() -> Any?)(obj)?.let { result -> finishJson(result, content) } - } - else -> { content -> - (method as suspend Any.() -> Any?)(obj)?.let { result -> autoReturn(result, content) } - } - } - } else obj to when (method.returnType) { - Void::class.java -> method as suspend (HttpContent) -> Unit - Void.TYPE -> method as suspend (HttpContent) -> Unit - Unit::class.java -> method as suspend (HttpContent) -> Unit - else -> when { - method.findAnnotation() != null -> { content -> - (method as suspend Any.(HttpContent) -> Any?)(obj, content)?.let { result -> finishHtml(result, content) } - } - method.findAnnotation() != null -> { content -> - (method as suspend Any.(HttpContent) -> Any?)(obj, content)?.let { result -> finishText(result, content) } - } - method.findAnnotation() != null -> { content -> - (method as suspend Any.(HttpContent) -> Any?)(obj, content)?.let { result -> finishJson(result, content) } - } - else -> { content -> - (method as suspend Any.(HttpContent) -> Any?)(obj, content)?.let { result -> autoReturn(result, content) } - } - } + if (mapping.isEmpty()) { + addRouter(obj, method, route, router) + } else mapping.forEach { + val base = safeRoute(it) + addRouter(obj, method, base + route, router) } } } } + @Suppress("UNCHECKED_CAST") + fun addRouter(obj: Any, method: KCallable<*>, route: String, router: Router Unit>>) { + router[safeRoute(route)] = if (method.parameters.size == 1) { + obj to when { + method.findAnnotation() != null -> { content -> + (method as suspend Any.() -> Any?)(obj)?.let { result -> finishHtml(result, content) } + } + method.findAnnotation() != null -> { content -> + (method as suspend Any.() -> Any?)(obj)?.let { result -> finishText(result, content) } + } + method.findAnnotation() != null -> { content -> + (method as suspend Any.() -> Any?)(obj)?.let { result -> finishJson(result, content) } + } + else -> { content -> + (method as suspend Any.() -> Any?)(obj)?.let { result -> autoReturn(result, content) } + } + } + } else obj to when (method.returnType) { + Void::class.java -> method as suspend (HttpContent) -> Unit + Void.TYPE -> method as suspend (HttpContent) -> Unit + Unit::class.java -> method as suspend (HttpContent) -> Unit + else -> when { + method.findAnnotation() != null -> { content -> + (method as suspend Any.(HttpContent) -> Any?)(obj, content)?.let { result -> finishHtml(result, content) } + } + method.findAnnotation() != null -> { content -> + (method as suspend Any.(HttpContent) -> Any?)(obj, content)?.let { result -> finishText(result, content) } + } + method.findAnnotation() != null -> { content -> + (method as suspend Any.(HttpContent) -> Any?)(obj, content)?.let { result -> finishJson(result, content) } + } + else -> { content -> + (method as suspend Any.(HttpContent) -> Any?)(obj, content)?.let { result -> autoReturn(result, content) } + } + } + } + } + + protected fun getAsyncRoutes(annotation: Annotation) = when (annotation) { is Mapping -> { annotation.route to getAsyncRouter(annotation.method)