개발일기
스프링과 통합과 폼 본문
편리한 폼 관리를 위한 속성
- th:object(기능 강화, 폼 커맨드 객체 선택)
- th:field, th:errors, th:errorclass
폼 컴포넌트 기능
- checkbox, radio button, List 등을 편리하게 사용할 수 있는 기능 지원
스프링의 멕시지, 국제화 기능의 편리한 통합
스프링의 변환 서비스 통합(ConversionService)
입력 폼 처리
- 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}"/>
등록 폼
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" placeholer="이름을 입력하세요">
</div>
<div>
<label for="price">가격</label>
<input type="text" id="price" th:field="*{price}" class=form-control" placeholder="가격을 입력하세요">
</div>
<div>
<label for="quantity">수량</label>
<input type="text" id="quntity" th:field="*{quantity}" class="form-control" placeholder="수량을 입력하세요">
</div>
- th:object="${item}" : <form> 에서 사용할 객체를 지정한다. 선택 변수 식(*{...}) 을 적용할 수 있다.
- th:field = "*{itemName}"
- *{itemName} 는 선택 변수 식을 사용했는데, ${item.itemName}과 같다. 앞서 th:object로 item을 선택했기 때문에 선택 변수 식을 적용할 수 있다.
- th:field는 id, name, value 속성을 모두 자동으로 만들어준다.
- id: th:field에서 지정한 변수 이름과 같다. id="itemName"
- name: th:field에서 지정한 변수이름과 같음
- value: th:field에서 지정한 변수의 값을 사용한다. value=" "
참고로 해당 예제에서는 id속성을 제거해도 th:field가 자동으로 만들어준다.
렌더링 전
<input type="text" id="itemName" th:field="*{itemName}" class="form-control" placeholder="이름을 입력하세요">
수정 폼
@GetMapping("/{itemId}/edit")
public String editForm(@PathVariable Long itemId, Model model) {
Item item = itemRepository.findById(itemId);
model.addAttibute("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>
<div>
<label for="price">가격</label>
<input type="text" id="price" th:field="*{price}" class="form-control">
</div>
<div>
<label for="quantity">수량</label>
<input type="text" id="quantity" th:field="*{quantity}" class="form-control">
</div>
체크 박스, 라디오 버튼 , 셀렉트 박스
상품 종료
public enum ItemType {
BOOK("도서"), FOOD("식품"), ETC("기타");
private final String description;
ItemType(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
배송 방식 - DeliveryCode
@Data
@AllArgsConstructor
public class DeliveryCode {
private String code;
private String displayName;
}
그외 Item 객체
체크 박스 - 단일 1
단순 HTML 체크 박스
<hr class="my-4">
<div>판매 여부</div>
<div>
<div class="form-check">
<input type="checkbox" id="open" name="open" class="form-chekc-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 : item.open=true //체크 박스를 선택하는 경우
FormItemController : item.open=null //체크 박스를 선택하지 않는 경우
체크 박스를 선택하지 않을 때
HTML에서 체크 박스를 선택하지 않고 폼을 전송하면 open이라는 필드 자체가 서버로 전송되지 않는다.
HTML checkbox는 선택이 안되면 클라이언트에서 서버로 값 자체를 보내지 않음. 수정의 경우에는 상황에 따라서 이 방식이 문제가 될 수 있음. 사용자가 의도적으로 체크되어 있던 값을 체크를 해제해도 저장시 아무값도 넘어가지 않기 때문에 , 서버 구현에 따라서 값이 오지 않은 것으로 판단하여 값 변경 안할 수 있음.
해당 문제를 해결하기 위해서는 스프링 mvc에서 약간의 트릭을 사용함. 히든 필드를 하나 만들어서, _open처럼 체크 박스 이름 앞에 언더스코어(_)를 붙여서 작성하면 정상적으로 해제 후에도 값이 넘어가진다.
체크 해제를 인식하기 위한 필드
<input type="hidden" name="_open" value="on"/>
기존 코드에 히든 필드 추가
<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
체크 박스 체크
'Spring > 백엔드 웹 개발 활용 기술' 카테고리의 다른 글
타임리프- 기본 기능 (0) | 2024.05.02 |
---|