스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 대시보드 - 인프런 | 강의 (inflearn.com)
스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 - 인프런 | 강의
웹 애플리케이션 개발에 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. MVC 2편에서는 MVC 1편의 핵심 원리와 구조 위에 실무 웹 개발에 필요한 모든 활용 기술들을 학습할 수 있
www.inflearn.com
타임리프 스프링 통합으로 추가되는 기능들
- 스프링의 SpringEL 문법 통합
- ${@myBean.doSomething()} 처럼 스프링 빈 호출 지원
- 편리한 폼 관리를 위한 추가 속성
- th:object (기능 강화, 폼 커맨드 객체 선택)
- th:field , th:errors , th:errorclass
- 폼 컴포넌트 기능
- checkbox, radio button, List 등을 편리하게 사용할 수 있는 기능 지원
- 스프링의 메시지, 국제화 기능의 편리한 통합
- 스프링의 검증, 오류 처리 통합
- 스프링의 변환 서비스 통합(ConversionService)
입력 폼 처리
Controller에서 빈 item 객체를 생성해서 넘겨줌
th:field="${item.~~~~}" 사용하면 id = "~~~~", name = "~~~~", value = "~~~~" 자동으로 생성
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
<form action="item.html" th:object="${item}" th:action method="post">
<div>
<label for="id">상품 ID</label>
<input type="text" id="id" name="id" class="form-control" value="1" th:value="${item.id}" readonly>
</div>
<div>
<label for="itemName">상품명</label>
<input type="text" id="itemName" name="itemName" class="form-control" value="상품A" th:value="${item.itemName}">
</div>
<div>
<label for="price">가격</label>
<input type="text" id="price" name="price" class="form-control" value="10000" th:value="${item.price}">
</div>
<div>
<label for="quantity">수량</label>
<input type="text" id="quantity" name="quantity" class="form-control" value="10" th:value="${item.quantity}">
</div>
....
</form>
|
cs |
form에서 th:object="${item}" 사용
th:field="*{itemName}" -> item.itemName
th:field="*{price}" -> item.price
th:field="*{quantity}" -> item.quantity
체크 박스 - 단일1
check 하면 on 넘어옴 -> true로 변환
check 안하면 check가 아예 사라짐-> null로 넘어감
수정 시 문제 발생 가능
체크 했다가 해제 -> null 넘어감 -> 아무 작업도 안 한 것으로 판단할 수 있음 -> 값 수정 안됨
Spring에서 체크 해제를 인식하기 위한 히든 필드 기능
<input type="checkbox" id="open" name="open" class="form-check-input">
<input type="hidden" name="_open" value="on"/>
실행 로그
item.open=true // 선택 O
item.open=false // 선택 X
※ 단점: 일일히 추가해야 함
체크 박스 - 단일2
th:field="*{open}": 히든 필드 생략 가능 (자동 생성됨)
<input type="checkbox" th:field="*{open}" class="form-check-input">
타임리프의 체크 확인
checked="checked"
체크 박스에서 판매 여부를 선택해서 저장하면, 조회시에 checked 속성이 추가된 것을 확인할 수 있다.
이런 부분을 개발자가 직접 처리하려면 상당히 번거롭다. 타임리프의 th:field 를 사용하면, 값이 true
인 경우 체크를 자동으로 처리해준다.
체크박스 - 등록, 수정
등록, 수정은 form에서 처리. form 태그에서 th:object="${item}" 추가했으므로 *{price}, *{quantity} 등 사용 가능
1
2
3
4
5
6
7
|
<div>판매 여부</div>
<div>
<div class="form-check">
<input type="checkbox" th:field="*{open}" class="form-check-input">
<label for="open" class="form-check-label">판매 오픈</label>
</div>
</div>
|
cs |
체크박스 - 조회
조회는 form 태그 사용 안함. th:object="${item}" 없으므로 ${item.price}, ${item.quantity} 등으로 사용해야 함.
조회 -> 변경하면 안되므로 disabled 추가
1
2
3
4
5
6
7
|
<div>판매 여부</div>
<div>
<div class="form-check">
<input type="checkbox" th:field="${item.open}" class="form-check-input" disabled>
<label for="open" class="form-check-label">판매 오픈</label>
</div>
</div>
|
cs |
체크박스 값 변경 후 수정 안되는 현상
POST/ edit 할 때 변경된 item이 제대로 넘어오는 지 확인하기 위해 log 출력 -> 잘 넘어옴
itemRepository.update()에 setOpen() 추가 안되어있어서 그럼
체크 박스 - 멀티
HashMap(): 순서 보장 안됨
LinkedHashMap(): 순서 보장 됨
지역 추가하는 코드 등록, 수정, 조회 다 들어감
1
2
3
4
5
|
Map<String, String> regions = new LinkedHashMap<>();
regions.put("SEOUL", "서울");
regions.put("BUSAN", "부산");
regions.put("JEJU", "제주");
model.addAttribute("regions", regions);
|
cs |
@ModelAttribute(): 컨트롤러 호출 시 항상 자동으로 model.addAttribute() 실행
1
2
3
4
5
6
7
8
|
@ModelAttribute("regions")
public Map<String, String> regions() {
Map<String, String> regions = new LinkedHashMap<>();
regions.put("SEOUL", "서울");
regions.put("BUSAN", "부산");
regions.put("JEJU", "제주");
return regions;
}
|
cs |
label 클릭해도 체크박스 활성화 -> 체크박스의 id를 알아야 함
th:field="*{regions}"에서 체크박스 id 자동 생성
th:for="${#ids.prev('open')}"
멀티 체크박스는 같은 이름의 여러 체크박스를 만들 수 있다. 그런데 문제는 이렇게 반복해서 HTML 태그를 생성할 때, 생성된 HTML 태그 속성에서 name 은 같아도 되지만, id 는 모두 달라야 한다. 따라서 타임리프는 체크박스를 each 루프 안에서 반복해서 만들 때 임의로 1 , 2 , 3 숫자를 뒤에 붙여준다.
each로 체크박스가 반복 생성된 결과 - id 뒤에 숫자가 추가됨
1
2
3
|
<input type="checkbox" value="SEOUL" class="form-check-input" id="regions1" name="regions">
<input type="checkbox" value="BUSAN" class="form-check-input" id="regions2" name="regions">
<input type="checkbox" value="JEJU" class="form-check-input" id="regions3" name="regions">
|
cs |
HTML의 id 가 타임리프에 의해 동적으로 만들어지기 때문에 <label for="id 값"> 으로 label 의 대상이 되는 id 값을 임의로 지정하는 것은 곤란하다. 타임리프는 ids.prev(...) , ids.next(...) 을 제공해서 동적으로 생성되는 id 값을 사용할 수 있도록 한다.
th:value="${region.key}" 가 존재하면 checked, 없으면 체크안함
<input type="checkbox" th:field="${item.regions}" th:value="${region.key}" class="form-check-input" disabled>
라디오 버튼
라디오 박스: 히든 필드 안만들어도 됨 -> 한 번 선택하면 절대 null로 만들 수 없기 때문
메시지, 국제화
스프링 부트 메시지 소스 기본 값: spring.messages.basename=messages
MessageSource를 스프링 빈으로 등록하지 않고, 스프링 부트와 관련된 별도의 설정을 하지 않으면 messages 라는 이름으로 기본 등록된다. 따라서 messages_en.properties, messages_ko.properties, messages.properties 파일만 등록하면 자동으로 인식된다.
스프링 메시지 소스 사용
메시지가 없으면 오류 발생
1
2
3
4
5
|
@Test
void notFoundMessageCode() {
assertThatThrownBy(() -> messageSource.getMessage("no_code", null, null))
.isInstanceOf(NoSuchMessageException.class);
}
|
cs |
default 메시지 설정 가능
1
2
3
4
5
|
@Test
void notFoundMessageCodeDefaultMessage() {
String result = messageSource.getMessage("no_code", null, "기본 메시지", null);
assertThat(result).isEqualTo("기본 메시지");
}
|
cs |
hello.name의 argument가 new Object[]에 넣은 값으로 치환됨
1
2
3
4
5
|
@Test
void argumentMessage() {
String message = messageSource.getMessage("hello.name", new Object[]{"Spring"}, null);
assertThat(message).isEqualTo("안녕 Spring");
}
|
cs |
'오늘 배운 것' 카테고리의 다른 글
[알고리즘] 다익스트라, 세그먼트 트리 (0) | 2021.07.13 |
---|---|
[알고리즘] 위상정렬, 프림, 크루스칼 (0) | 2021.07.12 |
[스프링 MVC 2] 타임리프 - 기본 기능(2) (0) | 2021.07.01 |
[스프링 MVC 1, 2] 스프링 MVC - 기본 기능 (2), 타임리프 - 기본 기능 (0) | 2021.06.30 |
[스프링 MVC 1] 스프링 MVC - 기본 기능 (1) (0) | 2021.06.28 |