[Spring MVC] [2] 2. 타임리프 - 스프링 통합과 폼

윤경·2021년 9월 16일
0

Spring MVC

목록 보기
16/26
post-thumbnail

[1] 프로젝트 설정

선생님이 올려주신 파일 중 form-start를 내 폴더에 받아 form으로 이름을 바꿔 사용
우리가 mvc1 강의에서 했던 간단한 프로젝트와 내용 같음. (선생님이 몇 가지만 바꾸신?)

그리고 코드를 넣었더니 게시물이 너무 길어져서 핵심 내용만 넣도록 해보겠다. (코드는 강의자료나 내가 가진 코드를 참고하자~~!)


[2] 타임리프 스프링 통합

타임리프가 제공하는 두가지 메뉴얼

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

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

  • SpringEL 문법 통합
  • ${@myBean.doSomething()}처럼 스프링 빈 호출 지원
  • 편리한 폼 관리를 위한 추가 속성
    - th:object (기능 강화, 폼 커멘드 객체 선택)
    • th:field, th:errors, th:errorclass
  • 폼 컴포넌트 기능
  • 스프링의 메시지, 국제화 기능의 편리한 통합(미국에서 들어오면 영어로)
  • 스프링의 검증, 오류 처리 통합
  • 스프링의 변환 서비스 통합 (ConversionService)

build.gradle에 implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'를 한 줄만 넣어주면 사용할 수 있다.


[3] 입력 폼 처리

th:object: 커멘트 객체를 지정
*{ }: 선택 변수 식. th:object에서 선택한 객체에 접근.
th:field: HTML 태그의 id, name, value 속성을 자동으로 처리 (id도 생략할 수 있지만 냅둔거임)

add, edit 부분 컨트롤러, 뷰 코드를 변경해 보았다.

왜 이렇게 하느냐

수정 폼의 경우 id, name, value를 모두 신경쓰지 않아도 된다. th:field덕분에 자동으로 처리되기 때문.

그리고 나중에 검증(Validation)에서 진짜 왜 쓰는지를 알 수 있을 것


[4] 요구사항 추가

📌 추가된 요구 사항

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

ENUM, 클래스, String 코드를 추가했고 일부러 다양한 상황을 준비했다.
각각의 상황에 어떻게 폼의 데이터를 받을 수 있는지 공부하자.


[5] 체크 박스 - 단일1

(체크 박스 체크를 안 하면 값이 아예 안 넘어감. open=false를 기대했지만 open=null이 됨.)

➡️ 그래서 히든필드 사용

즉,

체크박스를 체크하면 HTML Form에서 open=on이라는 값이 넘어가는데 스프링은 on→true로 변환해준다.

그런데 문제는 체크박스를 체크하지 않았을 때 false라는 값을 넘겨받지 못하는 것.

이는 _open이라는 ⭐️ 히든필드를 사용함으로써 해결할 수 있었다.

HTML checkbox는 선택이 안되면 클라이언트에서 서버로 값 자체를 보내지 않는데 수정시 이것이 문제가 될 수 있다. 사용자가 의도적으로 체크되어 있던 값을 해제해도 저장시 아무 값이 넘어가지 않아 값이 변경되지 않을 수 있다.

히든 필드는 _open처럼 기존 체크박스 이름 앞에 _를 붙여 전송하면 체크를 해제한 경우에는 open이 전송되지 않고, _open만 전송되는데 이때 스프링 MVC는 체크를 해제했다고 판단할 수 있다.

체크박스 체크
open=on&_open=on
스프링 MVC가 앞에 있는 값을 사용하고 _open 무시

체크박스 미체크
_open=on
하나 밖에 없어서 open 값이 체크되지 않았다는 것을 인식함
이 경우 서버에서 boolean 타입을 찍어보면 null이 아니라 false인 것을 확인할 수 있음


[6] 체크 박스 - 단일2

개발할 때마다 히든 필드를 추가하기엔 모든걸 귀찮아하는 개발자들이 가만 놔둘리가 없다.

타임리프가 제공하는 폼 기능을 이용하자.

⭐️ th:field=""

⬆️ 상품 상세에서는 체크박스를 수정할 수 없도록 disable

📌 타임리프의 체크 확인 checked="checked"
조회시 checked 속성이 추가되기 때문에 예전에 배웠듯 checked라는 속성이 존재만해도 체크해버린다.
이런 부분을 개발자가 직접 처리하려면 번거로우니까 또 타임리프 기능을 이용하자.

th:field를 사용하면 값이 true인 경우 체크를 자동으로 처리해준다.

ItemRepository.java 파일의 update()에 findItem 코드를 추가해 변경 사항을 반영할 수 있었다.


[7] 체크 박스 - 멀티

: 하나 이상 체크(다중 선택)

new LinkedHashMap<>();: 그냥 해시맵을 쓰면 순서가 보장되지 않으므로 LinkedHashMap 사용

📌 @ModelAttribute특별한 사용법
(어떤 메소드가 호출되든 모델에 다 담김)
등록 폼, 상세화면, 수정 폼에서 모두 서울, 부산, 제주라는 체크 박스를 반복해 보여줘야 한다.

그러면 각각의 컨트롤러에서 model.addAttribute()를 사용해 체크 박스를 구성하는 데이터를 반복해 넣어줘야 한다.

@ModelAttribute는 이렇게 컨트롤러가 있는 별도의 메소드에 적용할 수 있다.

해당 컨트롤러를 요청할 때 regions에서 반환한 값이 자동으로 모델에 담기게 된다.
(이렇게 말고 각각의 컨트롤러 메소드에서 모델에 직접 데이터를 담아 처리해도 됨)

th:for="${#ids.prev('regions')}": (이렇게 안 하면 다 같이 한 아이디를 쓰므로 안 됨.)
멀티 체크박스는 같은 이름의 여러 체크박스를 만들 수 있지만 반복해 HTML 태그를 생성할 때 생성된 HTML 태그 속성에서 name은 같아도 되지만 id는 모두 달라야 한다.

타임리프는 체크박스를 each 루프 안에서 반복해 만들 때 임의로 이름 뒤 1, 2, 3... 숫자를 붙여준다.

HTML의 id가 타임리프에 의해 동적으로 만들어지기 때문에 <label for="id 값">으로 label의 대상이 되는 id 값을 임의로 지정하는 것은 곤란하다. 타임리프는 ids.prev(), ids.next()을 제공해 동적으로 생성되는 id 값을 사용할 수 있도록 한다.

⬆️ 로그 출력하는 코드 삽입 후


[8] 라디오 버튼

: 하나만 선택 가능

ItemType.values(): 해당 ENUM의 모든 정보를 배열로 반환

라디오 버튼은 한 번 선택되면 값을 뺄 수 없다. 그러므로 수정시에도 항상 하나를 선택하도록 되어 있어 체크 박스와 달리 별도의 히든 필드가 필요 없다.

📌 타임리프에서 ENUM 직접 사용하기

해왔던 것처럼 모델에 ENUM을 담아 전달하는 대신 타임리프는 자바 객체에 직접 접근할 수 있다.

  • <div th:each="type : ${T(hello.itemservice.domain.item.ItemType).values()}">
    스프링 EL 문법으로 ENUM을 직접 사용할 수 있다. ENUM에 values()를 호출하면 해당 ENUM의 모든 정보가 배열로 반환된다.

하지만 !!
이렇게 사용하면 ENUM 패키지 위치가 변경될 때 자바 컴파일러가 타임리프까지 컴파일 오류를 잡을 수 없으므로 추천하지 않는다.


[9] 셀렉트 박스


profile
개발 바보 이사 중

0개의 댓글