在前面2篇文章使用 Kotlin 和Spring Boot 2.0快速開發REST API接口和使用 Kotlin 和Spring Boot 2.0快速開發REST API客戶端介紹瞭如何使用簡單代碼快速實現REST API的服務端接口及客戶端應用。java
此文簡單介紹如何使用Postman快速完成REST API接口的數據交互及調試工做,Postman的下載地址:https://www.getpostman.com/git
就像其主頁上說明的同樣,Postman能讓API的開發工做更加簡單高效,建議作API開發尚未用過Postman的同窗嚐嚐鮮。數組
回到正題,實現數據交互,咱們須要在REST API服務端實現針對不一樣類型HTTP請求的響應機制,其中常見的HTTP請求類型包括GET,POST,DELETE,PUT等,前面咱們的接口僅實現了針對不帶參數的GET類型請求的響應機制,如今咱們先看看含參數的GET請求如何處理。服務器
GET類型HTTP請求傳遞參數有以下2種方式,可分別經過request.pathVariable("id")或者request.queryParam("id")獲取到傳入的參數值:app
請求路徑格式參考框架 |
傳參方式函數 |
Kotlin響應函數post |
「/get/XXX」 | URL路徑變量 | GET("/get/{id}") { request -> ServerResponse.ok().body(bookRepository.findById(request.pathVariable("id")))} |
「/get?id=XXX」 | FORM表單參數 | GET("/get") { request -> val id = request.queryParam("id") ServerResponse.ok().body(bookRepository.findById(id.get())) } |
實現以上接口函數的方法後,能夠簡單經過Postman提交以下2個測試請求:測試
http://localhost:8080/book/get/5b976f860dded66908723462spa
http://localhost:8080/book/get?id=5b976f860dded66908723462
兩次請求獲取到的結果相同,具體參考以下截圖:
POST類型HTTP請求傳遞參數有以下2種方式,獲取參數值的方法參見下表:
請求路徑格式參考 |
傳參方式 |
Kotlin獲取參數值的方法 |
「/add?name=XXX」 | FORM表單參數 | request.queryParam("name") |
"/add" | Request Body | 獲取多個同類型Java對象參數值:request.bodyToFlux(Book::class.java) 獲取單個Java對象參數值:request.bodyToMono(Book::class.java) |
以上2種傳參方式的區別在於FORM表單參數僅支持簡單類型參數傳值,而Request Body可經過JSON格式傳遞複雜類型數據到服務端,Spring WebFlux框架會自動將JSON格式的入參轉化爲指定類型的實體bean,若是傳入的是多個Book類型對象的數組,能夠用request.bodyToFlux(Book::class.java)將其轉化爲Book類型元素的Flux流再作後續處理,若是傳入的是單個Book類型對象,能夠用request.bodyToMono(Book::class.java)將其轉化爲Book類型元素的Mono流作後續處理。
如下咱們聲明一個RestBookHandler對象來受理來自REST API的POST請求:
@Component class RestBookHandler(val bookRepository: BookRepository) { fun saveBook(request: ServerRequest): Mono<ServerResponse> = request.bodyToMono(Book::class.java) .flatMap { bookRepository.save(it) } .flatMap { it -> ServerResponse.ok().body(fromObject(it)) } }
受理POST請求的動做分解以下:
步驟1:request.bodyToMono(Book::class.java), 將傳入的Request Body 中的JSON字符串轉化爲Book類型的Mono流;
步驟2:flatMap { bookRepository.save(it) },保存Mono流內的Book對象;
步驟3:flatMap { it -> ServerResponse.ok().body(fromObject(it)) },將保存後的Book對象返回給調用者。
在主函數的beans框架內添加以下部分聲明一個名稱爲postHandler的bean處理來自/add路徑的POST請求,接收到的請求交給bookResthandler對象的saveBook方法進行處理:
bean("postHandler") { val bookRestHandler = ref<RestBookHandler>() router { POST("/add", bookRestHandler::saveBook) } }
經過Postman提交以下測試請求:
請求類型 | HTTP POST |
請求URL | http://localhost:8080/add |
Request Body(JSON格式串) | { "name":"Postman提交書籍", "author":"Michael Chen", "publish":"2018-09-11T13:49:00.000+0000" } |
服務器接受到Postman提交的請求後,正常執行相應過程返回的結果以下:
彙總以上實現的GET及POST方法,不帶參數和帶參數的方法,整個KotlinAppApplication.kt文件的代碼以下:
@SpringBootApplication class KotlinAppApplication interface BookRepository : ReactiveMongoRepository<Book, String> @Document data class Book(val id: ObjectId?, val name: String, val author: String, val publish: Date) fun main(args: Array<String>) { runApplication<KotlinAppApplication>(*args) { addInitializers( beans { bean("postHandler") { val bookRestHandler = ref<RestBookHandler>() router { POST("/add", bookRestHandler::saveBook) } } bean { val bookRepository = ref<BookRepository>() val interval = Flux.interval(Duration.ofMillis(100)) router { (accept(TEXT_HTML) and "/book").nest { GET("/list") { ServerResponse.ok().contentType(MediaType.TEXT_EVENT_STREAM) .body(Flux.zip(interval, bookRepository.findAll()).map { entry -> entry.t2 }) } GET("/get/{id}") { request -> ServerResponse.ok().body(bookRepository.findById(request.pathVariable("id"))) } GET("/get") { request -> val id = request.queryParam("id") ServerResponse.ok().body(bookRepository.findById(id.get())) } } } } bean { val bookRepository = ref<BookRepository>() ApplicationRunner { bookRepository.deleteAll() .thenMany(Flux.fromStream(Stream.generate { ObjectId.get() }.limit(10))) .map { Book(it, "Spring 空間", "Michael Chen", Date()) } .flatMap { bookRepository.save(it) } .thenMany(bookRepository.findAll()) .subscribe { println(it) } } } } ) } }
經過以上樣例能夠看出,在結合Kotlin和Spring Boot 2.0的基礎上,開發一個REST API接口能夠有更多靈活的方案,而不用拘泥於@RestController的方式。
以上示例代碼下載地址:https://gitee.com/chenbichao/kotlin-app