오봉이와 함께하는 개발 블로그
스프링 MVC 2 - 체크 박스 단일 본문
체크 박스 - 단일1
단순 HTML 체크 박스
resources/templates/form/addForm.html
에 추가하자
<hr class="my-4">
<!-- 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>
FormItemController 추가
@PostMapping("/add")
public String addItem(Item item, RedirectAttributes redirectAttributes) {
log.info("item.open={}", item.getOpen());
...
}
FormItemController
에 @Slf4j
추가
실행 로그
FormItemController : item.open=true //체크 박스를 선택하는 경우
FormItemController : item.open=null //체크 박스를 선택하지 않는 경우
체크 박스를 체크하면 HTML Form에서 원래는 open=on
이라는 값이 넘어가는데, 스프링은 on
이라는 문자를 true
타입으로 반환해준다.
(스프링 타입 컨버터가 이 기능을 수행한다)
HTML에서 체크 박스를 선택하지 않고 폼을 전송하면 open
이라는 필드 자체가 서버로 전송되지 않는다.
HTML checkbox는 선택이 안 되면 클라이언트에서 서버로 값 자체를 보내지 않는다.
수정의 경우 상황에 따라 문제가 될 수 있다.
사용자가 의도적으로 체크가 되어 있던 값을 체크를 해제해서 저장해도 저장시 아무 값도 넘어오지 않기 때문에 서버 구현에 따라 값이 오지 않은 것으로 판단해서 값을 변경하지 않을 수도 있다.
이런 문제 해결을 위해 스프링 MVC에서 트릭을 사용한다.
히든 필드를 하나 만들어서 기존 체크 박스 이름 앞에 언더바(_)
를 붙여서 정송하면 체크를 해제했다고 인식할 수 있다.
히든 필드는 항상 전송되기 때문에 체크를 해제한 경우 여기서 open
은 전송되지 않고, _open
만 전송되면 이 경우 스프링 MVC는 체크를 해제했다고 판단한다.
예시
<!-- 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>
FormItemController : item.open=true //체크 박스를 선택하는 경우
FormItemController : item.open=false //체크 박스를 선택하지 않는 경우
체크 박스 체크open=on&_open=on
체크 박스를 체크하면 스프링 MVC가 open
에 값이 있는 것을 확인하고 사용한다.
이때 _open
은 무시한다.
체크 박스 미체크_open=on
체크 박스를 체크하지 않으면 스프링 MVC가 _open
만 있는 것을 확인하고, open
의 값이 체크되지 않았다고 인식한다.
이 경우 서버에서 로그를 찍어보면 null이 아니라 false인 것을 확인할 수 있다.
체크 박스 - 단일2
개발할 때 마다 이렇게 히든 필드를 추가하는 것은 상당히 번거롭다.
타임리프가 제공하는 폼 기능을 사용하면 이런 부분을 자동으로 처리할 수 있다.
타임리프 - 체크 박스 코드 추가
<form action="item.html" th:object="${item}" th:action method="post">
<!-- 상위 코드 -->
<!-- single checkbox -->
<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>
th:object
를 사용하지 않았다면 th:field="${item.open}"
을 사용해야 한다.
타임리프 체크 박스 HTML 생성 결과
<!-- single checkbox -->
<div>판매 여부</div>
<div>
<div class="form-check">
<input type="checkbox" id="open" class="form-check-input" name="open" value="true">
<input type="hidden" name="_open" value="on"/>
<label for="open" class="form-check-label">판매 오픈</label>
</div>
</div>
타임리프를 사용하면 체크 박스의 히든 필드와 관련된 부분을 입력하지 않아도 자동으로 입력되어 있게 해준다.
HTML 생성 결과를 보면 히든 필드 부분이 자동으로 생성되어 있다.
실행 로그
FormItemController : item.open=true //체크 박스를 선택하는 경우
FormItemController : item.open=null //체크 박스를 선택하지 않는 경우
상품 상세 적용
<!-- single checkbox -->
<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>
주의 : item.html
에는 th:object
를 사용하지 않았기 때문에 th:field
부분에 ${item.open}
으로 적어주어야 한다.disabled
를 사용해서 상품 상세에서는 체크 박스가 선택되지 않도록 했다.
HTML 생성 결과
<hr class="my-4">
<!-- single checkbox -->
<div class="form-check">
<input type="checkbox" id="open" class="form-check-input" disabled name="open" value="true" checked="checked">
<label for="open" class="form-check-label">판매 오픈</label>
</div>
타임리프의 체크 확인checked="checked"
가 되어 있다.
체크 박스에서 선택해서 저장하면 조회할 때 checked
속성이 추가된 것을 확인할 수 있다.
이런 부분을 개발자가 직접 처리하려면 조건을 따로 달아서 보여줘야 하는 번거로움이 있는데, th:field
를 사용했을 때 값이 true
면 체크를 자동으로 처리해준다.
상품 수정 적용
상품 수정도 th:object
, th:field
를 모두 적용해야 한다.
<form action="item.html" th:object="${item}" th:action method="post">
<!-- 기존 코드 -->
<!-- single checkbox -->
<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>
이 상태로만 실행하면 체크 박스를 수정해도 반영되지 않기 때문에 실제 반영되도록 코드를 추가하자
@Repository
public class ItemRepository {
private static final Map<Long, Item> store = new HashMap<>(); //static
private static long sequence = 0L; //static
// 기존 코드
public void update(Long itemId, Item updateParam) {
Item findItem = findById(itemId);
findItem.setItemName(updateParam.getItemName());
findItem.setPrice(updateParam.getPrice());
findItem.setQuantity(updateParam.getQuantity());
findItem.setOpen(updateParam.getOpen());
findItem.setRegions(updateParam.getRegions());
findItem.setItemType(updateParam.getItemType());
findItem.setDeliveryCode(updateParam.getDeliveryCode());
}
// 기존 코드
}
출처 : 인프런 김영한 지식공유자님 강의 스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
'BE > Thymeleaf' 카테고리의 다른 글
스프링 MVC 2 - 라디오 버튼 (0) | 2022.08.18 |
---|---|
스프링 MVC 2 - 체크 박스 멀티 (0) | 2022.08.17 |
스프링 MVC 2 - 요구사항 추가 (0) | 2022.08.17 |
스프링 MVC 2 - 입력 폼 처리 (0) | 2022.08.17 |
스프링 MVC 2 - 타임리프 스프링 통합 (0) | 2022.08.17 |