All Downloads are FREE. Search and download functionalities are using the official Maven repository.

love.forte.simbot.http.template.spring.RestTemplateHttpTemplate.kt Maven / Gradle / Ivy

There is a newer version: 2.5.2
Show newest version
/*
 *
 *  * Copyright (c) 2020. ForteScarlet All rights reserved.
 *  * Project  component-onebot
 *  * File     RestTeamplateHttpTemplate.java
 *  *
 *  * You can contact the author through the following channels:
 *  * github https://github.com/ForteScarlet
 *  * gitee  https://gitee.com/ForteScarlet
 *  * email  [email protected]
 *  * QQ     1149159218
 *  *
 *  *
 *
 */
@file:JvmName("RestTemplateHttpTemplates")
package love.forte.simbot.http.template.spring

import kotlinx.coroutines.*
import love.forte.common.ioc.annotation.SpareBeans
import love.forte.simbot.http.template.*
import org.springframework.http.HttpEntity
import org.springframework.http.HttpMethod
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.web.client.RestTemplate
import kotlin.coroutines.suspendCoroutine
import org.springframework.http.HttpHeaders as SpringHeaders


private fun SpringHeaders.cookies(cookies: HttpCookies?) {
    if (cookies != null && cookies.isNotEmpty()) {
        val cookieList: MutableList = ArrayList(cookies.size)
        val sb = StringBuilder()
        cookies.forEach {
            sb.append(it.name).append('=').append(it.value)
            cookieList.add(sb.toString())
            sb.delete(0, sb.length)
        }

        this[SpringHeaders.COOKIE] = cookieList
    }
}


/**
 * 基于 [org.springframework.web.client.RestTemplate] 的 [love.forte.simbot.http.template.HttpTemplate] 实现。
 *
 * 需要注意的是,由于使用的是spring的rest template,因此相关配置都优先使用你自己的配置。例如 `timeout`。
 *
 * @author ForteScarlet
 */
@SpareBeans
class RestTemplateHttpTemplate(private val restTemplate: RestTemplate) : BaseHttpTemplate() {

    /**
     * get请求。
     * @param responseType 响应body封装类型。
     * @param headers 请求头信息。
     * @param requestParam 请求参数。
     */
    override fun  get(
        url: String,
        headers: HttpHeaders?,
        cookies: HttpCookies?,
        requestParam: Map?,
        responseType: Class,
    ): HttpResponse {
        val entity: ResponseEntity
        val headerEmpty = headers == null || headers.isEmpty()

        val headers0: HttpHeaders = if (!headerEmpty) {
            headers as HttpHeaders
        } else {
            HttpHeaders.instance
        }
        headers0.setUserAgentChromeIfAbsent()

        val spHeaders = SpringHeaders()
        spHeaders.putAll(headers0)
        spHeaders.cookies(cookies)


        val requestEntity = HttpEntity(spHeaders)

        entity = restTemplate.exchange(url,
            HttpMethod.GET,
            requestEntity,
            responseType,
            requestParam ?: emptyMap())

        return RestHttpResponse(entity)
    }

    /**
     * post请求。
     * @param responseType 响应body封装类型。
     * @param headers 请求头信息。
     * @param requestBody 请求参数。
     */
    override fun  post(
        url: String,
        headers: HttpHeaders?,
        cookies: HttpCookies?,
        requestBody: Any?,
        responseType: Class,
    ): HttpResponse {
        val headerEmpty = headers == null || headers.isEmpty()
        val spHeaders = SpringHeaders()
        spHeaders.contentType = MediaType.APPLICATION_JSON

        if (!headerEmpty) {
            // set content type as application/json
            headers as HttpHeaders
            spHeaders.putAll(headers)
        }
        spHeaders.cookies(cookies)


        val entity = restTemplate.postForEntity(url, HttpEntity(requestBody, spHeaders), responseType)
        return RestHttpResponse(entity)
    }

