이 글은 "스프링 인 액션 제5판 (크레이그 윌즈 지음)"을 읽고 주관적으로 작성된 글입니다.
※ 배우는 내용
1) 모델 데이터를 브라우저에서 보여주기
2) 폼 입력 처리하고 검사하기
3) 뷰 템플릿 라이브러리 선택하기
※ 요약
- 스프링 MVC란?
- 강력한 웹 프레임워크
- 스프링 애플리케이션의 웹 프론트엔드 개발에 사용
- 스프링 MVC 어노테이션
- 스프링 MVC는 어노테이션 기반
- @RequestMapping, @GetMapping, @PostMapping 등
- 어노테이션으로 요청 처리 메서드를 선언
- 스프링 MVC는 어노테이션 기반
- 요청 메서드의 뷰 이름 반환
- 대부분 요청 처리 메서드는 마지막에 Thymeleaf 템플릿과 같은 논리 뷰 이름을 반환
- 모델 데이터와 함께 해당 요청을 전달
- 유효성 검사 컴포넌트 지원
- 스프링 MVC는 유효성 검사 API 구현 컴포넌트로 유효성 검사 지원
- 자바 빈 유효성 검사 API, Hibernate Validator 등
- 뷰 컨트롤러 사용
- 모델 데이터가 없거나 처리가 필요없는 HTTP GET 요청 처리시 사용 가능
- 다양한 뷰 템플릿
- Thymeleaf에 추가하여 다양한 뷰 템플릿 지원
- FreMarker, Groovy Templates, Mustache 등
1. 정보 보여주기
- 컨트롤러
- 데이터를 가져오고 처리하는 역할
- 뷰
- 브라우저에 보여주는 데이터를 HTML로 나타내는 것
- 생성할 컴포넌트의 기낭
- 타코 식자재의 속성을 정의하는 도메인 클래스
- 식자재 정보를 뷰에 전달하는 스프링 MVC 컨트롤러 클래스
- 식자재의 내역을 사용자의 브라우저에 보여주는 뷰 템플릿
1) 도메인 설정하기
- 어플리케이션의 도메인
- 해당 어플리케이션의 이해에 필요한 개념을 다루는 영역
- 이 어플리케이션의 도메인은 다음 객체를 포함
- 타코 디자인
- 식자재
- 고객
- 고객의 타코 주문
- Lombok
- 런타임에 getter, setter 외에 equals(), toString(), hashCode() 등 유용한 메서드를 자동으로 생성
- 소스코드의 분량을 줄일 수 있음
- 메서드들이 코드에 추가되지는 않음
- Intellij 기준, ctrl + f12로 확인 가능 - 예제의 클래스 Ingredient
- final 속성들을 초기화하는 생성자가 없음
- getter, setter 등등의 메서드가 없음 - @Data
- 속성들이 getter, setter 생성 - @RequiredArgsConstructor
- final 속성 초기화 생성자 생성
- 런타임에 getter, setter 외에 equals(), toString(), hashCode() 등 유용한 메서드를 자동으로 생성
2) 컨트롤러 클래스 생성하기
- 컨트롤러의 역할
- HTTP 요청을 처리
- 브라우저에 보여줄 HTML을 뷰에 요청
- REST 형태의 응답 몸체에 직접 데이터를 추가
- 이 어플리케이션에서 정의하는 컨트롤러의 기능
- /design 요청 경로의 HTTP GET 요청을 처리
- 식자재 내역 생성
- 식자제 데이터의 HTML 작성을 뷰 템플릿에 요청 및 작성된 HTML을 웹 브라우저에 전송
- @Slf4j
- 자바에서 사용하는 SLF4J Logger 생성
- Simple Loggin Facade
- @Controller
- 해당 클래스를 컨트롤러로 식별하게하여, 컴포넌트 검색이 필요함을 나타냄
- 즉, 스프링 어플리케이션 컨텍스트에 해당 클래스의 인스턴스를 bean으로 추가
- @RequestMapping
- 클래스 수준에서, 해당 컨트롤러가 처리하는 요청의 종류를 나타냄
- @RequestMapping("/design")
- 클래스 수준에서, 해당 컨트롤러가 처리하는 요청의 종류를 나타냄
- @GetMapping
- 메서드 수준에서, HTTP GET 요청이 수신되면 해당 메서드가 호출됨을 나타냄
- @RequestMapping은 특정 HTTP 요청을 지정하는(PostMapping, PutMapping 등) 어노테이션을 모두 선언함
- 따라서 가급적 특화된 것을 사용하는 것이 좋음
- Model 객체
- 컨트롤러와 뷰 사이에서 데이터를 운반하는 객체
- Model 객체의 속성(attribute)에 있는 데이터는 뷰가 알 수 있는 servlet 요청 속성들로 복사됨
1) 뷰 디자인하기
- Thymeleaf
- 빌드 명세에 dependency로 추가하면
- 스프링 부트의 autoconfiguration에서 런타임에 classpath의 Thymeleaf를 찾아 bean을 자동 생성 - 요청 데이터를 나타내는 요소 속성을 추가로 갖는 HTML
- 빌드 명세에 dependency로 추가하면
- 뷰 라이브러리
- 어떤 웹 프레임워크와도 사용 가능하도록 설계
- 따라서, 스프링의 추상화 모델을 모르고, 컨트롤러가 데이터를 넣는 Model 대신, servlet 요청 속성을 사용
- th:text
- 교체를 수행
- ${ }
- 요청 속성의 값을 사용
- th:each
- 컬렉션을 반복 처리
- 해당 컬렉션의 각 요소를 하나씩 HTML로 나타냄
- @{ }
- 참조되는 정적 콘텐츠
- 로고 이미지, 스타일시트 위치
- 참조되는 정적 콘텐츠
2. 폼 제출 처리하기
- 예제의 <form>에 action 속성이 없음 -> button을 누를 시
- <form method="POST" th:object="${taco}">
- 브라우저가 form에 데이터를 모음
- GET 요청과 같은 경로(/design)로 HTTP POST 요청을 전송
- @PostMapping 메서드 (processDesign())
- 즉, /design 경로의 controller에 HTTP POST를 처리하는 메서드를 추가해야함
- 이 때, processDesign 메서드의 인자로 전달되는 Taco 객체의 속성과 바인딩
<input name="ingredients" type="checkbox"
th:value="${ingredient.id}" />
<span th:text="${ingredient.name}">INGREDIENT</span><br /> - checkbox 여러 요소들은 모두 ingredients라는 이름을 가지고, 텍스트 입력 요소의 이름은 name
- 이 필드들은 Taco 클래스의 ingredients / name 속성 값과 바인딩
- 리디렉션(Redirection)
- 그런데, 이 메서드의 반환값에 redirect가 붙음
- "redirect:/orders/current" - 이는 해당 메서드의 실행이 끝난 후 사용자의 브라우저가 /orders/current 상대 경로로 재접속됨을 나타냄
- 즉, /orders/current 경로의 요청을 처리할 컨트롤러가 필요
- 그런데, 이 메서드의 반환값에 redirect가 붙음
- 리디렉션시 GET/POST
- [???] POST요청에 대한 처리 후, redirect의 경로에 대한 처리는 GET으로 받는 이유?
- <form>에 action이 있는 경우
- /orders 경로로 제출하도록 지정
<form method="POST" th:action="@{/orders}" th:object="${order}">
- /orders 경로로 제출하도록 지정
3. 폼 입력 유효성 검사하기
1) 유효성 검사 규칙 선언하기
- Hibernate 컴포넌트
- 입력 데이터에 대한 유효성을 검사해야 함
- 스프링은 자바의 빈 유효성 검사(bean validation) API를 지원(구현)
- 유효성 검사 규칙을 쉽게 선언 - 이 API를 구현한 Hibernate 컴포넌트는 스프링 부트 웹 스타터 의존성으로 자동 추가
- 유효성 검사 적용 방법
- 검사할 클래스에 검사 규칙 선언
- 검사를 하는 컨트롤러 메서드에 검사 구행 지정
- 검사 에러를 보여주도록 form 뷰 수정
- 검사 클래스에 유효성 검사 규칙 선언
- 예제에서는 Taco, Order 클래스
- @NotNull : null인지 확인
- @Size : min으로 최소 개수 지정 (String, List 상관없이 사용)
- @NotBlank : 입력을 하지 않은 필드만 확인
- @CreaditCardNumber : Luhn(룬) 알고리즘 검사로 신용카드 번호인지만 확인
- @Pattern : 정규 표현식 확인
- @Digits : 숫자 검사
@NotNull
@Size(min=5, message="Name must be at least 5 characters long")
private String name;
@Size(min=1, message="You must choose at least 1 ingredient")
private List<String> ingredients;
- 유효성 검사 결과
- message
- 유효성 규칙이 충족하지 않으면 보여줄 메세지 정의
- message
2) 폼과 바인딩될 때 유효성 검사 수행하기
- 검사 컨트롤러 메서드에서 검사 수행
- 예제에서는 DesignTacoController의 processDesign(), OrderController의 processOrder()
- @Valid : 해당 객체의 유효성 검사를 수행
public String processDesign(@Valid Taco design, Errors errors) {
if (errors.hasErrors()) {
return "design";
} - 제출된 form 데이터와 Taco 객체가 바인딩 된 후, 해당 메서드의 코드가 실행되기 전에 검사
- hasErrors() 메서드로 검사
- error가 있는 경우, design을 반환하여 다시 form을 보이게 함
3) 유효성 검사 에러 보여주기
- Thymeleaf
- fields와 th:errors 속성으로 Errors 객체의 편리한 사용 방법 제공
<input type="text" th:field="*{name}" />
<span
class="validationError" th:if="${#fields.hasErrors('name')}"
th:errors="*{name}">Name Error</span>
<br />
<button>Submit your taco</button> - class
- 사용자의 주의를 끌기 위한 에러의 명칭을 지정 - th:if
- <span>을 보여줄지 말지 결정
- fields.hasErros()를 통해 에러 확인 - th:errors
- 사전에 정의된 메시지(Name Error)를 검사 에러 메시지로 교체
- fields와 th:errors 속성으로 Errors 객체의 편리한 사용 방법 제공
4. 뷰 컨트롤러로 작업하기
- 지금까지 프로그래밍 패턴
- @Controller
- 스프링 컴포넌트 검색으로 스프링 어플리케이션 컨텍스트에 bean을 생성하기 위해 등록 - @RequestMapping
- 클래스가 처리하는 요청의 패턴을 정의 - @PostMapping
- 메서드가 어떤 종류의 요청을 처리하는지 정의
- @Controller
- 뷰 컨트롤러
- 뷰에 요청을 전달하는 일만 하는 컨트롤러
- 모델 데이터나 사용자 입력을 처리하지 않음
- 예제
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("home");
}
} - WebMvcConfigurer
- 뷰 컨트롤러의 역할을 수행하는 구성 클래스가 구현해야할 인터페이스
- 인터페이스지만 정의된 모든 메서드의 기본적인 구현을 제공
- 따라서, 필요한 메서드만 오버라이딩
- 어떤 구성 클래서에서도 해당 인터페이스를 구현할 수 있지만, 서로 다른 종류의 클래스(웹, 데이터, 보안 등)는 새로 생성하는 것을 선호
- addViewControllers()
- WebMvcConfigurer의 메서드
- 하나 이상의 뷰 컨트롤러 등록
- ViewControllerRegistry 객체를 인자로 받음
- addViewController()
- ViewControllerRegistry의 메서드
- 뷰 컨트롤러가 GET 요청을 처리하는 "/"를 인자로 전달
- ViewControllerRegistration 객체를 반환
- setViewName()
- ViewControllerRegistration의 메서드
- 해당 경로의 요청이 전달되어야하는 뷰 지정 (home)
5. 뷰 템플릿 라이브러리 선택하기
- 뷰 템플릿 라이브러리
- 취향에 따라 뷰 템플릿 라이브러리 선택
- 스프링의 유연성이 좋아 대부분 템플릿을 지원
- 스프링에서 지원되는 템플릿
- FreeMarker
- Groovy 템플릿
- JavaServer Page (JSP)
- Mustache
- Thymeleaf
- 대게 템플릿의 사용 방법
- 뷰 템플릿을 선택
- 의존성 추가
- /templates 디렉터리에 템플릿 작성
- JSP
- JSP는 의존성을 추가하지 않음
- Servlet Container(Web Container)가 JSP 명세를 구현
- Servlet Container는 /WEB-INF 밑에서 JSP 코드를 찾음
- 만약 JAR 파일을 생성하면 이 요구사항을 충족시킬 수 없음
- 따라서, WAR 파일로 생성
1) 템플릿 캐싱
- 템플릿 캐싱
- 템플릿은 최초 사용될 때 한 번만 파싱되고 캐시에 저장
- 이는 불필요한 파싱을 하지 않아 성능을 향상시킴
- 그러나 개발 시점에서는, 코드가 변할 때마다 어플리케이션을 다시 시작해야하는 불편함이 있음
- 템플릿 캐싱 비활성화
- 각 템플릿의 캐싱 속성을 false로 설정
- Thymeleaf의 경우, application.properties에 다음을 추가
- spring.thymeleaf.cache=false - 그러나 배포시 해당 설정을 true 혹은 삭제시켜줘야함
- 스프링 부트의 DevTools를 사용하는 것이 더 쉬움 (어떻게 사용하는건지?)
'책읽기' 카테고리의 다른 글
[데이터 분석을 위한 SQL 레시피](작성중)[3장] 데이터 가공을 위한 SQL (0) | 2021.07.21 |
---|---|
[쉽게 배우는 운영체제](요약)[Part-2][Ch-3] 프로세스와 스레드 (0) | 2021.07.20 |
[파이썬 알고리즘 인터뷰][배열] 주식을 사고팔기 가장 좋은 시점 (0) | 2021.07.19 |
[파이썬 알고리즘 인터뷰][배열] 자신을 제외한 배열의 곱 (0) | 2021.07.19 |
[파이썬 알고리즘 인터뷰][배열] 배열 파티션1 (0) | 2021.07.19 |