0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【セレクトボックス連動】WebAPI を叩く際に Enum を JSON で渡す

Last updated at Posted at 2020-05-29

Kotlin API を叩く際に Enum を JSON から変換する

  • SpringBoot2
  • Thymeleaf
  • Jackson (Jsonのシリアライズ・デシリアライズで利用)
  • パラメータで渡すのが一番簡単ですが、折角(?)なので JSON で渡してみる
  • Jsonで渡すと書いてありますが実際は、Json -> Enum 変換
  • Kotlin

実施環境

開発PC: Windows 10
Java: 8
Kotlin: 0.8.19
Eclipse: 2019-06 (4.12.0)

想定される場面

  • 連動するセレクトボックスなど
    • 1つ目のセレクトボックスの選択によって2つ目のセレクトボックスの内容が変わる場合
    • Enum の入れ子でやってみる
    • Enum は継承出来ないのが今ひとつ

1つ目のセレクトボックス用 Enum

  • JsonSerialize, JsonDeserialize アノテーションでシリアライズ・デシリアライズのクラスを指定
@JsonSerialize(using = EnumSerializer::class)
@JsonDeserialize(using = EnumDeserializer::class)
enum class Select1Enum(val text:String, val arr:Array<*>) {

    SELECT1("セレクト2-1", Select21Enum.values()),
    SELECT2("セレクト2-2", Select22Enum.values()),
    SELECT3("セレクト2-3", Select23Enum.values()),
    ;
        // 名称により Enum 取得
        fun getByText(text: String):Select1Enum? {

            var result: Select1Enum? = null
            enumValues<Select1Enum>().forEach {
                if (it.text == text) {
                    result = it
                }
            }
            return result
        }

    }

    override fun toString():String {
        return ReflectionToStringBuilder.toString(this)
   }
}

2つめのセレクトボックス用 Enum

  • 同様に複数用意
enum class Select21Enum(val text:String) {

    SELECT1("セレクト2-1ー1"),
    SELECT2("セレクト2-1-2"),
    SELECT3("セレクト2-1-3"),
    ;
        // 名称により Enum 取得
        fun getByText(text: String):Select21Enum? {

            var result: Select21Enum? = null
            enumValues<Select21Enum>().forEach {
                if (it.text == text) {
                    result = it
                }
            }
            return result
        }

    }
}

シリアライズ・デシリアライズ用のクラス

  • 簡単に Enum の text で enum の項目が指定できるように
class EnumDeserializer:JsonDeserializer<Any>() {

	@Throws(IOException::class)
	override fun deserialize(jp:JsonParser, ctxt:DeserializationContext):Select1Enum? {

        val jsonNode:JsonNode = jp.getCodec().readTree(jp)

	    val jsonValue = jsonNode.get("text").asText()
	    for (enumValue in Select1Enum.values()) {
	    	if (enumValue.text.equals(jsonValue)) {
	    		return enumValue
	    	}
	    }
	    return null
  	}
}

class EnumSerializer:JsonSerializer<Select1Enum>() {

    @Throws(IOException::class)
    override fun serialize(value:Select1Enum, jgen:JsonGenerator, provider:SerializerProvider) {
        jgen.writeStartObject()
        jgen.writeFieldName("text")
        jgen.writeString(value.text)
        jgen.writeEndObject()
    }
}

APIで出力するテンプレートを用意

  • fragment_select2.html(thymeleaf)
<!DOCTYPE html>

<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"/>
    <title>Insert title here</title>
</head>
<body id="fragmentBody" th:fragment="fragmentBody()">
            <select name="select2" id="select2" th:fragment="fragmentSelect()">
              <option value="">選択してください。</option>
              <option th:if="${select2List != null}" th:each="i : ${select2List}" th:value="${i.text}" th:text="${i.text}" th:selected="${i.text} == *{select2}"> --- </option>
            </select>
            <span th:if="${#fields.hasErrors('select2')}" th:errors="*{select2}" id="select2.errors" class="help-block error" th:style="|display: block;|">正しく入力してください。</span>
</body>
</html>

API出力用コントローラ

  • /api/select/getSelect2
  • @RequestBody アノテーションをつける
  • 後述 javascript で呼び出される
  • Json 形式で受け取ったパラメータを Enum へデシリアライズ
@Controller
@RequestMapping("api/select")
open class SelectApiController {

    @PostMapping(path=["/getSelect2"],
        consumes=[MediaType.APPLICATION_JSON_VALUE])
    open fun getSelect2(@RequestBody(required=false) select1:Select1Enum?, model:Model): String {

    	if (select1 != null) {
            model.addAttribute("select2List", select1.arr)
        }

        return "fragment_select2::fragmentSelect()"
    }
}

入力用フォームのHTML(抜き出し)

            <div>
              <select name="select1" id="select1" th:field="*{select1}">
                <option value="">選択してください。</option>
                <option th:each="i : ${selectList}" th:value="${i.text}" th:text="${i.text}">選択1</option>
              </select>
              <span th:if="${#fields.hasErrors('select1')}" th:errors="*{select1}" id="select1.errors" class="help-block error" th:style="|display: block;|">セレクト1を正しく入力してください。</span>
            </div>
            <div id="fragment_select2" th:include="select/fragment_select2::fragmentBody()">

セレクトボックス連動用 javascript

  • jquery 利用
  • Json 形式で渡す
  • 結果は #fragment_select2 に注入
// ページロード後に呼び出す
function initializeSelect1Events() {

	// 業種セレクト連動
	$("#select1").on('change', function(e) {
		select1OnChange();

	});
}

function select1OnChange() {
	var url = contextPath + '/api/select/getSelect2';
	var value = $("#select option:selected").val();
	var data = JSON.stringify({'text': value});

	$.ajax({
		headers: {
			'Content-Type': 'application/json'
		},
		url: url,
		type: 'POST',
		cache: false,
		dataType: 'html',
		data: data,
		traditional: true,
		beforeSend: function(xhr, settings) {}
	})
	.done(function(data, textStatus, xhr) {
		if (data.error !== undefined) {
			alert(data.error);
		}
		else if (data.length == 0) {
			alert("セレクト2が取得できませんでした");
		}
		else {
			$("#fragment_select2").html(data);
		}
	})
	.fail(function(xhr, textStatus, errorThrown){
		alert("セレクト2が取得できませんでした");
	})
	.always(function(xhr, msg){
	});
}

以上、お疲れさまでした!

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?