[스프링 MVC - 2편] 타임리프 - 스프링 통합과 폼

지현·2021년 12월 29일
0

스프링

목록 보기
23/32

타임리프 스프링 통합

타임리프는 스프링 없이도 동작하지만, 스프링과 통합을 위한 다양한 기능을 편리하게 제공


입력 폼 처리

  • th:object 를 적용하려면 먼저 컨트롤러에서 해당 오브젝트 정보를 model로 넘겨주어야 함 (빈 값이여도)
  • th:object="${item}" : <form> 에서 사용할 객체를 지정
  • th:field="*{itemName}"
    • th:object를 사용했기 때문에 선택 변수 식(*{...}) 적용 가능
    • th:field="${item.itemName}" == th:object="${item}", th:field="*{itemName}"
  • th:field 는 id , name , value 속성을 모두 자동으로 생성해줌
    • id : th:field 에서 지정한 변수 이름과 같음
    • name : th:field 에서 지정한 변수 이름과 같음
    • value : th:field 에서 지정한 변수의 값을 사용
  • th:object의 영향 범위는 해당 폼 내부에서만 영향을 줌

th:object 사용 이전

<form action="item.html" th:action method="post">
        <div>
            <label for="id">상품 ID</label>
            <input type="text" id="id" name="id" th:value="${item.id}" class="form-control" readonly>
        </div>
</form>

th:object 사용 이후

<form action="item.html" th:action th:object="${item}" method="post">
        <div>
            <label for="id">상품 ID</label>
            <input type="text" id="id" th:field="*{id}" class="form-control" readonly>
        </div>
</form>
  • id 속성도 제거해도 됨

체크 박스 - 단일1

단순 html 체크 박스

<div class="form-check">
 <input type="checkbox" id="open" name="open" class="form-check-input">
 <label for="open" class="form-check-label">판매 오픈</label>
 </div>
  • 체크 박스를 체크하면 HTML Form에서 open=on 이라는 값이 넘어감 > 스프링은 on 이라는 문자를 true 타입으로 변환
  • 체크 박스를 선택하지 않을 때 HTML에서 체크 박스를 선택하지 않고 폼을 전송하면 open 이라는 필드 자체가 서버로 전송되지 않음 > 스프링에서 false가 아닌 null이 입력됨
  • HTML checkbox는 선택이 안되면 클라이언트에서 서버로 값 자체를 보내지 않아서 수정의 경우에는 상황에 따라서 이 방식이 문제가 될 수 있음

문제 해결

<input type="checkbox" id="open" name="open" class="form-check-input">
 <input type="hidden" name="_open" value="on"/> <!-- 히든 필드 추가 -->
  • 스프링 MVC는 히든 필드를 하나 만들어서, _open 처럼 기존 체크 박스 이름 앞에 언더스코어( __ )를 붙여서 전송하면 체크를 해제했다고 인식
  • 히든 필드는 항상 전송됨
  • 체크 박스 체크
    • open=on&_open=on
    • 체크 박스를 체크하면 스프링 MVC가 open 에 값이 있는 것을 확인하고 사용
    • 이때 _open 은 무시
  • 체크 박스 미체크
    • _open=on
    • 체크 박스를 체크하지 않으면 스프링 MVC가 _open 만 있는 것을 확인하고, open 의 값이 체크되지 않았다고 인식
    • 이 경우 boolean 값은 null 이 아닌 false

체크 박스 - 단일2

<div> <div class="form-check">
 <input type="checkbox" id="open" th:field="*{open}" class="form-checkinput">
 <label for="open" class="form-check-label">판매 오픈</label>
 </div>
</div>
  • 타임리프를 사용하면 체크 박스의 히든 필드와 관련된 부분도 함께 해결해줌
  • HTML 생성 결과를 보면 타임리프가 히든필드를 자동으로 생성
    <input type="hidden" name="_open" value="on"/>
  • checked="checked"
    • 체크 박스에서 판매 여부를 선택해서 저장하면, 조회시에 checked 속성이 추가되어있음
    • 타임리프의 th:field를 사용하면, 값이 true인 경우 체크를 자동으로 처리해주기 때문
    • 값이 true면 checked 속성을 넣고, 값이 false면 checked 속성을 넣지 않음

체크 박스 - 멀티

