tamuraです。

今回はDropwizardでデータベースを参照していきます。


pom.xml

以下の記述をpom.xmlに追加します。

<dependency>  
  <groupId>io.dropwizard</groupId>
  <artifactId>dropwizard-jdbi</artifactId>
  <version>${dropwizard.version}</version>
</dependency>

<dependency>  
  <groupId>com.github.tamurashingo.dbutil3</groupId>
  <artifactId>dbutil3</artifactId>
  <version>0.1.0</version>
</dependency>  

DAOの作成

まずはDAOのinterfaceを作成します。 messageIdを渡すとそれに対応したSayingを返すDAOを定義します。

package com.github.tamurashingo.dropwizard.helloworld.dao;

import com.github.tamurashingo.dropwizard.helloworld.Saying;  
import com.google.common.base.Optional;

public interface MessageDAO {

    public Optional<Saying> getMessage(String messageId);

}

続いてMySQL用の実装を作成します。 具体的にSQLを書いていきます。

package com.github.tamurashingo.dropwizard.helloworld.dao.impl;

import org.skife.jdbi.v2.sqlobject.Bind;  
import org.skife.jdbi.v2.sqlobject.SqlQuery;  
import org.skife.jdbi.v2.sqlobject.customizers.Mapper;  
import org.skife.jdbi.v2.sqlobject.customizers.SingleValueResult;

import com.github.tamurashingo.dropwizard.helloworld.Saying;  
import com.github.tamurashingo.dropwizard.helloworld.dao.MessageDAO;  
import com.github.tamurashingo.dropwizard.helloworld.dao.impl.mapper.SayingMapper;  
import com.google.common.base.Optional;

public interface MessageDAOMySQLImpl extends MessageDAO {

    @Override
    @SingleValueResult(Saying.class)
    @SqlQuery(
              " select "
            + "   message "
            + " from "
            + "   m_message "
            + " where "
            + "   id = :messageId "
    )
    @Mapper(SayingMapper.class)
    public Optional<Saying> getMessage(@Bind("messageId") String messageId);

}

以下の3つのアノテーションでどのようなSQLが実行されてどのような結果を返すかを定義しています。

  • @SingleValueResult
  • @SqlQuery
  • @Mapper

余談ですが、リスト(List<Saying>)を返したい場合は、@SingleValueResultのアノテーションを外すだけで大丈夫です。

続いて、SQLの結果をJavaBeanにするマッパーを定義します。 これは拙作のDBUtils3を(わざわざ)使います。

Mapperは毎回インスタンスが生成されるようなので、BeanBuilderstaticで持つようにしています。

package com.github.tamurashingo.dropwizard.helloworld.dao.impl.mapper;

import java.sql.ResultSet;  
import java.sql.SQLException;

import org.skife.jdbi.v2.StatementContext;  
import org.skife.jdbi.v2.tweak.ResultSetMapper;

import com.github.tamurashingo.dbutils3.BeanBuilder;  
import com.github.tamurashingo.dbutils3.BeanBuilderException;  
import com.github.tamurashingo.dropwizard.helloworld.Saying;

public class SayingMapper implements ResultSetMapper<Saying> {

    private static final BeanBuilder builder;

    static {
        builder = new BeanBuilder(Saying.class);
    }

    @Override
    public Saying map(int index, ResultSet r, StatementContext ctx) throws SQLException {
        try {
            Saying saying = builder.build(r);
            return saying;
        }
        catch (BeanBuilderException ex) {
            throw new SQLException(ex);
        }
    }

}

Resource

ResourceでDAO使うため、コンストラクタでDAOを受け取るように変更します。
また、messageIdが渡されなかったりデータベースに値がなかったときのために初期値を作っています。

package com.github.tamurashingo.dropwizard.helloworld;

import javax.ws.rs.GET;  
import javax.ws.rs.Path;  
import javax.ws.rs.Produces;  
import javax.ws.rs.QueryParam;  
import javax.ws.rs.core.MediaType;

import com.github.tamurashingo.dropwizard.helloworld.dao.MessageDAO;  
import com.google.common.base.Optional;

@Path("/hello-world")
@Produces(MediaType.APPLICATION_JSON)
public class HelloWorldResource {

    private MessageDAO messageDAO;
    private Saying defaultValue = new Saying("hello world");

    public HelloWorldResource(MessageDAO messageDAO) {
        this.messageDAO = messageDAO;
    }

    @GET
    public Saying sayHello(@QueryParam("messageid") Optional<String> messageId) {
        if (messageId.isPresent()) {
            return messageDAO.getMessage(messageId.get()).or(defaultValue);
        }
        else {
            return defaultValue;
        }
    }
}

SayingBeanBuilderを使うにあたり、

  • @Column
  • setter

が必要なので変更します。

package com.github.tamurashingo.dropwizard.helloworld;

import com.fasterxml.jackson.annotation.JsonProperty;  
import com.github.tamurashingo.dbutils3.Column;

public class Saying {

    @Column("message")
    private String greeting;

    public Saying() {
    }

    public Saying(String greeting) {
        this.greeting = greeting;
    }

    @JsonProperty
    public String getGreeting() {
        return this.greeting;
    }

    public void setGreeting(String greeting) {
        this.greeting = greeting;
    }
}

Application

最後にApplicationを修正します。 DAOの生成などを追加しています。

package com.github.tamurashingo.dropwizard.helloworld;

import org.skife.jdbi.v2.DBI;

import com.github.tamurashingo.dropwizard.helloworld.dao.MessageDAO;  
import com.github.tamurashingo.dropwizard.helloworld.dao.impl.MessageDAOMySQLImpl;

import io.dropwizard.Application;  
import io.dropwizard.db.DataSourceFactory;  
import io.dropwizard.jdbi.DBIFactory;  
import io.dropwizard.migrations.MigrationsBundle;  
import io.dropwizard.setup.Bootstrap;  
import io.dropwizard.setup.Environment;

public class HelloWorldApplication extends Application<HelloWorldConfiguration> {

    public static void main(String...args) throws Exception {
        new HelloWorldApplication().run(args);
    }

    @Override
    public void initialize(Bootstrap<HelloWorldConfiguration> bootstrap) {
        bootstrap.addBundle(new MigrationsBundle<HelloWorldConfiguration>() {
            @Override
            public DataSourceFactory getDataSourceFactory(HelloWorldConfiguration configuration) {
                return configuration.getDataSourceFactory();
            }
        });
    }

    @Override
    public void run(HelloWorldConfiguration configuration, Environment environment) throws Exception {
        final DBIFactory factory = new DBIFactory();
        final DBI jdbi = factory.build(environment, configuration.getDataSourceFactory(), "helloworlddb");
        final MessageDAO messageDAO = jdbi.onDemand(MessageDAOMySQLImpl.class);

        environment.jersey().register(new HelloWorldResource(messageDAO));
    }
}

実行

$ mvn clean package
$ java -jar target/helloworld-0.0.1-SNAPSHOT.jar server hello-world.yml

でサーバが実行します。

http://localhost:8080/hello-world

にアクセスすると初期値である

{"greeting":"hello world"}

が表示されます。

http://localhost:8080/hello-world?messageid=00002

にアクセスするとデータベースに格納した値の

{"greeting":"こんにちは"}

が表示されます。