반응형
WebFlux에서 몽고 DB 연동하는 법을 알아 보겠습니다.
Webflux에서 몽고 DB 연동하기
1. 프로젝트 생성하기
디펜던시도 선택해줍니다.
Lombok, 반응형 스프링용으로 나온 Reactive Mongo, Reactive Web까지 선택하였습니다.
그리고 Finish를 해줍니다.
2. 뷰 설정
뷰 페이지에서 사용할 thymeleaf가 빠졌네요. 추가된 pom.xml 입니다.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
WebConfig.java
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.config.EnableWebFlux;
import org.springframework.web.reactive.config.ViewResolverRegistry;
import org.springframework.web.reactive.config.WebFluxConfigurer;
import org.thymeleaf.spring5.ISpringWebFluxTemplateEngine;
import org.thymeleaf.spring5.SpringWebFluxTemplateEngine;
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring5.view.reactive.ThymeleafReactiveViewResolver;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ITemplateResolver;
@EnableWebFlux
@Configuration
public class WebConfig implements ApplicationContextAware, WebFluxConfigurer {
ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = context;
}
@Bean
public ITemplateResolver thymeleafTemplateResolver() {
final SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(this.context);
resolver.setPrefix("classpath:templates/");
resolver.setSuffix(".html");
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setCacheable(false);
resolver.setCheckExistence(false);
return resolver;
}
@Bean
public ISpringWebFluxTemplateEngine thymeleafTemplateEngine() {
SpringWebFluxTemplateEngine templateEngine = new SpringWebFluxTemplateEngine();
templateEngine.setTemplateResolver(thymeleafTemplateResolver());
return templateEngine;
}
@Bean
public ThymeleafReactiveViewResolver thymeleafReactiveViewResolver() {
ThymeleafReactiveViewResolver viewResolver = new ThymeleafReactiveViewResolver();
viewResolver.setTemplateEngine(thymeleafTemplateEngine());
return viewResolver;
}
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.viewResolver(thymeleafReactiveViewResolver());
}
}
view 설정을 해줍니다.
resources/templates 하위에 있는 html파일을 읽도록 처리할 예정입니다.
3. document 설정
Lombok을 활용한 document를 설정합니다.
JPA로 만들기 때문에 매핑할 Movie 클래스를 정의하였습니다.
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
@Document(collection="list")
public class Movie {
@Id
private String id;
private String title;
private String director;
private String since;
private int audienceCnt;
public Movie(String title, String director, String since, int audienceCnt) {
super();
this.title = title;
this.director = director;
this.since = since;
this.audienceCnt = audienceCnt;
}
}
몽고 DB 데이터는 아래와 같습니다.
4. repository 생성하기
MovieRepository.java
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import org.springframework.stereotype.Repository;
import com.psw.movie.document.Movie;
@Repository
public interface MovieRepository extends ReactiveMongoRepository<Movie, String>{
}
ReactiveMongoRepository를 상속받아 구현합니다.
5. 서비스 생성
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import com.psw.movie.document.Movie;
import com.psw.movie.repository.MovieRepository;
import reactor.core.publisher.Flux;
@Service
public class MovieService {
private final ApplicationEventPublisher publisher;
private final MovieRepository movieRepository;
public MovieService(ApplicationEventPublisher publisher, MovieRepository movieRepository) {
this.publisher = publisher;
this.movieRepository = movieRepository;
}
public Flux<Movie> allMovies(){
return movieRepository.findAll();
}
}
생성한 repository에서 데이터를 가공하거나 변경할 서비스를 생성합니다.
해당 포스팅에서는 다른 기능없이 전체를 가져오는 findAll()메소드를 통해 전부 가져올 예정입니다.
6. handler 작성
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import com.psw.movie.document.Movie;
import com.psw.movie.service.MovieService;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@Component
public class MovieHandler {
private final MovieService movieService;
public MovieHandler(MovieService service) {
this.movieService = service;
}
final static MediaType TEXT_HTML = MediaType.TEXT_HTML;
final static MediaType APPLICATION_JSON = MediaType.APPLICATION_JSON;
//movie.html로 변환
public Mono<ServerResponse> movie(ServerRequest request){
return ServerResponse.ok().contentType(TEXT_HTML).render("movie");
}
//요청이오면 JSON형태로 데이터 파싱
public Mono<ServerResponse> getMovieList(ServerRequest request){
Flux<Movie> list = this.movieService.allMovies();
return ServerResponse.ok().contentType(APPLICATION_JSON).body(list, Movie.class);
}
}
서비스를 사용하여 모든 영화리스트를 가져오는 핸들러를 작성합니다.
7. 핸들러를 연결할 라우터를 작성합니다.
요청에 따라 파싱해줄 라우터입니다.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import com.psw.movie.handler.MovieHandler;
@Configuration
public class MovieRouter {
final static MediaType TEXT_HTML = MediaType.TEXT_HTML;
final static MediaType APPLICATION_JSON = MediaType.APPLICATION_JSON;
@Bean
public RouterFunction<ServerResponse> index(MovieHandler movieHandler){
return RouterFunctions.route(
RequestPredicates.GET("/").and(RequestPredicates.accept(TEXT_HTML)), movieHandler::movie)
.andRoute(RequestPredicates.GET("/movie").and(RequestPredicates.accept(TEXT_HTML)), movieHandler::movie);
}
@Bean
public RouterFunction<ServerResponse> getMoiveList(MovieHandler movieHandler){
return RouterFunctions.route(
RequestPredicates
.POST("/getMovieList")
.and(RequestPredicates.accept(APPLICATION_JSON)),
movieHandler::getMovieList);
}
@Bean
public RouterFunction<ServerResponse> getMoiveListSearch(MovieHandler movieHandler){
return RouterFunctions.route(
RequestPredicates
.POST("/getMovieList/{req}")
.and(RequestPredicates.accept(APPLICATION_JSON)),
movieHandler::getMovieList);
}
}
8. html소스 작성
마지막으로 뷰페이지 html소스를 작성하고 부트 프로젝트를 구동합니다.
movie.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Movie</title>
<style>
*{padding:0; margin:0;}
table tr th{background-color: #FFBB00;}
table tr th, td{border: 1px solid black; text-align: center; width: 200px;padding: 5px;}
.inputMovieData tr td{padding: 5px;}
</style>
</head>
<script src="https://code.jquery.com/jquery-3.4.1.js"></script>
<body>
<h1>WebFlux Asynchronous</h1>
<br/><br/><br/>
<h1>Movie List</h1>
<table id="MovieTable">
<tr>
<th>제목</th>
<th>감독</th>
<th>연도</th>
<th>관객수</th>
</tr>
</table>
</body>
<script>
$(document).ready(function(){
init();
});
function init(){
reqAjaxPost("/getMovieList", "", fnSuccess);
}
function fnSuccess(res){
if(res != null){
var tag = "<tr><th>제목</th><th>감독</th><th>연도</th><th>관객수</th> </tr>";
res.forEach(function(d){
tag += "<tr>" +
"<td>" + d.title + "</td>" +
"<td>" + d.director + "</td>" +
"<td>" + d.since + "</td>" +
"<td>" + d.audienceCnt + "</td>" +
"</tr>";
});
$("#MovieTable").empty().append(tag);
}
}
function reqAjaxPost(url, param, fnSuccess){
$.ajax({
url: url,
type: "POST",
data: param,
dataType: "JSON",
success: function(args){
fnSuccess(args);
},
error: function(args){
alert("에러가 발생했습니다.");
}
});
}
</script>
</html>
완성된 소스의 구조
스프링 부트 프로젝트를 구동합니다.
로컬 몽고DB에서 데이터를 가져와 영화정보를 파싱하는 예제를 작성해보았습니다.
반응형
'WEB > Spring' 카테고리의 다른 글
Spring - HttpSessionListener 로그인 세션 관리(중복 로그인 방지하기) (6) | 2020.04.13 |
---|---|
Spring - lombok @AllArgsConstrutor 인식 에러, 동작 안함 (0) | 2020.04.08 |
Spring WebFlux - ajax(비동기)를 통한 데이터 파싱 예제 (0) | 2020.03.25 |
Spring WebFlux - WebFlux 알아보기... index.html연동 (0) | 2020.03.23 |
SpringBoot - 스프링부트에서 채팅프로그램(소켓통신) 만들기-5(Websocket으로 파일 전송하기) (12) | 2020.03.06 |