@ModelAttribute의 특별한 사용법

    @ModelAttribute("regions")
    public Map<String,String> regions(){
        Map<String, String> regions= new LinkedHashMap<>();
        // HashMap은 순서가 보장이 되지 않기 때문에 LinkedHashMap을 쓰면 순서대로 들어감
        regions.put("SEOUL","서울");
        regions.put("BUSAN","부산");
        regions.put("JEJU","제주");
        return regions;
    }
  • @ModelAttribute는 컨트롤러에 있는 별도의 메서드에 적용 가능
  • 해당 컨트롤러를 요청할 때 regions 에서 반환한 값이 자동으로 모델(model)에 담기게 됨
  • 어떤 컨트롤러의 메서드가 호출이 되든 자동으로 모델에 다 담기게 됨 > 여러 컨트롤러에서 사용하는 데이터이면 model.addAttribute(...) 을 사용하는 코드 중복을 제거할 수 있음
        <!-- multi checkbox -->
        <div>
            <div>등록 지역</div>
            <div th:each="region : ${regions}" class="form-check form-check-inline">
                <input type="checkbox" th:field="*{regions}" th:value="${region.key}"
                       class="form-check-input">
                <label th:for="${#ids.prev('regions')}"
                       th:text="${region.value}" class="form-check-label">서울</label> </div>
        </div>
  • th:for="${#ids.prev('regions')}"
    • 멀티 체크박스는 같은 이름의 여러 체크박스를 만들 수 있는데, 생성된 HTML 태그 속성에서 name 은 같아도 되지만, id 는 모두 달라야 함
    • 타임리프는 체크박스를 each 루프 안에서 반복해서 만들 때 임의로 1, 2, 3 숫자를 뒤에 붙여줌
    • HTML의 id 가 타임리프에 의해 동적으로 만들어지기 때문에 <label for="id 값"> 으로 label의 대상이 되는 id 값을 임의로 지정하면 안됨
    • 타임리프는 ids.prev(...) , ids.next(...)을 제공 > 동적으로 생성되는 id 값 사용 가능
  • th:field="*{regions}"를 사용하면 히든 필드도 자동 생성
  • checked="checked"
    • 멀티 체크 박스에서 등록 지역을 선택해서 저장하면, 조회시에 checked 속성이 추가 되어있음
    • 타임리프는 th:field 에 지정한 값과 th:value 의 값을 비교해서 체크를 자동으로 처리
      • ex) th:field의 item.regions에 ["SEOUL","BUSAN"]이 체크되어 저장 되어있을 때 th:value로 SEOUL, BUSAN, JEJU를 순서대로 돌면서 th:field의 item.regions에 해당 값이 있으면 checked

라디오 버튼

        <!-- radio button -->
        <div>
            <div>상품 종류</div>
            <div th:each="type : ${itemTypes}" class="form-check form-check-inline">
                <input type="radio" th:field="*{itemType}" th:value="${type.name()}"class="form-check-input">
                <label th:for="${#ids.prev('itemType')}" th:text="${type.description}"
                       class="form-check-label">
                    BOOK
                </label>
            </div>
        </div>
  • 라디오 버튼은 여러 선택지 중에 하나를 선택할 때 사용
  • 라디오 버튼은 한번 클릭하면 수정으로 값을 null로 바꾸지 못하기 때문에(무조건 하나 선택해야함) 히든 필드가 필요 없음
  • 라디오 버튼에서 선택해서 저장하면, 조회시에 해당 선택지에 checked="checked" 속성이 추가되어 있음

셀렉트 박스

        <!-- SELECT -->
        <div>
            <div>배송 방식</div>
            <select th:field="*{deliveryCode}" class="form-select">
                <option value="">==배송 방식 선택==</option>
                <option th:each="deliveryCode : ${deliveryCodes}" th:value="${deliveryCode.code}"
                        th:text="${deliveryCode.displayName}">FAST</option>
            </select>
        </div>
  • 셀렉트 박스는 여러 선택지 중에 하나를 선택할 때 사용
  • <select> 태그를 사용
  • 맨 위에 <option>은 기본 옵션(아무것도 선택하지 않았을 때), 그 아래는 옵션을 여러개 생성해야함
  • 선택한 항목에 selected 속성이 추가됨 > th:field="*{deliveryCode}"th:value="${deliveryCode.code}"를 타임리프가 비교해서 값이 같으면 selected="selected" 속성 추가


출처
[인프런] 스프링 MVC 2편 - 백엔드 웹 개발 활용 기술

0개의 댓글