개발일기

스프링과 통합과 폼 본문

Spring/백엔드 웹 개발 활용 기술

스프링과 통합과 폼

한둥둥 2024. 5. 20. 15:16

편리한 폼 관리를 위한 속성 

  • 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