    /**
     * post/form 请求。
     * @param responseType 响应body封装类型。
     * @param headers 请求头信息。
     * @param requestForm 请求参数,一个对象实例,此对象实例只会获取其中一层字段值作为表单提交,不会像json那样嵌套获取。如果字段对应的是一个其他的实例,则会直接获取其toString的值。
     */
    override fun  form(
        url: String,
        headers: HttpHeaders?,
        cookies: HttpCookies?,
        requestForm: Map?,
        responseType: Class,
    ): HttpResponse {
        val headerEmpty = headers == null || headers.isEmpty()
        val spHeaders = SpringHeaders()
        // application/x-www-form-urlencoded
        spHeaders.contentType = MediaType.APPLICATION_FORM_URLENCODED

        if (!headerEmpty) {
            // set content type as application/json
            headers as HttpHeaders
            spHeaders.putAll(headers)
        }
        spHeaders.cookies(cookies)

        val entity = restTemplate.postForEntity(url, HttpEntity(requestForm, spHeaders), responseType)
        return RestHttpResponse(entity)
    }

    /**
     * 使用请求实例请求。
     * 如果 [request.type][HttpRequest.type] 为 [get][HttpRequestType.GET] 或者 [form][HttpRequestType.FORM],
     * 则 [request.requestParam][HttpRequest.requestParam] 应该为 `Map?` 类型实例。
     */
    override fun  request(request: HttpRequest): HttpResponse {
        val entity = runBlocking { doRequest(Request(request)) }
        return RestHttpResponse(entity)
    }


    private suspend fun  requestSuspend(request: HttpRequest): HttpResponse {

        // cookies
        val entity = doRequest(Request(request))
        return RestHttpResponse(entity)

    }


    private suspend fun  doRequest(req: Request): ResponseEntity {
        return suspendCoroutine {
            Dispatchers.Default.dispatch(it.context) {
                it.resumeWith(runCatching { restTemplate.exchange(req.url, req.method, req.entity, req.responseType) })
            }
        }
    }

    /**
     * 请求多个,其中,如果 [HttpRequest.responseType] 为null,则其请求结果将不会出现返回值中。
     *
     * 如果[parallel] 为true,则应并行请求[requests]并按照顺序同步返回最终结果。如果为false,则按照顺序依次阻塞请求所有。
     *
     * @param parallel 是否异步请求。
     * @return 全部的响应结果,其顺序为 [requests] 中的顺序。
     */
    @OptIn(DelicateCoroutinesApi::class)
    override fun requestAll(parallel: Boolean, vararg requests: HttpRequest<*>): List> {
        return if (parallel) {
            requests.map {
                GlobalScope.async { requestSuspend(it) }
            }.map { runBlocking { it.await() } }
        } else {
            requests.map { request(it) }
        }
    }


}
@JvmInline
private value class Request(val request: HttpRequest) {
    val url: String get() = request.url

    val method: HttpMethod
        get() = when (request.type) {
            HttpRequestType.GET -> HttpMethod.GET
            HttpRequestType.POST -> HttpMethod.POST
            HttpRequestType.FORM -> HttpMethod.POST
        }

    val media: MediaType?
        get() = when (request.type) {
            HttpRequestType.GET -> null
            HttpRequestType.POST -> MediaType.APPLICATION_JSON
            HttpRequestType.FORM -> MediaType.APPLICATION_FORM_URLENCODED
        }

    val springHeaders: SpringHeaders
        get() {
            val spHeaders = SpringHeaders()
            media?.also {
                spHeaders.contentType = it
            }
            (request.headers ?: HttpHeaders.instance).also {
                it.setUserAgentChromeIfAbsent()
                spHeaders.putAll(it)
            }

            spHeaders.cookies(request.cookies)

            return spHeaders
        }

    val entity: HttpEntity<*>
        get() = HttpEntity(request.requestParam, springHeaders)

    val responseType get() = request.responseType
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy