ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [스프링MVC - 2편] 타임리프 스프링 통합 (1)
    스프링&스프링부트 2025. 2. 1. 17:45

    타임리프 스프링 통합

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

     

    스프링 통합으로 추가되는 기능들

    • 스프링의 SpringEL 문법 통합
    • ${@myBean.doSomething()}처럼 스프링  호출 지원
    • 편리한  관리를 위한 추가 속성
      • th:object (기능 강화,  커맨드 객체 선택)
      • th:field, th:errors, th:errorclass
    •  컴포넌트 기능
      • checkbox, radio button, List 등을 편리하게 사용할  있는 기능 지원
    • 스프링의 메시지, 국제화 기능의 편리한 통합
    • 스프링의 검증, 오류 처리 통합
    • 스프링의 변환 서비스 통합(ConversionService)

     

     

    1. 입력 처리

    • th:object : 커맨드 객체를 지정한다
    • *{...} : 선택 변수 식이라고 한다, th:object에서 선택한 객체에 접근한다
    • th:field : HTML 태그의 id, name, value 속성을 자동으로 처리해 준다
    • 렌더링 :<input type="text" th:field="*{itemName}" />
    • 렌더링  : <input type="text" id="itemName" name="itemName" th:value="*{itemName}" />

     

    2. 등록

    th:object 적용하려면 먼저 해당 오브젝트 정보를 넘겨주어야 한다

    등록 폼이기 때문에 데이터가 비어있는 오브젝트를 만들어서 뷰에 전달한다

     

     

     

    등록 폼

    FormItemController

    @GetMapping("/add")
    public String addForm(Model model) {
    	model.addAttribute("item", new Item());
    	return "form/addForm";
    }
    <form action="item.html" th:action th:object="${item}" method="post">
    <div>
    	<label for="itemName">상품명</label>
    	<input type="text" id="itemName" th:field="*{itemName}" class="form-control" placeholder="이름을 입력하세요">
    </div>
    '''
    • th:object="${item}" :<form>에서 사용할 객체를 지정한다. 선택 변수 식(*{...})을 적용할  있다
    • th:field="*{itemName}"
      • *{itemName}는 선택 변수 식을 사용했는데, ${item.itemName}과 같다 th:object로 item을 선택했기 때문에 선택 변수 식을 적용할  있다
      • th:field는 id, name, value 속성을 모두 자동으로 만들어준다
    • 렌더링 전 : <input type="text" id="itemName" th:field="*{itemName}" class="form-control" placeholder="이름을 입력하세요" >
    • 렌더링 후 : <input type="text" id="itemName" class="form-control" placeholder="이름을 입력하세요" name="itemName" value="">

     

     

     

    수정폼

    @GetMapping("/{itemId}/edit")
    public String editForm(@PathVariable Long itemId, Model model) {
    	Item item = itemRepository.findById(itemId);
    	model.addAttribute("item", item);
    	return "form/editForm";
    }
    <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>
    	<div>
    		<label for="itemName">상품명</label>
    		<input type="text" id="itemName" th:field="*{itemName}" class="form-control">
    	</div>
        '''

     

     

     

    요구사항 추가

    • 판매 여부 : 판매 오픈 여부 / 체크 박스로 선택할  있다
    • 등록 지역 : 서울, 부산, 제주 / 체크 박스로 다중 선택할  있다
    • 상품 종류 : 도서, 식품, 기타 / 라디오 버튼으로 하나만 선택할  있다
    • 배송 방식 : 빠른 배송, 일반 배송, 느린 배송 / 셀렉트 박스로 하나만 선택할  있다

     

     

     

    1. ItemType - 상품 종류 enum 추가

    2. 배송 방식 - DeliveryCode 추가

    3. Item - 상품 필드 추가

     

     

     

    체크 박스 - 단일1 ( 단순 HTML 체크박스)

    <!-- single checkbox -->
    <div>판매 여부</div>
    	<div>
    		<div class="form-check">
    		<input type="checkbox" id="open" name="open" class="form-check-input">
    		<label for="open" class="form-check-label">판매 오픈</label>
    	</div>
    </div>

    체크 박스를 체크하면 HTML Form에서 open=on이라는 값이 넘어간다

    스프링은 on이라는 문자를 true 타입으로 변환해준다

     

     

    문제 : 체크 박스를 선택하지 않을 때

    HTML에서 체크 박스를 선택하지 않고 폼을 전송하면 open이라는 필드 자체가 서버로 전송되지 않는다

    HTML checkbox 선택이 안되면 클라이언트에서 서버로 자체를 보내지 않는다

    수정의 경우에는 상황에 따라서 이 방식이 문제가 있다

    사용자가 의도적으로 체크되어 있던 값을 체크를 해제해도 저장시 아무 값도 넘어가지 않기 때문에, 서버 구현에 따라서 값이 오지 않은 것으로 판단해서 값을 변경하지 않을 수도 있다

     

     

    해결 : 체크 해제를 인식하기 위한 히든 필드 <input type="hidden" name="_open" value="on"/>

    <!-- single checkbox -->
    <div>판매 여부</div>
    	<div>
    		<div class="form-check">
    		<input type="checkbox" id="open" name="open" class="form-check-input">
            <!-- 히든 필드 추가 -->
    		<input type="hidden" name="_open" value="on"/> 
    		<label for="open" class="form-check-label">판매 오픈</label>
    	</div>
    </div>

    체크 박스 체크

    • open=on&_open=on
    • 체크 박스를 체크하면 스프링 MVC가 open에 값이 있는 것을 확인하고 사용한다
    • 이때 _open은 무시한다

    open=on&_open=on`

    체크 박스를 체크하면 스프링 MVC `open` 값이 있는 것을 확인하고 사용한다. 이때 `_open` 무시한다.

    **체크 박스 미체크**

    `_open=on`

    체크 박스를 체크하지 않으면 스프링 MVC `_open` 있는 것을 확인하고, `open` 값이 체크되지 않았다고 인식한

    .

    경우 서버에서 `Boolean` 타입을 찍어보면 결과가 `null` 아니라 `false` 것을 확인할 있다.

     

    체크 박스 미체크

    • _open=on
    • 체크 박스를 체크하지 않으면 스프링 MVC _open만 있는 것을 확인하고, open의 값이 체크되지 않았다고 인식한다
    •  경우 서버에서 Boolean 타입을 찍어보면 결과가 null이 아니라 false이다

     

     

     

    체크 박스 - 단일2 ( 타임리프)

    <div>판매 여부</div>
    <div>
        <div class="form-check">
            <input type="checkbox" id="open" th:field="*{open}" class="form-check-input">
            <label for="open" class="form-check-label">판매오픈</label>
        </div>
    </div>

    타임리프를 사용하면 체크 박스의 히든 필드와 관련된 부분도 함께 해결해준다

    HTML 생성 결과를 보면 히든 필드 부분이 자동으로 생성되어 있다

     

     

     

    상품 상세에 적용 - item.html

    <div>판매 여부</div>
    <div>
        <div class="form-check">
            <input type="checkbox" id="open" th:field="${item.open}" class="form-check-input" disabled>
            <label for="open" class="form-check-label">판매오픈</label>
        </div>
    </div>

    타임리프의 체크 확인 - checked="checked"

    체크 박스에서 판매 여부를 선택해서 저장하면, 조회시에 checked 속성이 추가되었다

    타임리프의 th:field 사용하면, 값이 true 경우 체크를 자동으로 처리해 준다

    728x90
Designed by Tistory.