Dropwizardについての続きです。
前回は以下の説明をしました。
- mavenでのbuild
- Configurationクラス
- Applicationクラス
- Resourceクラス
- Representationクラス
- HealthCheck機能
今回は前回のサンプルに以下を追加していきます。
- 静的ファイルの表示
- テンプレートエンジンによる動的ファイルの表示
- ssl通信
- 認証
静的ファイルと動的ファイル
maven設定
静的ファイルはdropwizard-assets
動的ファイルはdropwizard-views-freemarker、またはdropwizard-views-mustache
に依存させます。
<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>
Resourceクラス
ポイントは@Produces
でリソースから返されるMIMEタイプを指定することくらいです。
@Path("/views")
public class ViewResource {
@GET
@Produces("text/html;charset=UTF-8")
@Path("/freemarker")
public View freemarkerUTF8() {
return new View("/views/ftl/utf8.ftl", Charsets.UTF_8) {
};
}
@GET
@Produces("text/html;charset=UTF-8")
@Path("/mustache")
public View mustacheUTF8() {
return new View("/views/mustache/utf8.mustache", Charsets.UTF_8) {
};
}
}
上記で利用しているViewクラスはDropwizardでViewを表現するためのabstractクラスになります。
HTMLを表示したい場合は、このViewクラスでpublicなオブジェクトを返すGetterメソッドを作ります。
例えば、以下のようにPersonクラスを返して、templateで表示します。
public class PersonView extends View {
・・・
public Person getPerson() {
return person;
}
}
<html>
<body>
<h1>Hello {{person.fullName}}</h1>
</body>
</html>
Viewクラス自身のpublicメソッドは@JsonIgnoreが指定されているので、jsonでは表示されないようになっています。
@JsonIgnore
public String getTemplateName() {
return templateName;
}
@JsonIgnore
public Optional<Charset> getCharset() {
return Optional.fromNullable(charset);
}
テンプレート
<html>
<body>
<h1>This is an example of a freemarker</h1>
文字コード:${charset}
</body>
</html>
<html>
<body>
<h1>This is an example of a mustache</h1>
文字コード:{{charset}}
</body>
</html>
Applicationクラス
BundleクラスとResourceクラスを登録します。
AssetsBundleクラスとViewBundleクラスはDropwizardで用意されているクラスになります。
BasicAuthProviderは、Basic認証用の組み込みクラスになります。
@Override
public void initialize(Bootstrap<HelloWorldConfiguration> bootstrap) {
bootstrap.addBundle(new AssetsBundle());
bootstrap.addBundle(new ViewBundle());
}
@Override
public void run(HelloWorldConfiguration configuration,
Environment environment) throws ClassNotFoundException {
・・・
environment.jersey().register(new ViewResource());
・・・
}
静的ファイル
静的ファイルはassets
ディレクトリに置きます。
これはAssetsBundleクラスのデフォルトです。コンストラクタで変更できます。
alert('sample');
動作確認
mvn package
でjarを作成後、起動すると新しく登録したResourceのURIが表示されています。
$ java -jar target/spike-dropwizard-1.0-SNAPSHOT.jar server example.yml
INFO [2014-06-08 13:30:34,302] io.dropwizard.jersey.DropwizardResourceConfig: The following paths were found for the configured resources:
・・・
GET /views/freemarker (com.github.ko2ic.resources.ViewResource)
GET /views/mustache (com.github.ko2ic.resources.ViewResource)
対応するURIを呼び出すと変換されたHTMLが表示されます。
$ curl http://localhost:8080/views/freemarker
<html>
<body>
<h1>This is an example of a freemarker</h1>
文字コード:Optional.of(UTF-8)
</body>
</html>
$ curl http://localhost:8080/views/mustache
<html>
<body>
<h1>This is an example of a mustache</h1>
文字コード:Optional.of(UTF-8)
</body>
</html>
静的ファイルは/assets/ファイルパス
で呼び出します。
$ curl http://localhost:8080/assets/js/example.js
alert('sample');
SSLと認証
SSL
SSLは、keystoreを作成して設定をするだけでアクセスできました。
https://localhost:8443/hello-world
server:
・・・
- type: https
port: 8443
keyStorePath: example.keystore
keyStorePassword: example
validateCerts: false
以上です。次は認証です。
maven設定
dropwizard-authの依存を追加します。
<dependency>
<groupId>io.dropwizard</groupId>
<artifactId>dropwizard-auth</artifactId>
<version>${dropwizard.version}</version>
</dependency>
Representationクラス
ただのドメインクラスです。
public class User {
private final String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Authenticator
認証用のインターフェイスAuthenticator
を実装します。
認証OKの場合にOptional.of(p)
、NGの場合はOptional.absent()
を返します。
ここで引数になっているBasicCredentials
はDropwizardのBasic認証用のクラスになります。
このサンプルの場合は、user/passでbasic認証が通ります。
public class ExampleAuthenticator implements
Authenticator<BasicCredentials, User> {
@Override
public Optional<User> authenticate(BasicCredentials credentials)
throws AuthenticationException {
if ("user".equals(credentials.getUsername())
&& "pass".equals(credentials.getPassword())) {
return Optional.of(new User("ko2ic " + credentials.getUsername()));
}
return Optional.absent();
}
}
Resourceクラス
メソッドの引数に@Auth
を付けることで認証対象のメソッドになり、Authenticator#authenticate()の戻り値が渡されます。
@Path("/protected")
@Produces(MediaType.TEXT_PLAIN)
public class ProtectedResource {
@GET
public String showSecret(@Auth User user) {
return String.format("Hey there, %s. You know the secret!",
user.getName());
}
}
Applicationクラス
@Override
public void run(HelloWorldConfiguration configuration,
Environment environment) throws ClassNotFoundException {
・・・
environment.jersey().register(
new BasicAuthProvider<>(new ExampleAuthenticator(),
"SUPER SECRET STUFF"));
environment.jersey().register(new ProtectedResource());
・・・
}
動作確認
$ curl -u user:pass http://localhost:8080/protected
Hey there, ko2ic user. You know the secret!