Java
undertow

SidenでRestサービスとDBアクセス

More than 3 years have passed since last update.

Siden

https://github.com/taichi/siden
Hello Worldやったので、
http://qiita.com/masatsugumatsus/items/c07e13f81fea12fa590e

次は、RestとDBアクセス

Entity

Lombok使えって話しだが。。。

Book.java
import java.io.Serializable;

public class Book implements Serializable{  

    /**
     * 
     */
    private static final long serialVersionUID = 6484020759599047569L;

    private String isbn;
    private String name;

    public String getIsbn() {
        return isbn;
    }
    public void setIsbn(String isbn) {
        this.isbn = isbn;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

Resouceクラス

bodyの取り出し方が分かりません。。。
JsonライブラリはなれているからGsonを使う

BookResource.java
import java.io.IOException;
import java.nio.ByteBuffer;

import ninja.siden.App;
import ninja.siden.Renderer;
import ninja.siden.Request;

import org.skife.jdbi.v2.DBI;
import org.skife.jdbi.v2.Handle;
import org.xnio.channels.StreamSourceChannel;

import com.google.gson.Gson;

public class BookResource  {

        private App app;
    private DBI dbi;
    private Gson gson = new Gson();

    public BookResource(App app, DBI dbi) {
        this.app = app;
        this.dbi = dbi;
    }

    @Override
    public void defineRoutes() {

        app.post(
                "/books",
                (req, res) -> {
                    String body = body(req);
                    Book book = gson.fromJson(body, Book.class);;
                    try (Handle h = dbi.open()) {
                        h.execute(
               "MERGE INTO book(isbn, name) VALUES(?, ?)",
               book.getIsbn(),
               book.getName());
                    }
                    return book;
                }).render(Renderer.of(gson::toJson))
                .type("application/json");;

        app.get("/books/:isbn",
                (req, res) -> {
                    return req.params("isbn")
                            .map(isbn -> {
                                Book b = null;
                                try (Handle h = dbi.open()) {
                                    b = h.createQuery(                                                      "SELECT isbn,name "
                                  +"FROM book WHERE isbn=:isbn")
                                    .bind("isbn", isbn).map(Book.class)
                                    .first();

                                }
                                return b;
                        }).orElseThrow(ResouceNotFoundException::new);
                }).render(Renderer.of(gson::toJson))
                 .type("application/json");
                  }

    private  String body(Request req) {
        int size = (int) req.raw().getRequestContentLength();
        ByteBuffer buff = ByteBuffer.allocate(size);
        try (StreamSourceChannel reqChannel = req.raw().getRequestChannel()) {
            reqChannel.read(buff);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }

        return new String(buff.array());

    }
}

main

Application.java
import javax.sql.DataSource;

import ninja.siden.App;

import org.h2.jdbcx.JdbcConnectionPool;
import org.skife.jdbi.v2.DBI;
import org.skife.jdbi.v2.Handle;

public class Application {
    public static void main(String[] args) {
        DataSource ds = JdbcConnectionPool.create("jdbc:h2:mem:test",
                "username",
                "password");
        DBI dbi = new DBI(ds);

        init(dbi);

        App app = new App();
        new BookResource(app,dbi).defineRoutes();

        app.listen();   
    }

    private static void init(DBI dbi) {
        try(Handle h = dbi.open()){
        h.execute("create table book(isbn varchar(11) primary key, name varchar(100))");
        }
    }
}

テスト

BookResourceSpec.groovy
package com.sidensample.mm;


import javax.sql.DataSource;

import org.h2.jdbcx.JdbcConnectionPool;
import org.skife.jdbi.v2.DBI;
import org.skife.jdbi.v2.Handle;

import groovyx.net.http.RESTClient
import ninja.siden.App
import spock.lang.Ignore;
import spock.lang.Shared
import spock.lang.Specification

class BookResourceSpec extends Specification {

    @Shared stop
    def endpoint = new RESTClient( 'http://localhost:8080/' )

    def setupSpec(){
        DataSource ds = JdbcConnectionPool.create("jdbc:h2:mem:test",
                "username",
                "password");
        DBI dbi = new DBI(ds);
        Handle h = dbi.open();
        h.execute("create table book(isbn varchar(11) primary key, name varchar(100))");
        h.execute("insert into book(isbn, name) values (?, ?)", "1234", "ほんの名前");

        h.close();

        def app = new App()


        new BookResource(app,dbi).defineRoutes()
        stop = app.listen()
    }

    def "postのテスト"(){
        when:

        def resp=endpoint.post([ path: 'books',
            body:[isbn:"1234",name:"abcd"],
            requestContentType:"application/json"
        ])

        def resp2=endpoint.get([ path: 'books/1234'])

        then:
        with(resp) {
            status == 200
            data.isbn == "1234"
            data.name == "abcd"
        }
        with(resp2) {
            status == 200
            data.isbn == "1234"
            data.name == "abcd"
        }
    }

    def cleanupSpec(){
        stop.stop()
    }
}

Dropwizardよりも簡単なのは凄いな。microserviceにはいけるんではないか。

要望

・管理用の別ポート設定(多分できるけど、もう少し簡単に。。。)
・body部取得の方法(自信ない。。。)
・静的コンテンツをClasspathResourceでアクセスして欲しい。