Spring BootのRestControllerからHTMLを生成する方法

こんにちは、さるまりんです。

RESTful APIをSpring Bootで作っておりまして。
こんな感じのコードを書いておりました。

@RestController
@RequestMapping("/api")
public class SomeController {
    @RequestMapping("some")
    public @ResponseBody SomeResponse some() {
        return new SomeResponse();
    }
}

書き進めるうちに幾つかのパスでHTMLを返却する必要があることがわかりました。

そこで@RestControllerのアノテーションをつけたコントローラからHTMLを表示する方法です。

ModelAndViewを使う

Spring Bootで画面を作成するときはThymeleafテンプレートエンジンを使うことが多いと思います。
ModelAndViewを使うと、このテンプレートエンジンを使って画面を表示することができます。

@RequestMapping("some-template")
public ModelAndView someTemplate() {
    ModelAndView mav = new ModelAndView();
    mav.setViewName("some");
    mav.addObject("data", data);
    return mav;
}

ModelAndViewクラスのオブジェクトを作り(mav = new ModelAndView())、
それにview名を設定(mav.setViewName(view名))、
埋め込むデータを設定(mav.addObject(名前, 値))し、
オブジェクトを返却します。

これでview名で指定されたHTMLに値を埋め込んで表示することができます。

直接書き出す

テンプレートエンジンとか使わずに直接そのままHTMLを返したいときはどうするでしょう?

HttpServletResponsewriterに直接書き込むことで実現できます。

@RequestMapping("some-direct")
public void someDirect(
    HttpServletRequest request,
    HttpServletResponse response)
        throws Exception {
   response.setContentType(MediaType.TEXT_HTML_VALUE);
   response.getWriter().write("<html><body><h1>RESULT</h1></html>");
}

サーブレットの出力方法、基本になる技術は同じなんですね。

混在させる

一つのメソッド=(エンドポイント)で場合によってはテンプレートエンジンを使いたい時と、そのまま出力したいケースが混在する場合はどうするでしょう。

その場合は単純に条件で分けます。

@RequestMapping("some-if")
public ModelAndView someIf(
    HttpServletRequest request,
    HttpServletResponse response)
        throws Exception {

    ...処理をして...

    if (isSuccess) {
        ModelAndView mav = new ModelAndView();
        mav.setViewName("success");
        mav.addObject("data", data);
        return mav;
    } else {
        response.setContentType(MediaType.TEXT_HTML_VALUE);
        response.getWriter().write("<html><body><h1>ERROR</h1></html>");
        return null;
    }
}

分岐して直接書き出した方はModelAndViewは何も返すものはないのでnullを返却しています。

作りながら迷ってしまったのでまとめてみました。
RestControllerではもっといろんなことができるのでそれはまた別の機会に。

読んでくださってありがとうござます。

それではまた!