본 프로젝트 자료는 김영한님의 스프링 MVC 2편 - 백엔드 웹 개발 활용 기술을 참고 제작됐음을 알립니다.
타임리프가 제공하는 입력 폼 기능을 적용해서 기존 프로젝트의 폼 코드를 효율적으로 개선해보고자 한다.
예제 코드
@GetMapping("/add")
public String addForm(Model model) {
model.addAttribute("item", new Item());
return "form/addForm";
}
HTML
수정 후 코드소스
참고로 해당 예제에서 id 속성을 제거해도 th:field 가 자동으로 만들어준다.
수정 폼
예제 코드
@GetMapping("/{itemId}/edit")
public String editForm(@PathVariable Long itemId, Model model) {
Item item = itemRepository.findById(itemId);
model.addAttribute("item", item);
return "form/editForm";
}
HTML
수정 폼은 앞서 설명한 내용과 같다.
수정 후 코드소스
위에 배운 내용들로 체크박스, 라디오 버튼, 셀렉트 박스를 편리하게 사용하는 방법을 만들어 보고자 한다.
다음 요구사항
위 요구사항 관련 예시(사진)
예제 코드
public enum ItemType {
BOOK("도서"), FOOD("음식"), ETC("기타");
private final String description;
ItemType(String description) {
this.description = description;
}
}
상품 종류는 ENUM 을 사용.
/**
* FAST : 빠른 배송
* NORMAL : 일반 배송
* SLOW : 느린 배송
*/
@Data
@AllArgsConstructor
public class DeliveryCode {
private String code;
private String displayName;
}
배송 방식은 DeliveryCode 라는 클래스를 사용.
code 는 FAST 같은 시스템에서 전달하는 값이고, displayName 은 빠른 배송 같은 고객에게 보여주는 값이다.
@Data
public class Item {
private Long id;
private String itemName;
private Integer price;
private Integer quantity;
private Boolean open; // 판매 여부
private List<String> regions; // 등록 지역
private ItemType itemType; // 상품 종류
private String deliveryCode; // 배송 방식
public Item() {
}
public Item(String itemName, Integer price, Integer quantity) {
this.itemName = itemName;
this.price = price;
this.quantity = quantity;
}
}
등록 준비
판매 여부를 확인하기 위한 체크박스(단일) 를 만들고자 한다.
HTML
상품 등록이 제대로 넘어오는지 체크해보기 위해 로그를 사용해보자.
@Slf4j 애노테이션 추가 필수*
실행 결과
체크박스가 생긴 것을 확인 할 수 있고, 이후 체크하고 상품 등록을 누를 시
로그로 넘어왔다는 것을 확인 할 수 있다.
체크 박스를 체크하지 않으면 스프링 MVC가 _open 만 있는 것을 확인하고, open 의 값이 체크되지 않았다고 인식한다.
이 경우 서버에서 Boolean 타입을 찍어보면 결과가 null 이 아니라 false 인 것을 확인할 수 있다.
하지만 이대로 냅두면 상품 등록 후 나와도 박스를 체크 혹은 해제가 가능하다.
이 부분을 수정해야 한다.
우선 상품 상세 관련 클래스에 들어가 같은 코드를 넣어두자.
disabled 를 사용해서 상품 상세에서는 체크 박스가 선택되지 않도록 작업해주면
체크박스를 수정으로 들어가지 않는 이상 막을 수 있다.
체크 박스를 멀티로 사용해서, 하나 이상을 체크할 수 있도록 해보자.
예제 코드
@ModelAttribute("regions")
public Map<String, String> regions() {
Map<String, String> regions = new LinkedHashMap<>();
regions.put("SEOUL", "서울");
regions.put("BUSAN", "부산");
regions.put("JEJU", "제주");
return regions;
}
이것을 넣어주면 regions 으로 지역들을 간편하게 사용할 수 있다.
등록, 수정, 상세화면 폼에 모두 체크 박스를 반복해서 보여줘야 하는데, @ModelAttribute 를 사용하면 regions로 모든 지역을 넣어줄 수 있다.
나머지 폼에도 체크 박스 - 단일 와 같이 등록하면 된다.
라디오 버튼은 여러 선택지 중에 하나를 선택할 때 사용할 수 있다.
예제 코드
@ModelAttribute("itemTypes")
public ItemType[] itemTypeps() {
return ItemType.values();
}
위와 마찬가지로 타임리프에서 지원하는 편의기능 @ModelAttribute 를 사용
@ModelAttribute("itemTypes")
public ItemType[] itemTypeps() {
return ItemType.values();
}
HTML
상품 등록 폼에 기능을 추가
라디오 버튼은 이미 선택이 되어 있다면, 수정시에도 항상 하나를 선택하도록 되어 있으므로 체크 박스와 달리 별도의 히든 필드를 사용할 필요가 없다.
나머지 폼들도 위와 같이 수정해서 넣어주면 된다.
주의: 타임리프에서 ENUM 을 직접 사용할 수 있다.
@ModelAttribute("itemTypes")
public ItemType[] itemTypeps() {
return ItemType.values();
}
위 코드 없이
${T(hello.itemservice.domain.item.ItemType).values()}" 스프링EL 문법으로 ENUM을 직접 사용할 수 있지만, 나중에 수정할 사항이 생겼을 때 찾는데 복잡할 수 있어 사용하는거 추천하지 않는다.
셀렉트 박스는 여러 선택지 중에 하나를 선택할 때 사용할 수 있다.
예제 코드
@ModelAttribute("deliveryCodes")
public List<DeliveryCode> deliveryCodes() {
List<DeliveryCode> deliveryCodes = new ArrayList<>();
deliveryCodes.add(new DeliveryCode("FAST", "빠른 배송"));
deliveryCodes.add(new DeliveryCode("NORMAL", "일반 배송"));
deliveryCodes.add(new DeliveryCode("SLOW", "느린 배송"));
return deliveryCodes;
}
DeliveryCode 를 등록 폼, 조회, 수정 폼에서 모두 사용하므로 위와 똑같이 @ModelAttribute 를 사용했다.
*참고: @ModelAttribute 가 있는 deliveryCodes() 메서드는 컨트롤러가 호출 될 때 마다 사용되므로 deliveryCodes 객체도 계속 생성된다. 이런 부분은 미리 생성해두고 재사용하는 것이 더 효율적이다.
HTML
셀럭트 박스는 select 를 사용해서 만들면 되고, 나머지는 위와 같은 방식이라 설명을 생략하겠다.
끝