Spring BootでマルチSelectボックスをAjax+Jsonで扱う方法

Spring Bootで複数選択可能なSelectボックスをAjax+Jsonで扱う方法です。

Spring BootでマルチSelectボックスをAjax+Jsonで扱う方法

複数選択可能な Select ボックスを作ってくれる jQuery プラグインってたくさんありますが、今回は自分が普段よく使う Bootstrap Multiselect を使います。

↓これが・・・、

Selectボックス マルチ選択

↓こうなります^^

Selectボックス マルチ選択プラグイン

Bootstrap 向けに作られていることと、ドロップダウン内の件数が多い場合、フィルターできるので便利ってことが特徴ですかね。

詳しくは「Bootstrap Multiselect」を参考に。


環境

  • Spring Boot 1.4.1
  • Thymeleaf 3.0.2
  • Windows7
  • Java8
  • Eclipse 4.6 Neon
  • Bootstrap 3.3.7
  • jQuery 2.1.1
  • Bootstrap Multiselect 0.9.13

Spring Bootでサンプルアプリを作る

まずは Spring Boot のサンプルを作ります。

・pom.xml


<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>jp.demo.sbmlt</groupId>
  <artifactId>spring-boot-multiple</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.4.1.RELEASE</version>
  </parent>
  <properties>
    <java.version>1.8</java.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>
    <thymeleaf-layout-dialect.version>2.0.5</thymeleaf-layout-dialect.version>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-devtools</artifactId>
    </dependency>
    <dependency>
      <groupId>org.webjars</groupId>
      <artifactId>bootstrap</artifactId>
      <version>3.3.7</version>
    </dependency>
    <dependency>
      <groupId>org.webjars</groupId>
      <artifactId>jquery</artifactId>
      <version>2.1.1</version>
    </dependency>
    <dependency>
      <groupId>org.webjars</groupId>
      <artifactId>bootstrap-multiselect</artifactId>
      <version>0.9.13</version>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
          <source>${java.version}</source>
          <target>${java.version}</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

Webjars で Bootstrap Multiselect を設定しておきましょう。

・Application.java


package jp.demo.sbmlt;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {
  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
  }
}

・IndexController.java

package jp.demo.sbmlt;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class IndexController {
  @RequestMapping(value = "/", method = RequestMethod.GET)
  String index(Model model) {
    return "index";
  }
}

・index.html


<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
  <title>Spring Boot de Multiple Select</title>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <meta name="description" content="Spring BootでマルチSelectボックスをAjax(Json)で扱うサンプル">
  <meta name="keywords" content="springboot,jquery,multiselect,filter">
  <link rel="stylesheet" media="all" th:href="@{/webjars/bootstrap/3.3.7/css/bootstrap.min.css}" />
  <link rel="stylesheet" media="all" th:href="@{/webjars/bootstrap-multiselect/0.9.13/css/bootstrap-multiselect.css}" />
  <!--[if lt IE 9]>
    <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
    <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
  <![endif]-->
  <style type="text/css">
    body {
      font-family: "Helvetica Neue",Helvetica,Arial,"ヒラギノ角ゴ Pro W3","Hiragino Kaku Gothic Pro","メイリオ",Meiryo,"MS Pゴシック","MS PGothic",sans-serif;
    }
  </style>
</head>
<body>
<div class="container">
  <h1 class="page-header">Spring BootでマルチSelectボックスをAjax+Jsonで扱うサンプル</h1>
</div>
<script type="text/javascript" th:src="@{/webjars/jquery/2.1.1/jquery.min.js}"></script>
<script type="text/javascript" th:src="@{/webjars/bootstrap/3.3.7/js/bootstrap.min.js}"></script>
<script type="text/javascript" th:src="@{/webjars/bootstrap-multiselect/0.9.13/js/bootstrap-multiselect.js}"></script>
</body>
</html>

あらかじめ、Bootstrap Multiselect の CSS / Javascript を読み込んでおきます。

・application.yml


spring:thymeleaf:mode:HTML

ここまで作ったら mvn clean, mvn test を実行して、動作検証しておきましょう。

Spring BootでマルチSelectボックスを扱うサンプルアプリ構成

マルチSelectボックスをAjax+Jsonで送信する

いよいよ本題です。まずは、コントローラークラスから変更していきます。

・IndexController.java

コントローラークラスに、ドロップダウンのリストをクライアントへ送信する記述を追記します。


package jp.demo.sbmlt;

import java.util.LinkedHashMap;
import java.util.Map;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class IndexController {
  @RequestMapping(value = "/", method = RequestMethod.GET)
  String index(Model model) {
    model.addAttribute("colors", getColors());
    return "index";
  }
  Map<String, String> getColors() {
    Map<String, String> map = new LinkedHashMap<String, String>();
    map.put("red", "Red");
    map.put("green", "Green");
    map.put("blue", "Blue");
    map.put("orange", "Orange");
    map.put("purple", "Purple");
    map.put("yellow", "Yellow");
    map.put("brown", "Brown");
    map.put("black", "Black");
    return map;
  }
}

実務では、データベースから取得した値を利用すると思いますが、ここでは MAP オブジェクトを生成して値リストを作っています。model.addAttribute で名前を付けてクライアントへ送信します。

・index.html

次に HTML を追記します。Bodyタグを下記のように変更します。


