たそらぼ

日頃思ったこととかメモとか。

play 2.7.xのカスタムエラーページ設定

playのエラーページはデフォルトだとユーザー目線で明らかに気持ち悪いので、カスタムエラーページを設定する方法を調べました。
特に2.7.xは日本語の情報も少ないので、docementを手掛かりに自分で設定することになりました。

※公式のplay-java-ebean-exampleサンプル
f:id:tasotasoso:20190512200148p:plain
定義されてないURLを指定すると、こんなページを吐きます。
だめですね。。。

大まかな手順

①/appにErrorHandler.javaを作成する。
②ErrorHandler.javaで、DefaultHttpErrorHandlerを継承したErrorHandlerクラスを作成し、エラー発生時のメソッドを作成する。

・document該当箇所
www.playframework.com

・メソッド一覧
www.playframework.com

404エラーページの作成

とりあえず、documentを頼りに設置してみる。

・ErrorHandler.java

import com.typesafe.config.Config;

import play.*;
import play.api.OptionalSourceMapper;
import play.api.UsefulException;
import play.api.routing.Router;
import play.http.DefaultHttpErrorHandler;
import play.mvc.Http.*;
import play.mvc.*;

import javax.inject.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;

@Singleton
public class ErrorHandler extends DefaultHttpErrorHandler {

  @Inject
  public ErrorHandler(
      Config config,
      Environment environment,
      OptionalSourceMapper sourceMapper,
      Provider<Router> routes) {
    super(config, environment, sourceMapper, routes);
  }

  protected CompletionStage<Result> onNotFound(RequestHeader request, String message) {
    return CompletableFuture.completedFuture(
        Results.notFound("Hey! This Page is not Found!!!!!"));
  }
}

先ほどのURLを調べると、
f:id:tasotasoso:20190512200200p:plain
ちゃんと思った文面が出力されましたね。

404のカスタムエラーページの作成

onNotFoundでカスタムエラーページのオブジェクトを返すように設定します。
今回はpage404.scala.htmlというviewを作成して、Results.notFound()に渡します。
※プロジェクトは、なんでもよいのですが、公式のplay-java-hello-world-tutorialで検証しました。


・ErrorHandler.java

import com.typesafe.config.Config;

import play.*;
import play.api.OptionalSourceMapper;
import play.api.UsefulException;
import play.api.routing.Router;
import play.http.DefaultHttpErrorHandler;
import play.mvc.Http.*;
import play.mvc.*;
import play.twirl.api.Html;

import javax.inject.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;

@Singleton
public class ErrorHandler extends DefaultHttpErrorHandler {

  @Inject
  public ErrorHandler(
      Config config,
      Environment environment,
      OptionalSourceMapper sourceMapper,
      Provider<Router> routes) {
    super(config, environment, sourceMapper, routes);
  }

  protected CompletionStage<Result> onNotFound(RequestHeader request, String message) {
    return CompletableFuture.completedFuture(
        Results.notFound(views.html.page404.render()));
  }
}


・page404.scala.html

@()

@main("404") {
    <h1>This is custom error message!!!</h1>
}


・main.scala.html

@*
 * This template is called from the `index` template. This template
 * handles the rendering of the page header and body tags. It takes
 * two arguments, a `String` for the title of the page and an `Html`
 * object to insert into the body of the page.
 *@
@(title: String)(content: Html)

<!DOCTYPE html>
<html lang="en">

<head>
    <title>@title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" media="screen" href='@routes.Assets.versioned("stylesheets/main.css")'>
    <link rel="stylesheet" media="screen" href='@routes.Assets.versioned("stylesheets/prism.css")'>
    <link rel="shortcut icon" type="image/png" href='@routes.Assets.versioned("images/favicon.png")'>
    <script src='@routes.Assets.versioned("javascripts/hello.js")' type="text/javascript"></script>
    <script src='@routes.Assets.versioned("javascripts/prism.js")' type="text/javascript"></script>
</head>

<body>
    <section id="top">
        <div class="wrapper">
            <img class="resize" src="assets/images/play_icon_reverse.svg" alt="logo" />
            <h1>Play Hello World Web Tutorial</h1>
        </div>
    </section>
    @content
</body>

</html>


適当に存在しないURLにアクセスすると、ちゃんとカスタムエラーページが表示されています。
f:id:tasotasoso:20190514234943p:plain

この調子でエラーページを作りこめば、運用に耐えるカスタムページが作れそうです。

まとめ

ErrorHandler.javaのonNotFound()の返り値として、文字列またはviewオブジェクトを設定すると、カスタムエラーページが設定できました。
ネット上で探してもなかなか情報が出てこず、だいぶ苦戦しましたが、分ってしまえばシンプルで使いやすそうですね。