※当サイトの記事には、広告・プロモーションが含まれます。

JSTL(JavaServer Pages Standard Tag Library)の<c:foreach>を再描画させるには

nazology.net

脳科学の発展を祈るしかないってことかね...

JSTL(JavaServer Pages Standard Tag Library)の<c:foreach>を再描画させるには

枯れた技術なはずなのに、意外と情報が無くて驚きなのだけど。

Java側で<c:foreach>で繰り返し処理する変数の値を変えたら、<c:foreach>も自動的に再描画してくれると思いきや、然に非ず。

じゃあ、どうするかと言うと、

<c:if test=""></c:if>

などで<c:foreach>を囲ってあげる必要があるっぽい。

とりあえず、<c:foreach>単独では再描画は無理っぽい。

あとは、JavaScriptを使って再描画できるのかもしらんけど、フロントエンドに詳しくないので、今回はJavaScriptを使う方法は考えない方向でいきます。

JSTL(JavaServer Pages Standard Tag Library)の<c:foreach>を再描画させてみる

試してみる。

利用するプロジェクトとしては、

ts0818.hatenablog.com

⇧ 上記の記事で作成したもので。

今回、追加したファイルなど。

コーディングは以下のような感じになりました。

■/spring-mvc-jsp/src/main/java/com/dto/form/RadioButtonDto.java

package com.dto.form;

import lombok.Data;

@Data
public class RadioButtonDto {

	private String label;
	
	private String value;
	
	private boolean checked;
	
}    

■/spring-mvc-jsp/src/main/java/com/form/SettingForm.java

package com.form;

import lombok.Data;

@Data
public class SettingForm {

	private String elevetorHandlingFlg;
	private String wheelchairHandlingFlg;
	private String aedHandlingFlg;
	
	private Boolean completeUpdate; 
	private Integer updateCount;
}    

■/spring-mvc-jsp/src/main/java/com/controller/SettingController.java

package com.controller;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.dto.form.RadioButtonDto;
import com.form.SettingForm;

@Controller
@RequestMapping("settingController")
public class SettingController {

	@ModelAttribute
	public SettingForm initForm() {
		SettingForm settingForm = new SettingForm();
		return settingForm;
	}

	/**
	 * 表示
	 * @param settingForm
	 * @return
	 */
	@RequestMapping("currentSetting")
	public ModelAndView settingForm(SettingForm settingForm) {
		ModelAndView mv = new ModelAndView("setting/index");
		
		// TODO:データベースから取得
		
		// ラジオボタンを生成
		List<RadioButtonDto> elevetorHandlingFlgList = makeRadioButton(makeMapForHandlingFlg(), settingForm.getElevetorHandlingFlg());
		List<RadioButtonDto> wheelchairHandlingFlgList = makeRadioButton(makeMapForHandlingFlg(), settingForm.getWheelchairHandlingFlg());
		List<RadioButtonDto> aedHandlingFlgList = makeRadioButton(makeMapForHandlingFlg(), settingForm.getAedHandlingFlg());

		mv.addObject("elevetorHandlingFlgList", elevetorHandlingFlgList);
		mv.addObject("wheelchairHandlingFlgList", wheelchairHandlingFlgList);
		mv.addObject("aedHandlingFlgList", aedHandlingFlgList);
		if (Objects.nonNull(settingForm.getCompleteUpdate()) 
				&& settingForm.getCompleteUpdate()) {
			settingForm.setCompleteUpdate(false);
			mv.addObject("completeUpdate", true);
			int updateCount = settingForm.getUpdateCount();
			settingForm.setUpdateCount(++updateCount);
		} else {
			mv.addObject("completeUpdate", false);
			settingForm.setUpdateCount(0);
		}
		return mv;

	}
	
	/**
	 * 更新
	 * @param settingForm
	 * @return
	 */
	@RequestMapping("update")
	public ModelAndView updateSetting(SettingForm settingForm) {
		// TODO:データベースの更新
		
		settingForm.setCompleteUpdate(true);
		return settingForm(settingForm);
	}
	
	/**
	 * 削除
	 * @param settingForm
	 * @return
	 */
	@RequestMapping("delete")
	public ModelAndView deleteSetting(SettingForm settingForm) {
		// TODO:データベースの更新
		
		// フォームをリセット
		settingForm = deleteForm(settingForm);
		settingForm.setCompleteUpdate(true);
		return settingForm(settingForm);
	}
	