<body>
<div class="container">
  <h1 class="page-header">Spring BootでマルチSelectボックスをAjax+Jsonで扱うサンプル</h1>
  <form class="form-horizontal" id="multipleform" name="multipleform" role="form" method="post" action="" novalidate>
    <div class="form-group">
      <label for="singleselect" class="col-sm-3 control-label">シングル</label>
      <div class="col-sm-9">
        <select id="singleselect" name="singleselect" class="form-control">
          <option value="">---</option>
          <option th:each="item : ${colors}" th:value="${item.key}" th:text="${item.value}" th:selected="${item.key} == *{singleselect}">SingleSelect</option>
        </select>
      </div>
    </div>
    <div class="form-group">
      <label for="multiselect" class="col-sm-3 control-label">マルチ</label>
      <div class="col-sm-9">
        <select id="multiselect" name="multiselect" class="form-control" multiple="multiple">
          <option th:each="item : ${colors}" th:value="${item.key}" th:text="${item.value}" th:field="*{colors}">MultiSelect</option>
        </select>
      </div>
    </div>
    <div class="form-group">
      <label for="textinput" class="col-sm-3 control-label">テキスト</label>
      <div class="col-sm-9">
        <input type="text" class="form-control" name="textinput" placeholder="テキスト" value="">
      </div>
    </div>
    <div class="form-group">
      <label for="textarea" class="col-sm-3 control-label">テキストエリア</label>
      <div class="col-sm-9">
        <textarea class="form-control" name="textarea" rows="5"></textarea>
      </div>
    </div>
  </form>
  <div class="text-center">
    <button type="button" id="btnSend" name="btnSend" class="btn btn-success">送信する</button>
  </div>
</div>
<script type="text/javascript" th:src="@{/webjars/jquery/2.1.1/jquery.min.js}"></script>
<script type="text/javascript" th:src="@{/webjars/bootstrap/3.3.7/js/bootstrap.min.js}"></script>
<script type="text/javascript" th:src="@{/webjars/bootstrap-multiselect/0.9.13/js/bootstrap-multiselect.js}"></script>
<script type="text/javascript">
jQuery(document).ready(function() {
  $("#multiselect").multiselect({enableCaseInsensitiveFiltering: true});
});
$('#btnSend').click(function() {
  var indata = parseJson($('#multipleform').serializeArray());
  $.ajax({
    type: "POST",
    url: "./multi",
    dataType: "json",
    data: JSON.stringify(indata),
    contentType: 'application/json',
    scriptCharset: 'utf-8',
    success: function(otdata, dataType) {
      alert("OK" );
    },
    error: function(XMLHttpRequest, textStatus, errorThrown) {
      alert("Error : " + errorThrown);
    }
  });
});
var parseJson = function(formdata) {
  var data = {};
  $(formdata).each(function(index, obj){
    if(data[obj.name] === undefined)
      data[obj.name] = [];
    if (  $("#"+obj.name).prop('multiple') )
      data[obj.name].push(obj.value);
    else
      data[obj.name] = obj.value;
  });
  return data;
}
</script>
</body>

ポイントは、シングルSelect、マルチSelect、テキストボックス、テキストエリアと、よく使う入力オブジェクトを使っていることですかね。

・IndexForm.java

次に、サーバーサイドで受信する From クラスを作ります。

受け取る値は、セレクトボックスのシングル選択値とマルチ選択値、それとテキストボックスの入力値とテキストエリアの入力値の4つです。

・IndexForm.java


package jp.demo.sbmlt;

import java.util.List;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class IndexForm {
  private String singleselect;
  private List<String> multiselect;
  private String textinput;
  private String textarea;
}

複数値を取得する為、マルチセレクトボックスだけ List 型にしているのがポイントです。

・MultiSelectController.java

最後に、コントローラーを追加します。


package jp.demo.sbmlt;

import java.util.Arrays;
import java.util.List;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MultiSelectController {
  @RequestMapping(value = "/multi", consumes=MediaType.APPLICATION_JSON_VALUE)
  @ResponseBody
  public List<String> multi(@RequestBody IndexForm form) {
    System.out.println("######## Start ##########");
    System.out.println("Singleselect : " + form.getSingleselect());
    System.out.println("Multiselect  : " + (form.getMultiselect() != null ? form.getMultiselect().toString() : "") );
    System.out.println("Textinput    : " + form.getTextinput());
    System.out.println("Textarea     : " + form.getTextarea());
    System.out.println("######## End ##########");
    return Arrays.asList("OK");
  }
}

Multiselect については、何も選択されないと null で送信されてくるので、分岐処理が入っています。

動作検証

では、早速動作検証しましょう。下図のように入力して送信ボタンを押下します。

Spring BootでマルチSelectボックスをAjax+Jsonで扱うサンプルアプリ

すると、サーバー側ではこんなログが・・・・


######## Start ##########
Singleselect : red
Multiselect  : [green, orange, purple]
Textinput    : テキストボックス TEST
Textarea     : テキストエリア

Test
######## End ##########

おおおー、いい感じで送信されましたねー^^

まとめ

Spring Bootで複数選択可能なSelectボックスをAjax+Jsonで扱う方法を紹介しました。

複数選択できるドロップダウンって、実務ではかなり使えますよねー。ただの multiple では、デザインがアレで使いたくありませんでしたが、今では様々なプラグインが用意されていて、デザインもホントお洒落で素敵です。しかもコーディングは極少量ですから。おまけにフィルターできるようになるなんて。一昔(二昔?)前じゃ自前でゴリゴリ書くしかなかったから、便利な世の中になったなぁ・・・と思う今日この頃です。

今はゴリゴリとコーディングするより、使えるプロダクトやプラグインを集めて、最小のコーディングで開発するって感じですものね。

HTML 内に 記述した Javascript の parseJson ってのは、もう少しキレイにしたいと思いましたが、まぁいいか・・・。どなたかいい感じにできる方、コメントお待ちしておりますm(_ _)m

おつかれさまでした。

この記事がお役に立ちましたら シェア をお願いいたします。