使用Kotlin + Jersey + Jetty + MongoDB建立可擴充套件的RESTful API - Andrew

banq發表於2020-03-07

這種組合可以像其他任何servlet應用程式一樣擴充套件,同時也可以部署到其他伺服器,例如Tomcat。與Node.js之類的東西相比,我更喜歡伺服器端的Kotlin。儘管它需要更多的初始設定,但您以後可以使用它,因此會大大受益。對我們來說,最重要的兩件事是正確的多執行緒支援以及正確構建程式碼的固有需求。
我們使用Jetty為公司中的多個Web應用程式提供服務。為了易於使用和部署,Jetty會永久安裝在我們的伺服器上,我們不會將其嵌入到webapp本身中。

1.建立一個Kotlin專案。我們使用Gradle,但是您可以根據需要使用Maven。您也可以使用我的模板

2.除了通常的依賴關係之外,這還需要依賴關係的列表:

dependencies {    
    compile 'org.mongodb:mongodb-driver-sync:3.10.0'    
    compile 'org.litote.kmongo:kmongo:3.9.2'    
    compile 'org.litote.kmongo:kmongo-id-jackson'    
    compile 'org.litote.kmongo:kmongo-id:3.9.2'
    compile 'org.glassfish.jersey.core:jersey-server:2.30'    
    compile 'org.glassfish.jersey.containers:jersey-container-servlet:2.30'
    compile 'org.glassfish.jersey.inject:jersey-hk2:2.30'    
    compile 'org.glassfish.jersey.media:jersey-media-json-jackson:2.30'
}


3.建立一個web.xml在src/main/webapp/WEB-INF/web.xml
4.使用此程式碼段填充您的web.xml。將%%替換為您的資訊。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
    <display-name>%%YourProjectName%%</display-name>
    <servlet>
        <servlet-name>Jersey REST Service</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>jersey.config.server.provider.packages</param-name>
            <param-value>%%your.package.here%%</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Jersey REST Service</servlet-name>
        <url-pattern>/api/*</url-pattern>
    </servlet-mapping>
</web-app>


5.我們需要註冊@Provider的KMongo。這將確保JSON物件與KMongo我們接下來建立的資料類之間的轉換是無縫的。建立一個KMongoProvider.kt並使用以下程式碼:

@Provider
class KMongoProvider : ContextResolver<ObjectMapper> {
    override fun getContext(type: Class<*>): ObjectMapper {
        return KMongoJackson.mapper
    }
}

object KMongoJackson {
    val mapper = jacksonObjectMapper()

    init {
        mapper.registerModule(IdJacksonModule())
    }
}

6.讓我們連線到資料庫並建立一個資料模型:

class Connect {
    companion object {
        val client = KMongo.createClient()
        val database = client.getDatabase("kotlin-example")
    }
}

data class Dog (
        @BsonId var _id: StringId<Dog> = newStringId(),
        var owner: String,
        var name: String,
        var bornAt: Int,
        var lastVaccineAt: Int?
) {
    companion object

    fun collection(): MongoCollection<Dog> {
        return Connect.database.getCollection<Dog>("dogs")
    }
}


7.現在我們需要為我們的Dog類提供資源。它將告訴Jersey如何與模型進行互動,並將為API訪問公開模型:

@Path("dogs")
@Produces(APPLICATION_JSON)
class DogResource {

    @GET
    fun listDogs(): MongoIterable<Dog> {
        return Dog.collection().find().map { it }
    }

    @POST
    fun createDog(token: Dog) {
        Dog.collection().save(token)
    }

    @GET
    @Path("{id}")
    fun getDog(@PathParam("id") id: String): Dog? {
        return Dog.collection().findById(id)
    }

    @PUT
    @Path("{id}")
    fun updateDog(@PathParam("id") id: String, dog: Dog) {
        dog._id = StringId(id)
        Dog.collection().replaceById(id, dog)
    }

    @DELETE
    @Path("{id}")
    fun deleteDog(@PathParam("id") id: String): Boolean {
        return Dog.collection().deleteById(id).deletedCount > 0
    }

}

該listDogs()方法不使用任何引數,而是使用我們為DogResource定義的路徑。createDog()方法輸入引數是JSON,與資料模型匹配但沒有_id金鑰。嘗試傳送錯誤格式的,JSON以檢視其行為。該get / update / delete方法適用於*/dogs/{id}/。

8.我使用下面列出的擴充套件功能輕鬆地透過id查詢/替換內容。建立一個DBUtility.kt並將函式放入其中。

fun <T> MongoCollection<T>.findById(id: String): T? {
    return this.findOneById(StringId<T>(id))
}

fun <T> MongoCollection<T>.deleteById(id: String): DeleteResult {
    return this.deleteOneById(StringId<T>(id))
}

fun <T> MongoCollection<T>.replaceById(id: String, newObject: T): UpdateResult {
    return this.replaceOne(KMongoUtil.idFilterQuery(StringId<T>(id)), newObject)
}


9.現在進行測試。我使用Postman傳送POST請求到localhost:8080/api/dogs/。內容如下:

{
    "owner": "John Doe",
    "name": "Good Boy",
    "bornAt": 1583158516
}


現在,您可以在幾分鐘內新增任意數量的資源,而無需為此做太多事情。您還可以使用自定義路徑並定義所需的任何方法,Jersey將始終為您處理解析和實際servlet建立。

相關文章