記事のターゲット
- SpringでWebアプリを開発している人
- jQueryを使わずにAjaxを実装したい人
- Java、Thymeleaf関連の知識はある程度ある方
はじめに
ブラウザはchromeのみでしか試していないのでご了承ください。
基本的には変わらないと思いますが、今回はThymeleafで実装するのでurlの書き方が少し異なる部分があります。
今回のゴールはとりあえずAjaxが動き、コンソールにOKという文字を出すことで設定しています。
実装方法
step
1まずはThymeleafに下準備をする
HTMLファイルに直接JSを書いても良いのですが、外部のJSファイルを使用する場合は以下のようにファイルを読み込みます。
// @{/js/各自の名前.js}の部分は\src\main\resources\static以下にファイルを置いた際のパスです。
<script th:src="@{/js/schedule-top.js}" type="text/javascript" ></script>
そして今回はJSONでの実装となるので、
・次月ボタンを押す
・上の画像にある年月を取得
・サーバーに渡し、次月のデータ処理
・画面に返してコンソールにOKを出す
という流れで行きます。
ではBody部分に以下のコードを追加します。「th:value="@{/schedule/top}」にはSpring側での処理部分のPathを記述します。どこで使うかは後で説明いたします。
class等は特に記述しなくでも大丈夫です。
//SpringへのPathを用意する
<input type="hidden" id="ajax_uri" th:value="@{/schedule/top}">
<div id="date">
<div class="year-wrapper">
<p class="display-month" id="year" th:text="${scheduleIndexForm.calendar.get('year')}"></p>
<p>年</p>
</div>
<div class="day-wrapper">
<p class="display-month" id="month" th:text="${scheduleIndexForm.calendar.get('month')}"></p>
<p>月</p>
</div>
</div>
step
2JSファイルを記述する。
今回は全て生のJavaScript、いわゆるVanillaJSで記述していくのでjQueryよりも冗長な書き方になります。
とりあえず以下のコードを記述します。外部JSの場合は<Script>タグは必要ありません。
//window.onloadにfunctionを設定することにより、画面の読み込みが終わった後に自動で実行される処理を記述できます。
window.onload = function () {
//画面の年月を取得する
let year = document.getElementById("year").textContent;
let month = document.getElementById("month").textContent;
//Springに引き渡すデータをJSON型にしておく
let formData = JSON.stringify({
"calendar":{
"year" : year,
"month" : month
}
});
//次月へボタン押下時処理
let nextMonth = document.getElementById("next-month");
nextMonth.addEventListener("click", function () {
//HTML部分で追加したPathをdocument.querySelector("#ajax_uri").valueで指定する。
doAjaxPost(formData, document.querySelector("#ajax_uri").value, function(resData){
//Ajaxから正常にデータが返ってきたときの処理
console.log('OK');
});
});
}
//POST通信のajax処理
function doAjaxPost(data, url, callback){
//リクエストのデータ
let request = new XMLHttpRequest();
//サーバーのステータスが変わった場合かつ正常に終わった場合Springから受け取ったデータをもとの処理へ返す処理を定義
request.onreadystatechange = function () {
//readyStateが4の場合サーバのレスポンスの受信が完了
//statusが200の場合は通信が成功していることを表す
if(request.readyState == 4 && request.status == 200){
try{
//responseTextにするとjsonは受け取れない
callback(request.response);
return;
}catch(err){
console.log(err.message);
return;
}
}
return;
}
//どういう形で通信を行うか指定(第三引数は省略可、trueにすることで非同期通信となる)
request.open("POST", url , true);
//サーバーへ渡すデータタイプをここで指定、今回はJSONの書き方
request.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
//戻ってくるデータをJSON型で受け取ることを宣言
request.responseType = "json";
//準備ができたらデータを送る
request.send(data);
}
JS側はとりあえずこれで大丈夫です。後はSpringの処理だけです。
step
3SpringのControllerへ記述する
//POST通信の場合はRequestMethod.POSTと記述
@RequestMapping(path="schedule/top", method=RequestMethod.POST)
//AjaxをSpringで処理したい場合にResponseBodyの記述が必要
@ResponseBody
//基本的には文字列を返すがAjaxの場合は必要な情報のみ返すので戻り値をその都度変更
//@RequestBodyはHTMLから送られてきたJSONのデータをどのクラスで受け取るかを指定するもの
public ScheduleIndexForm makeAjaxCalendar(@ModelAttribute(FORM_NAME) ScheduleSessionForm session,@RequestBody ScheduleIndexForm scheduleIndexForm, Model model) throws Exception{
//中略
return new ScheduleIndexForm();
}
メソッドの引数にある@RequestBodyについてもう少しだけ説明します。
JS部分で記述した以下のコードを見てください
let formData = JSON.stringify({
"calendar":{
"year" : year,
"month" : month
}
});
calendarという要素の中にさらにyear、monthというプロパティを作っています。
そしてJava側で受け取るFormを見てみると、
public class ScheduleIndexForm {
//カレンダー作成に必要な情報保持
private Map<String, String> calendar;
//以下略
直下にcalendarというフィールドを持っています。
そしてcalendarの中にはyearとmonthという値が入ってきます。
このようにネストした要素もJSONで受け渡せるのが@RequestBodyです。
動かしてみる
実際に動かしてみます。
次月ボタンを押すと、
Ajaxが動いて、
コンソールにコメントが出ます。
最後に
今回VanillaJSでのAjax実装だったのですが、jQueryではわからない内部のことがわかって勉強になりました。
<以下参考サイト>
https://code-maven.com/ajax-request-for-json-data
https://developer.mozilla.org/ja/docs/Web/Guide/AJAX/Getting_Started
https://salumarine.com/how-to-convert-json-string-to-map-in-java/
https://www.ne.jp/asahi/hishidama/home/tech/java/spring/boot/rest/jackson.html
https://so-zou.jp/software/tech/network/tech/http/status-code/