LoginSignup
8
9

More than 5 years have passed since last update.

Spring-BootのThymeleafを同じURLで連続して何回も使いたい

Last updated at Posted at 2016-04-22

何を言ってるかわからないだろう。それでいい。いいタイトルが思い浮かばなかった。Webの経験が浅いのでいい言葉を知らない(言い訳)

何がしたいかというと、Spring-Boot + Thymeleafで、固定のサイドビュー + メイン画面 のような作りのWeb画面において、画面を再読み込みせずにメイン画面だけ更新したい、という要件があったとする。

例として、/index.htmlが上記の固定のサイドビュー + メイン画面の構成として、サーバサイドで以下のようなマッピングでリスンしている状態の場合、/indexへの初期遷移時は/index.htmlに対してThymeleafが働き問題ないが、そのあと、例えばサイドメニューで別項目を選択し、メイン画面を更新する必要がある場合、リクエストを/index/hogeで行い、サーバが例えばhogeModelAndViewを返却したとすると、サーバは/index/hoge.htmlを探しに行ってしまい、リソースが無いので400エラーになる。

SampleController.java
    @RequestMapping(value = "/index", method = RequestMethod.GET)
    public ModelAndView index(ModelAndView mav) {
        mav.setViewName("index");
        mav.addObject("param", "hoge");
        return mav;
    } 

よしんば/index/hoge.htmlを置いたとしても、/index.htmlと同じサイドビューと同じコードを書くのは流石に無いし、画面がサイドビューごと更新されてしまう。(サイドメニューがアコーディオン表現で開いたり閉じたりするようなメニューにしていた場合、開いていたのに閉じるなど、かなりかっこ悪い動きになる)

仕方ないので、jQuery$.ajax()でJSONデータを取得し、DOMを動的にいじる等で対応していたのだが、せっかくThymeleafを使っているのに初期遷移時だけしか使えないというのは何とも寂しい。
色々模索していたところ、とりあえず以下の方法で落ち着いた。

index.html
    <!-- メインメニュー(JQueryのload()で流し込む) -->
    <!-- ① -->
    <div id="main_menu"></div>

<script>

// 〜〜(省略)〜〜

    // 画面1を読み込む
    if (/* 画面1を読み込むための条件判定 */) {

        // 画面1をロードする
        // ②
        $('#main_menu').load('/menu1', null, function () {
            // なんか処理
        });
    }
    // 画面2を読み込む
    else if (/* 画面2を読み込むための条件判定 */) {

        // 画面2をロードする
        // ②
        $('#main_menu').load('/menu2', null, function () {
            // なんか処理
        });
    }

// 〜〜(省略)〜〜

</script>
SampleController.java
    // ③
    @RequestMapping(value = "/menu1", method = RequestMethod.GET)
    public ModelAndView index(ModelAndView mav) {
        mav.setViewName("menu1");
        mav.addObject("param", "hoge");
        return mav;
    } 

index.htmlに、空のセレクターを用意する。
jQueryload()関数に①のセレクターを設定し、サーバにリクエストする
③サーバは通常通りの方法でModelAndViewを返却する

こうするとテンプレートも分けられるし、流し込まれるhtml内でThymeleafを使うことも出来る。
注意点として、流し込むmenu1.htmlにJavaScriptを書くと、load()されるたびに読み込まれてしまい、関数が同時に何回も呼ばれてしまう。
とりあえず関数はテンプレート単位にJSファイルに分けて、

index.html
<script>
    $(document).ready(function(){
        $.getScript("/js/menu1.js");
        $.getScript("/js/menu2.js");
    });
</script>

とやったら回避出来た。あと、<head></head>内は設定しないと文字化け等してしまったので、
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
等は書いた。

8
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
9