그렉 턴키스트, 『스프링 부트 실전 활용 마스터』의 1장 스프링부트 웹 애플리케이션 만들기를 요약한 내용입니다.
인텔리제이의 Spring Initializr로 새로운 프로젝트를 생성한다.
디펜던시는 Spring Reactive Web과 Thymeleaf 총 2개를 선택하고 프로젝트를 생성한다.
Dish 클래스와 Kitchen 서비스, Server 컨트롤러를 작성하고 실행후 /server 요청을 해봤는데 404 에러가 뜬다 왜지...?
-> 스프링부트 버전을 2.4.2로 바꾸어서 해결
ServerController는 2개의 웹 메서드를 가지고 있다.
반환되는 미디어 타입은 text/event-steam이고 250ms마다 랜덤한 Dish를 반환한다.
deliverDishes 함수는 map 메서드를 사용해 Dish의 delivered를 true로 바꾸고 반환한다.
@RestController
public class ServerController {
private final KitchenService kitchen;
public ServerController(KitchenService kitchen) {
this.kitchen = kitchen;
}
@GetMapping(value = "/server", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
Flux<Dish> serveDishes() {
return this.kitchen.getDishes();
}
@GetMapping(value = "/served-dishes", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
Flux<Dish> deliverDishes(){
return this.kitchen.getDishes()
.map(dish -> Dish.deliver(dish));
}
}
KitchenService의 getDishes 메서드는 Flux.generate()를 사용해 데이터를 비동기적으로 반환한다.
@Service
public class KitchenService {
Flux<Dish> getDishes(){
return Flux.<Dish> generate(sink -> sink.next(randomDish()))
.delayElements(Duration.ofMillis(250));
}
private Dish randomDish(){
return menu.get(picker.nextInt(menu.size()));
}
private List<Dish> menu = Arrays.asList(
new Dish("Sesame chicken"),
new Dish("Lo mein noodles, plain"),
new Dish("Sweet & sour beef")
);
private Random picker = new Random();
}
Dish는 단순한 POJO(Plain Object Java Object) 객체로서 description 필드와 delivered 필드를 가지고 있고 게터, 세터, toString() 메서드와 deliver() 메서드를 가지고 있다.
public class Dish {
private String description;
private boolean delivered = false;
public static Dish deliver(Dish dish){
Dish deliveredDish = new Dish(dish.description);
deliveredDish.delivered = true;
return deliveredDish;
}
public Dish(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public boolean isDelivered() {
return delivered;
}
@Override
public String toString() {
return "Dish{" +
"description='" + description + '\'' +
", delivered=" + delivered +
'}';
}
}
위와 같이 작성하고 애플리케이션을 실행하고 localhost:8080/server를 요청하면 다음과 같이 비동기적으로 데이터 스트림이 반환된다
x 버튼을 누를 때까지 계속 나온다
실제 웹서비스를 만들기 위해서는 웹 페이지 화면을 반환해야한다.
타임리프는 리액티브 스트림을 완벽하게 지원하고 HTML과 100% 호환된다.
간단하게 타임리프 템플릿을 사용해보기 위해 인덱스 페이지를 반환하는 홈 컨트롤러를 작성한다.
Mono는 0개 또는 1개의 원소만 담을 수 있는 리액티브 컨테이너이다.
템플릿의 이름을 Mono.just()로 감싸 반환한다. 단순히 템플릿 이름만 반환할 때는 굳이 Mono에 담아 반환할 필요가 없다.
@Controller
public class HomeController {
@GetMapping
Mono<String> home(){
return Mono.just("home");
}
}
타임리프 뷰 리졸버는 컨트롤러가 반환한 템플릿 이름에 classpath:/templates/라는 접두어와 .html이라는 접미어를 붙인다.
타임리프는 DOM 기반 파서를 내장하고 있어서 모든 HTML 태그는 닫혀있어야 한다.
src/main/resources에 templates라는 디렉토리를 생성하고, templates 디렉토리 아래에 다음과 같이 home.html을 작성한다.
html 태그에 thymeleaf 관련 링크를 추가하고 title과 body에 내가 쓰고 싶은 내용을 적었다ㅎ
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Home Page</title>
</head>
<body>
<h1>Welcome to My Home Page!</h1>
<p>
스프링부트 리액티브 프로그래밍 공부중입니다! 아좌아좌~~
</p>
</body>
</html>
실행시키면 다음과 같이 아주 단순한 정적페이지를 볼 수 있다
Ajax로 첨부파일 다운로드 구현 | 스프링 MVC (0) | 2024.03.08 |
---|---|
[SpringBoot] 검색기능 구현, 몽고디비 쿼리 방법 정리 (0) | 2023.03.03 |
[SpringBoot] 리액티브 프로그래밍 | 간단한 이커머스 애플리케이션 예제 (0) | 2023.02.28 |
스프링부트 리액티브 프로그래밍 | 웹플럭스 (0) | 2023.02.22 |
JPA-style positional param was not an integral ordinal 오류 해결 (0) | 2022.07.28 |