###まえがき
いまどきのフレームワークを使用してWebAPIを作成してみる。
ということで、巷で話題のDropwizardにチャレンジしてみたので備忘録として書き留める。
ところで、Dropwizardは、mavenを使用しているためmavenの知識も必要である。
gradleなどで構築している事例もあったので全体像を掴めば構築可能と思われるが、
入門のためmavenを使用して先に進める。
###mavenプロジェクトの作成
まずは、mavenプロジェクトとして新規プロジェクトを作成する。
グループIdは、本来はドメイン利用した一意名にするのが正と思われるが、
ここではテスト用に仮パッケージ名としている。
また、アーティファクトId:についてもsampleAppとした。
開発環境には、Pleiades All in One 4.4 (Luna) を利用させていただいているが、
この環境下ではデフォルトがJ2SE1.5利用となっているためJava7に変更する。
Javaビルド・パスからライブラリータブを選択し、編集をクリック。
JavaSE-1.7(java7)を選択し、完了を押してダイアログを閉じる。
OKボタンを押してプロパティウィンドウを閉じると自動ビルドが行われ先ほどの警告が消える。
####pom.xmlの編集
以下の条件により、pom.xml を編集する。
・Hibernateを使用してMySQLと接続する。
・jarファイルを同包したjarファイルを作成する。
・依存するライブラリも一緒にjarファイルに含める。
<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.examples</groupId>
<artifactId>sampleApp</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>sampleApp</name>
<properties>
<dropwizard.version>0.7.1</dropwizard.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.6</version>
<configuration>
<createDependencyReducedPom>true</createDependencyReducedPom>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation=
"org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
<transformer implementation=
"org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.examples.sampleApp.SampleApp</mainClass> </transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>io.dropwizard</groupId>
<artifactId>dropwizard-core</artifactId>
<version>${dropwizard.version}</version>
</dependency>
<dependency>
<groupId>io.dropwizard</groupId>
<artifactId>dropwizard-hibernate</artifactId>
<version>${dropwizard.version}</version>
</dependency>
<dependency>
<groupId>io.dropwizard</groupId>
<artifactId>dropwizard-migrations</artifactId>
<version>${dropwizard.version}</version>
</dependency>
<dependency>
<groupId>io.dropwizard</groupId>
<artifactId>dropwizard-testing</artifactId>
<version>${dropwizard.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.dropwizard</groupId>
<artifactId>dropwizard-assets</artifactId>
<version>${dropwizard.version}</version>
</dependency>
<dependency>
<groupId>io.dropwizard</groupId>
<artifactId>dropwizard-views-freemarker</artifactId>
<version>${dropwizard.version}</version>
</dependency>
<dependency>
<groupId>io.dropwizard</groupId>
<artifactId>dropwizard-views-mustache</artifactId>
<version>${dropwizard.version}</version>
</dependency>
<dependency>
<groupId>io.dropwizard</groupId>
<artifactId>dropwizard-auth</artifactId>
<version>${dropwizard.version}</version>
</dependency>
<dependency>
<groupId>io.dropwizard</groupId>
<artifactId>dropwizard-spdy</artifactId>
<version>${dropwizard.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.34</version>
</dependency>
</dependencies>
</project>
注意点としては、propertiesにsourceEncodingを記述する。
これを記述しないと、eclipseでのビルド時に失敗する。
<properties>
<dropwizard.version>0.7.1</dropwizard.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
・dropwizard.version
使用するdropwizardのバージョンを書く。(2015.1.26現在)
・project.build.sourceEncoding
ソースコードのエンコーディングを書く。
build時に使用するプラグインとして以下のプラグインを記述。
・maven-shade-plugin
依存関係を調べて同包するために使用
・maven-jar-plugin
jarファイルを作成するために使用
dropwizard関連の設定は、dependenciesに記述する。
mysqlのjdbcドライバの設定もdependenciesに記述する。
pom.xmlの編集が終わったら保存する。
自動でビルドが開始される。
###dropwizardのお作法に従ってファイルを作成する。
dropwizardのGetting Startedにしたがって各ファイルを作成する。
####Configurationファイルの作成
アプリケーションとしての設定をここにまとめる。
yamlファイルから個別設定情報を読み込み設定することが可能。
package com.examples.sampleApp;
import io.dropwizard.Configuration;
import io.dropwizard.db.DataSourceFactory;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import com.fasterxml.jackson.annotation.JsonProperty;
public class SampleAppConfiguration extends Configuration {
@Valid
@NotNull
private DataSourceFactory database = new DataSourceFactory();
@JsonProperty("database")
public DataSourceFactory getDataSourceFactory() {
return database;
}
@JsonProperty("database")
public void setDataSourceFactory(DataSourceFactory dataSourceFactory) {
this.database = dataSourceFactory;
}
}
App.javaをSampleApp.javaに変更する。
package com.examples.sampleApp;
import io.dropwizard.Application;
import io.dropwizard.assets.AssetsBundle;
import io.dropwizard.db.DataSourceFactory;
import io.dropwizard.hibernate.HibernateBundle;
import io.dropwizard.migrations.MigrationsBundle;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;
import io.dropwizard.views.ViewBundle;
import com.examples.sampleApp.Resource.PersonResource;
import com.examples.sampleApp.db.PersonDAO;
import com.examples.sampleApp.entity.Person;
public class SampleApp extends Application<SampleAppConfiguration>
{
private final HibernateBundle<SampleAppConfiguration> hibernateBundle =
new HibernateBundle<SampleAppConfiguration>(Person.class) {
@Override
public DataSourceFactory
getDataSourceFactory(SampleAppConfiguration configuration) {
return configuration.getDataSourceFactory();
}
};
public static void main(String[] args) throws Exception {
new SampleApp().run(args);
}
@Override
public void initialize(Bootstrap<SampleAppConfiguration> bootstrap) {
bootstrap.addBundle(new AssetsBundle());
bootstrap.addBundle(new MigrationsBundle<SampleAppConfiguration>() {
@Override
public DataSourceFactory getDataSourceFactory
(SampleAppConfiguration configuration) {
return configuration.getDataSourceFactory();
}
});
bootstrap.addBundle(hibernateBundle);
bootstrap.addBundle(new ViewBundle());
}
@Override
public void run(SampleAppConfiguration configuration, Environment environment) {
final PersonDAO dao = new PersonDAO(hibernateBundle.getSessionFactory());
//使用するAPIはここで登録する。
environment.jersey().register(new PersonResource(dao));
}
}
####entityの作成
データ受け渡し用entityを作成する。
package com.examples.sampleApp.entity;
import java.util.Objects;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
@Entity
@Table(name = "person")
@NamedQueries(
{ @NamedQuery(
name = "com.examples.sampleApp.entity.Person.findAll",
query = "SELECT p FROM Person p"
) }
)
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column(name = "fullName", nullable = false)
private String fullName;
@Column(name = "jobTitle", nullable = false)
private String jobTitle;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public String getJobTitle() {
return jobTitle;
}
public void setJobTitle(String jobTitle) {
this.jobTitle = jobTitle;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Person)) return false;
final Person that = (Person) o;
return
Objects.equals(this.id, that.id) &&
Objects.equals(this.fullName, that.fullName) &&
Objects.equals(this.jobTitle, that.jobTitle);
}
@Override
public int hashCode() {
return Objects.hash(id, fullName, jobTitle);
}
}
####データベースアクセス用クラスを作成する。
データ転送用にdaoを作成。
package com.examples.sampleApp.db;
import io.dropwizard.hibernate.AbstractDAO;
import java.util.List;
import org.hibernate.SessionFactory;
import com.examples.sampleApp.entity.Person;
import com.google.common.base.Optional;
public class PersonDAO extends AbstractDAO<Person> {
public PersonDAO(SessionFactory factory) {
super(factory);
}
public Optional<Person> findById(Long id) {
return Optional.fromNullable(get(id));
}
public Person create(Person person) {
return persist(person);
}
public List<Person> findAll() {
return list(namedQuery("com.example.core.Person.findAll"));
}
}
####URLに対応したリソースファイルを作成
アクセス用URLに対応した処理を記述する。
ここでは、.../person/1 のURLでアクセスすることにより、
個人のデータをデータベースから取得し、表示する。
package com.examples.sampleApp.Resource;
import io.dropwizard.hibernate.UnitOfWork;
import io.dropwizard.jersey.params.LongParam;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import com.examples.sampleApp.db.PersonDAO;
import com.examples.sampleApp.entity.Person;
import com.google.common.base.Optional;
@Path("/person")
@Produces(MediaType.APPLICATION_JSON)
public class PersonResource {
private final PersonDAO personDao;
public PersonResource(PersonDAO personDao) {
this.personDao = personDao;
}
@GET
@UnitOfWork
@Path("/{personId}")
public Person getPerson(@PathParam("personId") LongParam personId) {
final Optional<Person> person = personDao.findById(personId.get());
return person.get();
}
}
###アプリケーション個別設定ファイルを作成する。
アプリケーション個別設定ファイルは、YAML形式にてプロジェクト直下に作成する。
database:
driverClass: com.mysql.jdbc.Driver
user: root
password:
url: jdbc:mysql://localhost:3306/sample
properties:
charSet: UTF-8
hibernate.dialect: org.hibernate.dialect.MySQLDialect
hibernate.show_sql: true # ←
maxWaitForConnection: 1s
validationQuery: "/* MyApplication Health Check */ SELECT 1"
minSize: 8
maxSize: 32
checkConnectionWhileIdle: false
.javaファイルの編集は以上。
作成後のTreeは下図のようになる。
###MySQLの設定
あらかじめインストールされたMySQLにPersonテーブルを作成する。
テスト用に2,3件データを入力する。
id | Full Name | Job Title |
---|---|---|
1 | Test Taro | IT |
2 | Test Jiro | SE |
3 | Test Hanako | PM |
####Buildと実行
maven clean
[INFO] Scanning for projects...
[INFO]
[INFO] Using the builder org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder with a thread count of 1
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building sampleApp 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ sampleApp ---
[INFO] Deleting D:\IDE\ws\luna\ws2\test02\sampleApp\target
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.666 s
[INFO] Finished at: 2015-01-26T15:38:45+09:00
[INFO] Final Memory: 5M/120M
[INFO] ------------------------------------------------------------------------
maven install
[INFO] Scanning for projects...
[INFO]
[INFO] Using the builder org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder with a thread count of 1
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building sampleApp 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ sampleApp ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory D:\IDE\ws\luna\ws2\test02\sampleApp\src\main\resources
[INFO]
[INFO] --- maven-compiler-plugin:2.5.1:compile (default-compile) @ sampleApp ---
[INFO] Compiling 5 source files to D:\IDE\ws\luna\ws2\test02\sampleApp\target\classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.836 s
[INFO] Finished at: 2015-01-26T15:42:07+09:00
[INFO] Final Memory: 9M/152M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:2.5.1:compile (default-compile) on project sampleApp: Fatal error compiling: tools.jar not found: D:\IDE\pleiades\java\7\..\lib\tools.jar -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException
tools.jarがないと怒られるので追記する。
ウィンドウメニューから設定を開き、インストール済みのJREを選択。
java7を選択して編集ボタンを押し、外部Jar追加ボタンよりpleiades/java/7/lib/tools.jarを
追加する。
再度 maven install を行う。今度は成功した。
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 38.336 s
[INFO] Finished at: 2015-01-26T16:19:21+09:00
[INFO] Final Memory: 14M/205M
[INFO] ------------------------------------------------------------------------
###jarファイルを実行する。
jarファイルが作成できたらコマンドプロンプトから起動する。
プロジェクトの上で右クリックし、コマンドプロンプトを選択。
コマンドプロンプト上でjarファイルを実行する。
java -jar target/sampleApp-0.0.1-SNAPSHOT.jar server sampleApp.yml
サーバが立ち上がるので、ブラウザから
http://localhost:8080/person/1
へアクセスする。
JSON形式でレスポンスが帰ってくる。
{"id":1,"fullName":"Test Taro","jobTitle":"IT"}
以上。