• 使用 Kotlin 协程 + Retrofit2 调用 REST API


    JSON : Placeholder

    JSON : Placeholder (https://jsonplaceholder.typicode.com/) 是一个用于测试的 REST API 网站。
    以下使用 Kotlin 协程 + Retrofit2 调用该网站的 REST API,获取字符串以及 JSON 数据。

    • GET /posts/1
    • GET /posts
    • POST /posts
    • PUT /posts/1
    • DELETE /posts/1

    所有 GET API 都返回JSON数据,格式(JSON-Schema)如下:

    {
      "type":"object",
      "properties": {
        "userId": {"type" : "integer"},
        "id": {"type" : "integer"},
        "title": {"type" : "string"},
        "body": {"type" : "string"}
      }
    }
    

    创建工程

    打开 Intellij IDEA,File / New / Project...
    在 New Project 向导的第1页,选 Kotlin, Project Template 选 JVM Application,Build System 选 Gradle Kotlin,Project JDK 选 1.8。
    在向导的第2页 Template 选 Console Application
    点击 Finish 按钮创建工程

    build.gradle.kts 内容如下

    import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
    
    plugins {
        kotlin("jvm") version "1.4.32"
        application
    }
    
    group = "me.xxxx"
    version = "1.0-SNAPSHOT"
    
    repositories {
        mavenCentral()
    }
    
    dependencies {
        testImplementation(kotlin("test-junit"))
    }
    
    tasks.test {
        useJUnit()
    }
    
    tasks.withType<KotlinCompile>() {
        kotlinOptions.jvmTarget = "1.8"
    }
    
    application {
        mainClassName = "MainKt"
    }
    

    将 dependencies 这部分的内容改为:

    dependencies {
        testImplementation(kotlin("test-junit"))
        val retrofitVersion = "2.9.0"
        implementation("com.squareup.retrofit2:retrofit:$retrofitVersion")
        implementation("com.squareup.retrofit2:converter-gson:$retrofitVersion")
        implementation("com.squareup.retrofit2:converter-scalars:$retrofitVersion")
        implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.3-native-mt")
    }
    

    这一段引用了 Kotlin 协程和 Retrofit 这两个库。
    其中 Retrofit 这个库中还包含了 Gson 和字符串的转换器。

    Post 对象

    jsonschema2pojo 可以将 JSON 数据或格式自动转换为 Java 的 POJO 类。

    data class Post(val userId: Int, val id: Int, val title: String, val body: String) {
        override fun toString() =
            "Post {userId = $userId, id = $id, title = "$title", body = "${body.replace("
    ", "\n")}"}"
    }
    

    Post 对象负责 Kotlin 对象与 JSON 数据之间的相互转换。
    由于两者字段名相同,这里不需要使用注解。

    // 如果需要加上注解的话
    data class Post(@SerializedName("userId") val userId: Int,
                    @SerializedName("id") val id: Int,
                    @SerializedName("title") val title: String,
                    @SerializedName("body") val body: String) {
    // ...
    }
    

    Retrofit 接口

    interface RestPost {
        @GET
        suspend fun getPostAsString(@Url url: String): String
        @GET("posts/{id}")
        suspend fun getPostAsJson(@Path("id") id: Int): Post
        @GET("posts")
        suspend fun getPosts(): List<Post>
        @FormUrlEncoded
        @POST("posts")
        suspend fun createPost(@Field("userId") userId: Int,
                       @Field("title") title: String,
                       @Field("body") body: String): Post
        @FormUrlEncoded
        @PUT("posts/{id}")
        suspend fun updatePost(@Field("userId") userId: Int,
                       @Path("id") id: Int,
                       @Field("title") title: String,
                       @Field("body") body: String): Post
        @DELETE("posts/{id}")
        suspend fun deletePost(@Path("id") id: Int): String
    }
    

    Retrofit 库使用专用接口调用 REST API。

    • 接口中的每一个方法都对应于一种 API 调用。
    • 注解 @GET @POST @PUT @DELETE 表示 API 调用时所使用的 HTTP 方法。
    • 注解 @GET 中带的值表示 API 调用时所包含的相对路径,其中可包含路径变量。
      "posts/{id}" 中的 {id} 为路径变量。
    • 注解 @Url 表示参数为路径。
    • 注解 @Path("id") 表示参数为路径变量。
    • 注解 @Field 表示参数为 HTTP 请求体中的键值对。
    • 使用注解 @Field 的方法必须加上注解 @FormUrlEncoded。

    Retrofit 对象

    val retrofitJson: Retrofit = Retrofit.Builder()
        .baseUrl("https://jsonplaceholder.typicode.com/")
        .addConverterFactory(GsonConverterFactory.create())
        .build()
    val retrofitString: Retrofit = Retrofit.Builder()
        .baseUrl("https://jsonplaceholder.typicode.com/")
        .addConverterFactory(ScalarsConverterFactory.create())
        .build()
    
    • retrofitJson 对象用于处理 REST API 所返回的 JSON 数据。
    • retrofitString 对象用于处理 REST API 所返回的字符串数据。

    调用 REST API

    suspend fun getPostAsString(): String =
        retrofitString.create(RestPost::class.java)
            .getPostAsString("posts/1")
    
    suspend fun getPostAsJson(): Post =
        retrofitJson.create(RestPost::class.java)
            .getPostAsJson(1)
    
    suspend fun getPosts(n: Int): List<Post> =
        retrofitJson.create(RestPost::class.java)
            .getPosts().take(n)
    
    suspend fun createPost(): Post =
        retrofitJson.create(RestPost::class.java)
            .createPost(101, "test title", "test body")
    
    suspend fun updatePost(): Post =
        retrofitJson.create(RestPost::class.java)
            .updatePost(101, 1, "test title", "test body")
    
    suspend fun deletePost(): String =
        retrofitString.create(RestPost::class.java)
            .deletePost(1)
    
    • getPostAsString 函数取出第1个Post,返回字符串
    • getPostAsJson 函数取出第1个Post,返回Post对象
    • getPosts 函数取出前n个Post,返回n个Post对象
    • createPost 函数创建1个Post,返回所创建的Post对象
    • updatePost 函数更新第1个Post,返回所更新的Post对象
    • deletePost 函数删除第1个Post,返回字符串

    main 函数

    fun main(args: Array<String>) = runBlocking {
        println(getPostAsString())
        println(getPostAsJson())
        println(getPosts(2))
        println(createPost())
        println(updatePost())
        println(deletePost())
    }
    

    输出结果

    {
      "userId": 1,
      "id": 1,
      "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
      "body": "quia et suscipit
    suscipit recusandae consequuntur expedita et cum
    reprehenderit molestiae ut ut quas totam
    nostrum rerum est autem sunt rem eveniet architecto"
    }
    Post {userId = 1, id = 1, title = "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", body = "quia et suscipit
    suscipit recusandae consequuntur expedita et cum
    reprehenderit molestiae ut ut quas totam
    nostrum rerum est autem sunt rem eveniet architecto"}
    [Post {userId = 1, id = 1, title = "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", body = "quia et suscipit
    suscipit recusandae consequuntur expedita et cum
    reprehenderit molestiae ut ut quas totam
    nostrum rerum est autem sunt rem eveniet architecto"}, Post {userId = 1, id = 2, title = "qui est esse", body = "est rerum tempore vitae
    sequi sint nihil reprehenderit dolor beatae ea dolores neque
    fugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis
    qui aperiam non debitis possimus qui neque nisi nulla"}]
    Post {userId = 101, id = 101, title = "test title", body = "test body"}
    Post {userId = 101, id = 1, title = "test title", body = "test body"}
    {}
    
  • 相关阅读:
    进击Node.js基础(一)
    关于bootstrap两个模态框的问题
    系列博文-Three.js入门指南(张雯莉)-网格 setInterval方法 requestAnimationFrame方法 使用stat.js记录FPS
    系列博文-Three.js入门指南(张雯莉)-照相机
    系列博文-Three.js入门指南(张雯莉)-静态demo和three.js功能概览
    for循环执行效率
    c/c++多维数组动态分配与释放
    C/C++数组指针与指针数组详解
    C/C++语言参数传递----值传递、引用传递、指针传递、指针引用传递
    float类型最大值和最小值
  • 原文地址:https://www.cnblogs.com/zwvista/p/14613060.html
Copyright © 2020-2023  润新知