	/**
	 * ラジオボタンを作成
	 * @param radioButtonMap
	 * @param currentValue
	 * @return
	 */
	private static List<RadioButtonDto> makeRadioButton(Map<String, String> radioButtonMap, String currentValue) {
		
		List<RadioButtonDto> radioButtonDtoList = new ArrayList<>();
		for (Map.Entry<String, String> entry: radioButtonMap.entrySet()) {
			RadioButtonDto radioButtonDto = new RadioButtonDto();
			radioButtonDto.setLabel(entry.getKey());
			radioButtonDto.setValue(entry.getValue());
			
			if (entry.getValue().equals(currentValue)) {
				radioButtonDto.setChecked(true);
			} else {
				radioButtonDto.setChecked(false);
			}
			radioButtonDtoList.add(radioButtonDto);
		}
		return radioButtonDtoList;
	}
	
	/**
	 * 二択(有・無)のラジオボタン
	 * @return
	 */
	private static Map<String, String> makeMapForHandlingFlg() {
		Map<String, String> handlingFlgMap = new LinkedHashMap<String, String>(){
			{
				put("有", "1");
				put("無", "0");
			}
		};
		return handlingFlgMap;
	}
	
	/**
	 * 削除の場合のフォームの内容をリセット
	 * @param settingForm
	 * @return
	 */
	private static SettingForm deleteForm(SettingForm settingForm) {
		settingForm.setElevetorHandlingFlg(null);
		settingForm.setWheelchairHandlingFlg(null);
		settingForm.setAedHandlingFlg(null);
		return settingForm;
	}
}

■/spring-mvc-jsp/src/main/webapp/WEB-INF/views/setting/index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>設定画面</title>
</head>
<body>
	<form:form method="post" modelAttribute="settingForm">
		<c:if test="${settingForm.updateCount ge 0 }">
		  更新回数:${settingForm.updateCount}
		  	<div>
				<span>エレベーター取扱有無</span>
			</div>
			<c:forEach var="obj" items="${elevetorHandlingFlgList}"
				varStatus="status">
				<c:choose>
					<c:when test="${obj.checked}">
						<form:radiobutton 
						    path="elevetorHandlingFlg"
							id="elevetor-${status.index}" 
							label="${obj.label}"
							value="${obj.value}" 
							checked="checked" 
						/>
					</c:when>
					<c:otherwise>
						<form:radiobutton 
						   path="elevetorHandlingFlg"
							id="elevetor-${status.index}" 
							label="${obj.label}"
							value="${obj.value}"
						 />
					</c:otherwise>
				</c:choose>
			</c:forEach>
			<div>
				<span>車椅子利用可能有無</span>
			</div>
			<c:forEach var="obj" items="${wheelchairHandlingFlgList}"
				varStatus="status">
				<c:choose>
					<c:when test="${obj.checked}">
						<form:radiobutton 
						    path="wheelchairHandlingFlg"
							id="wheelchair-${obj.checked }" 
							label="${obj.label}"
							value="${obj.value}" 
							checked="checked" 
						/>
					</c:when>
					<c:otherwise>
						<form:radiobutton 
						    path="wheelchairHandlingFlg"
							id="wheelchair-${obj.checked }" 
							label="${obj.label}"
							value="${obj.value}" 
						/>
					</c:otherwise>
				</c:choose>

			</c:forEach>
			<div>
				<span>AED設置有無</span>
			</div>
			<c:forEach var="obj" items="${aedHandlingFlgList}" varStatus="status">
				<c:choose>
					<c:when test="${obj.checked }">
						<form:radiobutton 
						    path="aedHandlingFlg"
							id="aedHandlingFlg-${obj.checked }" 
							label="${obj.label}"
							value="${obj.value}" 
							checked="checked" 
						/>
					</c:when>
					<c:otherwise>
						<form:radiobutton 
						    path="aedHandlingFlg"
							id="aedHandlingFlg-${obj.checked }" 
							label="${obj.label}"
							value="${obj.value}" 
						/>
					</c:otherwise>
				</c:choose>
			</c:forEach>

		</c:if>
		<form:hidden path="updateCount" value="${updateCount}" />

		<div>
			<input type="submit" value="更新"
				formAction="${pageContext.request.contextPath}/settingController/update" />
			<input type="submit" value="削除"
				formAction="${pageContext.request.contextPath}/settingController/delete" />
		</div>
	</form:form>
</body>
</html>    

⇧ データベースとの連携は実装していないですが、<c:if test="">の判定が実施される度に、<c:foreach>が再描画されるようになりました。

・初期表示

・更新ボタン押下

・削除ボタン押下

まぁ、何て言うか、<c:foreach>のitemsの値が変わるのを検知して再描画するようにしてくれれば良いものを、何故か、そういう仕様にはしてくれていないので、力業で実装するしかないっぽい...

そもそも、今時、JSTL(JavaServer Pages Standard Tag Library)を使っているシステムが稀少なのかもしれませんが...

枯れた技術なはずなのに情報が少ないとか辛い...

毎度モヤモヤ感が半端ない...

今回はこのへんで。