Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 자바의 정석 기초편 ch7
- 자바의 정석 기초편 ch8
- 스프링 mvc2 - 검증
- 2024 정보처리기사 시나공 필기
- 게시글 목록 api
- jpa 활용2 - api 개발 고급
- 자바의 정석 기초편 ch4
- 스프링 입문(무료)
- 스프링 db1 - 스프링과 문제 해결
- 스프링 mvc2 - 타임리프
- 스프링 mvc1 - 서블릿
- 스프링 mvc2 - 로그인 처리
- 코드로 시작하는 자바 첫걸음
- jpa - 객체지향 쿼리 언어
- 자바의 정석 기초편 ch11
- 타임리프 - 기본기능
- 2024 정보처리기사 수제비 실기
- 자바의 정석 기초편 ch2
- 자바의 정석 기초편 ch5
- 스프링 db2 - 데이터 접근 기술
- 자바의 정석 기초편 ch3
- @Aspect
- 자바의 정석 기초편 ch1
- 스프링 고급 - 스프링 aop
- 자바의 정석 기초편 ch6
- 스프링 mvc1 - 스프링 mvc
- 자바의 정석 기초편 ch9
- 자바의 정석 기초편 ch14
- 자바의 정석 기초편 ch12
- 자바의 정석 기초편 ch13
Archives
- Today
- Total
나구리의 개발공부기록
타임리프 - 스프링 통합과 폼, 프로젝트 설정, 타임리프 스프링 통합, 입력 폼 처리, 요구사항 추가 본문
인프런 - 스프링 완전정복 코스 로드맵/스프링 MVC 2편 - 백엔드 웹 개발 핵심 기술
타임리프 - 스프링 통합과 폼, 프로젝트 설정, 타임리프 스프링 통합, 입력 폼 처리, 요구사항 추가
소소한나구리 2024. 5. 27. 23:08 출처 : 인프런 - 스프링 MVC 2편 - 백엔드 웹 개발 핵심 기술 (유료) / 김영한님
유료 강의이므로 정리에 초점을 두고 코드는 일부만 인용
1. 프로젝트 설정
1) 프로젝트 설정
- 강의에서 제공하는 프로젝트가 있으나, 버전업이 많이 된 관계로 새로 프로젝트를 생성
(1) 프로젝트
- Gradle
- Java 17
- Spring Boot 3.3.0
(2) Metadata
- Group: hello
- Artifact: item-service
- Package name: hello.itemservice
- Packaging: Jar
(3) Dependencies
- Spring Web
- Thymeleaf
- Lombok
(4) 추가 작업
- 기존 프로젝트에 있는 클래스 파일들은 가져온 상태에서 진행
- settings.gradle의 프로젝트 이름을 form으로 변경
- hello하위 패키지 이름을 itemservice로 변경 후 Run/Debug 세팅의 경로도 hello.itemservice.ItemServiceApplication으로 변경
2. 타임리프 스프링 통합
1) 타임리프와 스프링
(1) 매뉴얼
- 기본 매뉴얼: https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html
- 스프링 통합 매뉴얼: https://www.thymeleaf.org/doc/tutorials/3.0/thymeleafspring.html
- 타임리프는 스프링 없이도 동작하지만 스프링과 통합을 위한 다양한 기능을 편리하게 제공함
(2) 스프링 통합으로 추가되는 기능들
- SpringEL 문법 통합
- ${@myBean.doSomething()} 처럼 스프링 빈 호출 지원
- 편리한 폼 관리를 위한 추가 속성
- th:object(기능 강화, 폼 커맨드 객체 선택)
- th:field, th:errors, th:errorclass - 폼 컴포넌트 기능
- checkbox, radio button, List 등을 편리하게 사용할 수 있는 기능 지원 - 스프링의 메시지, 국제화 기능의 편리한 통합
- 스프링의 검증, 오류 처리 통합
- 스프링의 변환 서비스 통합(ConversionService)
(3) 설정 방법
- 타임리프 템플릿 엔진을 스프링 빈에 등록하고, 타임리프용 뷰 리졸버를 스프링 빈으로 등록하는 방법
- https://www.thymeleaf.org/doc/tutorials/3.0/thymeleafspring.html#views-and-view-resolvers
- 원래는 위의 사이트에 들어가서 제공하는 방법대로 직접 스프링 빈으로 등록해야 하지만 스프링 부트는 이런 부분을 모두 자동화 해줌
- build.gradle에 다음의 한 줄을 넣어주면 Gradle은 타임리프와 관련된 라이브러리를 다운받고 스프링 부트는 타임리프와 관련된 설정용 스프링 빈을 자동으로 등록해줌(프로젝트 생성 시 thymeleaf를 추가했으면 자동으로 들어가 있음)
(4) Build.gradle
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
- 타임리프 관련 설정을 변경하고 싶다면 아래의 링크를 참고해서 application.properties에 추가하면 됨
3. 입력 폼 처리
1) 입력 폼 기능 적용
(1) 렌더링 전, 후 비교
- 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}" />
2) 등록 폼
(2) FormItemController - addForm()수정
- th:object를 적용하려면 먼저 오브젝트 정보를 넘겨주어야 함
- 등록 폼이기 때문에 데이터가 비어있는 빈 오브젝트를 만들어서 뷰에 전달
// th:object를 적용하기 위해 먼저 오브젝트 정보를 넘겨주기 위해 model.addAttribute로 빈 객체를 생성하여 정보를 넘겨줌
@GetMapping("/add")
public String addForm(Model model) {
model.addAttribute("item", new Item());
return "form/addForm";
}
(2) addForm.html 수정
- th:object="${item}": <form>태그 안의 범위에서 사용할 객체를 지정하고 선택 변수 식 *{...}을 적용할 수 있음
- th:field="*{itemName}"
- 선택 변수식은 &{item.itemName}과 동일하며 앞에서 th:object로 item을 선택했기 때문에 선택 변수식을 적용 할 수 있음
- th:field는 id, name, value 속성을 모두 자동으로 만들어 줌
- 즉, id 속성을 제거해도 th:field가 자동으로 만들어 주지만 IDE에서 에러가 난 것처럼 표시가 되어 해당 에러표시가 보기 싫으면 예제처럼 id를 유지해도 됨(선택 사항)
<!-- th:object="${item}" 추가-->
<form action="item.html" th:action th:object="${item}" method="post">
<div>
<label for="itemName">상품명</label>
<!-- th:object="${item}" 를 등록하여 id, name 을 모두 제거하고 th:field="*{label명}" 폼으로 id와 name을 자동으로 생성
*{itemName}은 ${item.itemName}과 동일하며 앞서 th:object로 item을 선택했기 때문에 변수식 적용이 가능
id도 삭제 가능하지만, IDE에서 에러가 발생하는 것처럼 보여서 그냥 유지 -->
<!-- <input type="text" id="itemName" name="itemName" class="form-control" placeholder="이름을 입력하세요">-->
<input type="text" id="itemName" th:field="*{itemName}" class="form-control" placeholder="이름을 입력하세요">
</div>
<div>
<label for="price">가격</label>
<!-- <input type="text" id="price" name="price" class="form-control" placeholder="가격을 입력하세요">-->
<input type="text" id="price" th:field="*{price}" class="form-control" placeholder="가격을 입력하세요">
</div>
<div>
<label for="quantity">수량</label>
<!-- <input type="text" id="quantity" name="quantity" class="form-control" placeholder="수량을 입력하세요">-->
<input type="text" id="quantity" th:field="*{quantity}" class="form-control" placeholder="수량을 입력하세요">
</div>
3) 수정 폼
- controller의 코드는 수정할게 없으므로 생략(원래의 코드에서 Model을 넘기고 있음)
(1) editForm.html 수정
- 길었던 코드가 id, name, value를 자동으로 생성해주는 th:field="*{...}"덕에 매우 간결해진 것을 확인할 수 있음
<!-- th:object="${item}" 추가-->
<form action="item.html" th:action th:object="${item}" method="post">
<div>
<label for="id">상품 ID</label>
<!- addForm의 내용처럼 id, name value를 지우고 th:field="${label명}" 폼으로 대체할 수 있음-->
<!-- <input type="text" id="id" name="id" class="form-control" value="1" th:value="${item.id}" readonly>-->
<input type="text" id="id" th:field="*{id}" class="form-control" readonly>
</div>
<div>
<label for="itemName">상품명</label>
<!-- <input type="text" id="itemName" name="itemName" class="form-control" value="상품A" th:value="${item.itemName}">-->
<input type="text" id="itemName" th:field="*{itemName}" class="form-control">
</div>
<div>
<label for="price">가격</label>
<!-- <input type="text" id="price" name="price" class="form-control" value="10000" th:value="${item.price}">-->
<input type="text" id="price" th:field="*{price}" class="form-control">
</div>
<div>
<label for="quantity">수량</label>
<!-- <input type="text" id="quantity" name="quantity" class="form-control" value="10" th:value="${item.quantity}">-->
<input type="text" id="quantity" th:field="*{quantity}" class="form-control">
</div>
4. 요구사항 추가
1) 추가된 요구 사항
(1) 기존 상품 서비스에 요구사항이 추가 되었다고 가정
- 판매 여부
- 판매 오픈 여부
- 체크 박스로 선택 - 등록 지역
- 서울, 부산, 제주
- 체크 박스로 다중 선택 - 상품 종류
- 도서, 식품, 기타
- 라디오 버튼으로 하나만 선택 - 배송 방식
- 빠른배송, 일반 배송, 느린 배송
- 셀렉트 박스로 하나만 선택
2) 기능 추가
(1) ItemType - 상품종류
- domain.item패키지에 Enum으로 생성
- 설명을 위해 description필드를 추가
package hello.itemservice.domain.item;
public enum ItemType {
BOOK("도서"), FOOD("음식"), ETC("기타");
private final String description; // 설명을 위한 description 필드 추가
ItemType(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
(2) DeliveryCode - 배송방식
- Class로 생성
- code는 FAST, NORMAL 처럼 시스템에 전달하는 값
- displayName은 빠른 배송, 일반 배송 처럼 고객에게 보여주는 값
package hello.itemservice.domain.item;
/**
* FAST: 빠른 배송
* NORMAL: 일반 배송
* SLOW: 느린 배송
*/
@Data
@AllArgsConstructor
public class DeliveryCode {
private String code; // 시스템에서 전달하는 값
private String displayName; // 고객에게 보여주는 값
}
(3) Item 수정
package hello.itemservice.domain.item;
@Data
public class Item {
// ... 기존 코드 생략
private Boolean open; // 판매 여부
private List<String> regions; // 등록 지역
private ItemType itemType; // 상품 종류
private String deliveryCode; // 배송 방식
// ... 기존 코드 생략
}