Thymeleaf : 템플릿 엔진
- 서버에서 데이터를 받아 우리가 보는 HTML 웹페이지에 데이터를 넣어 보여주는 도구를 뜻함.
- HTML 파일을 그대로 유지하면서 템플릿을 렌더링할 수 있는 기능이 가능함.
<h1 text=${이름}>
<p text=${나이}>
만약 서버에서 아래와 같은 json이 넘어왔을 때, 템플릿 엔진은 아래 값을 받아서 HTML에 값을 적용한다.
{
"이름" : "김자바",
"나이" : 20
}
타임리프 표현식과 문법
타임리프를 사용하기 위해 HTML 파일에 다음과 같은 선언문을 작성해야 한다.
<html xmlns:th="http://www.thymeleaf.org">
- 타임리프의 핵심은, th:xxx가 붙은 부분은 서버에서 렌더링되고 th 라는 값이 없으면 HTML의 기존 태그를 따른다.
동적 페이지 구현해보기
1) html 파일 셋팅
- 먼저 html 파일을 Thymleaf를 사용하여 템플릿 렌더링을 해준다.
코드 작성
- BookController.java
package com.estsoft.hello.controller;
import com.estsoft.hello.repository.BookRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ui.Model;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
@Slf4j
@Controller
public class BookController {
private final BookRepository bookRepository;
public BookController(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
@GetMapping("/books")
public String home(Model model) {
List<BookDTO> bookList = bookRepository.getAllBooks();
model.addAttribute("bookList", bookList);
return "bookManager";
}
@PostMapping("/books")
public String add(@RequestParam String id,
@RequestParam String name,
@RequestParam String author){
bookRepository.saveBook(new BookDTO(id, name, author));
return "redirect:/books";
}
// GET /books/{id}
@GetMapping("/books/{id}")
public String detail(@PathVariable("id") String isbn, Model model) {
log.info("isbn = "+isbn); // 특정 포맷으로 로그가 출력이 됨
model.addAttribute("book", bookRepository.findBookById(isbn));
return "bookDetail";
}
}
코드 뜯어보기
- @Slf4j : Lombok에서 제공하는 애노테이션. 로깅을 위한 코드를 간소화해주는 역할을 함. log 출력을 위해 사용했음.
- @Controller : 스프링에게 해당 클래스가 컨트롤러임을 알려주는 어노테이션임.
- @BookController : 생성자를 통해 BookRepository 객체를 주입받음.
<HTTP GET 메서드 처리 - 도서 목록 정보를 화면에 표시>
- @GetMapping("/books") : HTTP GET 메서드를 처리하는 메서드임. /books 경로로 들어오는 요청을 처리함. home 메서드는 bookRepository 객체를 통해 모든 도서 목록을 bookList에 불러옴. 이 목록은 도서 정보를 담고 있는 BookDTO 객체들의 리스트임.
- model.addAttribute("bookList", bookList) : model 객체에 bookList 라는 이름으로 도서 목록을 추가함. 이렇게 함으로써 뷰에서 해당 데이터를 사용할 수 있게 됨.
- return bookManager : 마지막으로, bookManager라는 문자열을 반환하는데 이는 뷰의 이름을 나타냄. 스프링은 이 뷰 이름을 기반으로 실제 뷰 템플릿을 찾아서 렌더링함!
<HTTP POST 메서드 처리 - 도서 정보를 데이터베이스에 저장하고, 도서 목록 화면으로 리다이렉트>
- @PostMapping("/books") : HTTP POST 메서드를 처리하는 메서드임. /books 경로로 들어오는 요청을 처리함.
- @RequestParam : add메서드에서는 이 어노테이션을 사용해서 요청 파라미터를 받음. 즉, HTTP POST 요청의 body에서 "id", "name", "author" 파라미터를 추출하여 각각의 매개변수에 매핑함.
- bookRepository.saveBook(id, name, author) : 객체의 saveBook 메서드를 호출하여 전달받은 도서 정보를 데이터베이스에 저장함. 새로운 도서를 추가하는 역할을 함.
- return "redirect:/books" : 도서를 추가한 후에 "/books"로 리다이렉트함. 이는 사용자가 도서를 추가한 후에 도서 목록 화면으로 다시 이동하게 됨을 의미함. 사용자는 도서를 추가한 결과를 즉시 확인 가능
<HTTP GET 메서드 처리 - 특정 도서의 상세 정보를 조회하고 해당 정보를 bookDetail 뷰로 전달함>
- @GetMapping("/books/{id}") : 경로에 {id}가 있으므로, 실제로는 해당 도서의 isbn을 나타냄.
- public String detail(@PathVariable("id") String isbn, Model model) : @PathVariable 어노테이션을 사용하여 /books/{id}경로로 들어오는 GET 요청을 매개변수로 받음. '{id}' 변수의 값을 'isbn' 매개변수에 매핑함. 또한 'Model' 객체를 매개변수로 받아서 뷰로 데이터를 전달할 수 있게 함.
- model.addAttribute("book", bookRepository.findBookById(isbn)) : bookRepository 객체의 findBookById 메서드를 호출하여 해당 isbn에 해당하는 도서 정보를 가져오고 book이라는 이름으로 모델에 추가함. 이렇게 함으로써 해당 도서의 정보를 뷰로 전달할 수 있음.
- return "bookDetail" : 뷰의 이름을 나타냄. 스프링은 이 뷰 이름을 기반으로 찾고 랜더링함.
- BookRepository.java
package com.estsoft.hello.repository;
import com.estsoft.hello.controller.BookDTO;
import org.springframework.stereotype.Repository;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Repository
public class BookRepository {
private Map<String, BookDTO> bookMap;
public BookRepository() {
bookMap = new HashMap<>();
BookDTO book1 = new BookDTO(
"123", "오늘도 개발자가 안된다고 말했다", "기획자");
BookDTO book2 = new BookDTO(
"978-89-98139-76-6", "객체지향의 사실과 오해", "조영호");
bookMap.put(book1.getId(), book1);
bookMap.put(book2.getId(), book2);
}
public List<BookDTO> getAllBooks() {
List<BookDTO> bookList = new ArrayList<>();
for (Map.Entry<String, BookDTO> book : bookMap.entrySet()) {
bookList.add(book.getValue());
}
return bookList;
}
public BookDTO findBookById(String isbn) {
return bookMap.get(isbn);
}
public void saveBook(BookDTO book) {
bookMap.put(book.getId(), book);
}
}
코드 뜯어보기
- getAllBooks() : 도서 목록을 조회하는 메서드임. 반환값으로는 List<BookDTO>를 가지고 있으며, 모든 도서 목록을 담고 있는 리스트를 반환함. bookMap이라는 Map에서 각각의 엔트리를 가져오고 해당 도서 객체 'BookDTO'를 얻음. 그리고 각 도서 객체를 bookList에 추가하고 return으로 반환함.
- findBookById() : 주어진 도서 ID에 해당하는 도서 정보를 조회하는 메서드임. bookMap에서 해당 ID에 매핑된 도서 정보를 반환함.
- saveBook() : 새로운 도서 정보를 저장함. BookDTO 객체를 받아서 해당 도서의 ID를 키로 하여 bookMap에 저장함.
- BookDTO.java
package com.estsoft.hello.controller;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
public class BookDTO {
private String id;
private String name;
private String author;
}
이렇게 Controller와 Repository에 데이터를 전송하고 처리할 때 DTO를 사용하면 데이터의 구조를 표준화하고 목적에 따라 필요한 정보를 캡슐화하여 코드를 유지보수하기 쉽게 만든다.
사용한 Spring Annotation 개념 정리
- @RequestParam : 주로 웹 요청에서 전달되는 쿼리 파라미터를 받아와서 메소드에서 사용할 수 있게 함.
- @PathVariable
@RequestParam과 @PathVariable 차이점은 뭐지??
- @RequestParam은 쿼리스트링을 통해 전달된 값들을 각각의 파라미터에 대입해준다.
- @PathVariable은 url에 전달되는 값을 받아오는 역할을 한다.
- @ResponseBody : 자바 객체 -> HttpResponse의 본문 responseBody의 내용으로 매핑
- @RequestBody : HttpResponse의 본문 responseBody의 내용 -> 자바 객체로 매핑
SLF4J로 Log 남기기
SLF4J : 다양한 로깅 프레임워크에 대한 인터페이스 모음. 여러가지 log를 남길 수 있음!
스프링 핵심 개념
제어의 역전(IoC)과 의존성 주입(DI)
제어의 역전(Inversion Of Control) : 필요한 객체를 직접 생성하거나 제어하는 것이 아니라 외부에서 관리하는 객체를 가져와서 사용하는 것을 '제어의 역전'이라고 한다.
/* 스프링 컨테이너가 객체를 관리하는 방식 예 */
public class A {
private B b; // 코드에서 객체를 생성하지 않고, 어디선가 받아온 객체를 b에 할당
}
의존성 주입(Dependency Injection) : 어떤 클래스가 다른 클래스에 의존하기 위해 주입한다는 말이다.
-> 생성자 주입, 필드 주입, Setter 주입 방법이 존재함. (@Autowired 사용)
결국 스프링은 객체를 관리하기 위해서 IoC를 하고있고 그것을 실제로 구현한 방식이 DI이다.
빈과 스프링 컨테이너
스프링 컨테이너 : 빈이 생성되고 소멸되는 모든 생명주기를 관리한다.
빈 : 스프링 컨테이너가 관리하고 생성하는 객체이다.
스프링은 빈을 등록하기 위해 어노테이션을 사용하여 스프링 컨테이너에 등록한다.
@Component // 클래스 MyBean을 스프링 컨테이너에 등록
public class MyBean {
}
-> MyBean이라는 클래스에 Component 어노테이션을 붙이면 MyBean 클래스가 빈으로 등록된다. 이렇게 등록된 이후에는 스프링 컨테이너에서 이 클래스를 관리한다.
+) 이때 빈의 이름은 클래스 이름의 첫 글자를 소문자로 바꿔서 관리함.
관점 지향 프로그래밍 (AOP)
: Aspect Oriented Programming. 프로그래밍에 대한 관심을 핵심, 관심사항, 공통 관심사항으로 나누어 관심 기준으로 모듈화하는 것을 의미한다. -> 쉽게 말하자면 관심사를 분리해서 프로그래밍하는 것!
ex)
핵심 관심사항 : 회원관리(회원가입, 전체회원조회)
공통 관심사항 : 호출 시간 로깅 작업
AOP를 적용한다면, 공통 관심사항에 해당하는 호출 시간 로깅 로직을 모듈화하여 핵심 관심사항이랑 분리할 수 있음!
이렇게 AOP를 적용하면 핵심 관심사항(회원관리) 코드에만 집중할 수 있게될 뿐만 아니라, 여러 장점이 있음.
- 핵심 관심사항과 공통 관심사항을 분리하여 유지보수가 쉬움.
- 공통 관심사항인 호출시간 로깅 로직이 모듈화되어 원하는 적용 대상을 선택 가능.
AOP 동작 방식
??? 코드 돌려보고 다시 정리하기.......
'Back-End > Spring' 카테고리의 다른 글
[Spring] MyBatis 실습 / JPA 개념 (외부) (0) | 2024.03.07 |
---|---|
[Spring] Docker, JPA 기초 실습 (외부) (0) | 2024.03.06 |
[Spring] 스프링 부트 실습&데베연결/MVC 개념 (0) | 2024.03.04 |
[Spring] 의존성/컴포넌트 스캔/의존관계 주입/스프링부트 디렉터리 (0) | 2024.02.29 |
[Spring] 스프링 기초/스프링부트 실습 (0) | 2024.02.28 |