SpringBoot #6 SpringBoot+React 기반 간단한 게시판 생성하기 #1 SpringBoot 프로젝트 기본 구조 생성

2021. 10. 14. 12:40JAVA/Spring

개요

스타트 스프링 부트라는 도서를 공부하던 중 웹 페이지를 처리하는 View 부분을 Thymeleaft라는 뷰 템플릿을 사용하여 구현하는 것으로 서술되었습니다. 하지만 저는 View 부분을 서버 개발과 분리하여 개발하고 싶었습니다. 그래서 서버 개발 부분은 SpringBoot 프레임워크를 사용하고 뷰 부분을 React 프레임워크 기반으로 분리하여 구현하고자 하였습니다. #6의 주제 목표는 SpringBoot+React 기반으로 두 프레임워크가 연동하고 간단한 게시판의 게시글 목록을 출력 및 페이징 기능까지 구현하는 것을 목표로 합니다. 그리고 서버 개발 부분에서 데이터베이스는 MySQL을 사용할 예정이고 연결방법은 Spring Data JPA를 활용하여 데이터베이스에 연결할 예정입니다.

 

본 글에서는 SpringBoot의 프로젝트를 생성하고 기본적인 컨트롤러 및 엔티티 클래스와 Repository를 설계합니다. 그리고 데이터베이스에 게시판의 게시글 더미 데이터를 삽입하는 것을 목표로 합니다.

 

  • SpringBoot와 React를 연동하여 프론트엔드 부분과 백엔드 개발 부분을 분리하여 구현함
  • 간단한 게시판을 구현하여 게시글의 목록과 페이지 처리 기능을 구현함
  • Spring Data JPA를 사용하여 데이터베이스에 연결하고 쿼리하도록 구현함

1. 프로젝트 디렉터리 구조 소개 및 SpringBoot 프로젝트 기본 구조 생성

SpringBoot
  -back-end
      - boot06 (SpringBoot 프로젝트명)
          -src
          ...
  -front-end
      - boot06 (React 프로젝트명)
          -src
          -public
          -node_modules

SpringBoot 프로젝트를 생성하기 위해서 back-end 디렉터리에서 프로젝트를 생성합니다.

 

1.1 프로젝트 생성

File->New->Spring Starter Project

Lombok 라이브러리 적용은 아래 링크를 통해서 설정할 수 있습니다.

https://yonghwankim-dev.tistory.com/127

 

Lombok 라이브러리 소개/설치

본 글은 스타트 스프링 부트 도서의 내용을 복습하기 위해서 작성된 글입니다. 개요 Lombok 라이브러리는 어디에 사용하는지 알아보고, 설치하여 테스트를 실습합니다. 1. Lombok 라이브러리는 어디

yonghwankim-dev.tistory.com

 

1.2 패키지 생성

아래 그림과 같이 패키지(config, controller, domain, persistence, vo)를 생성합니다.

1.3 CORSFilter 설정

org.zerock.config.CORSFilter 클래스 생성 및 작성

package org.zerock.config;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;

import org.springframework.context.annotation.Configuration;

@Configuration
public class CORSFilter implements Filter {
	@Override
	public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
			throws IOException, ServletException {
		System.out.println("필터링이 진행중입니다...");
		HttpServletResponse response = (HttpServletResponse) res;
		response.setHeader("Access-Control-Allow-Origin", "*");
		response.setHeader("Access-Control-Allow-Credentials", "true");
		response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
		response.setHeader("Access-Control-Allow-Credentials", "true");
		response.setHeader("Access-Control-Allow-Max-Age", "3600");
		response.setHeader("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, "
				+ "Authorization, Origin, Accept, Access-Control-Request-Method, Access-Control-Request-Headers");
		
		chain.doFilter(req, res);
	}
	
	public void init(FilterConfig filterConfig) {
		
	}
	
	public void destory() {
		
	}
}

 

1.4 application.properties 파일 설정

application.properties 파일은 데이터베이스 연결과 관련된 설정을 저장합니다. src/main/resources/application.properties 파일의 설정은 다음과 같이 설정합니다. spring.datasource.username, spring.datasource.password 부분은 자유롭게 설정하시면 됩니다.

#MySQL 설정
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/jpa_ex?useSSL=false
spring.datasource.username=jpa_user
spring.datasource.password=mysql_jpa_user

#스키마 생성(create)
spring.jpa.hibernate.ddl-auto=update
#DDL 생성시 데이터베이스 고유의 기능을 사용하는가?
spring.jpa.generate-ddl=false
#실행되는 SQL문을 보여줄 것인가?
spring.jpa.show-sql=true
#데이터베이스는 무엇을 사용하는가?
spring.jpa.database=mysql
#로그 레벨
logging.level.org.hibernate=info
#MySQL 상세 지정
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect

아래 설정에서 jpa_ex는 MySQL 데이터베이스의 데이터베이스명입니다. 이 부분도 사용자에 따라서 다를 수 있습니다.

spring.datasource.url=jdbc:mysql://localhost:3306/jpa_ex?useSSL=false

 

1.5 엔티티 클래스와 Repository 설계

아래 그림과 같이 WebBoard 클래스, WebBoardRepository 인터페이스 파일을 생성합니다.

org.zerock.domain.WebBoard.java

import java.sql.Timestamp;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@Entity
@Table(name="tbl_webboards")
@EqualsAndHashCode(of="bno")
@ToString
public class WebBoard {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long bno;
	private String title;
	private String writer;
	private String content;
	
	@CreationTimestamp
	private Timestamp regdate;
	@UpdateTimestamp
	private Timestamp updatedate;
}

 

org.zerock.persistence.WebBoardRepository.java

import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.data.repository.CrudRepository;
import org.zerock.domain.QWebBoard;
import org.zerock.domain.WebBoard;

import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Predicate;

public interface WebBoardRepository extends CrudRepository<WebBoard, Long>{

}

 

1.6 컨트롤러 생성

org.zerock.controller.WebBoardController.java

package org.zerock.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.zerock.domain.WebBoard;
import org.zerock.persistence.WebBoardRepository;
import org.zerock.vo.PageMaker;
import org.zerock.vo.PageVO;

import lombok.extern.java.Log;

@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@RequestMapping("/boards/")
@Log
public class WebBoardController {
	
	@Autowired
	private WebBoardRepository repo;
	
	@GetMapping("/list")
	public PageMaker<WebBoard> list() {
		log.info("list() called...");
	}
}

 

1.7 Querydsl 설정

게시물의 검색에는 동적 쿠러리르 이용해서 처리할 것이므로 pom.xml에 Querydsl 관련 라이브러리와 코드 생성 플러그인을 추가합니다.

 

pom.xml의 <dependencies> 태그의 일부

		<dependency>
		  <groupId>com.querydsl</groupId>
		  <artifactId>querydsl-apt</artifactId>
		  <version>${querydsl.version}</version>
		  <scope>provided</scope>
		</dependency>
		
		<dependency>
		  <groupId>com.querydsl</groupId>
		  <artifactId>querydsl-jpa</artifactId>
		  <version>${querydsl.version}</version>
		</dependency>

pom.xml의 <plugins> 태그의 일부

			<plugin>
		      <groupId>com.mysema.maven</groupId>
		      <artifactId>apt-maven-plugin</artifactId>
		      <version>1.1.3</version>
		      <executions>
		        <execution>
		          <goals>
		            <goal>process</goal>
		          </goals>
		          <configuration>
		            <outputDirectory>target/generated-sources/java</outputDirectory>
		            <processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
		          </configuration>
		        </execution>
		      </executions>
		    </plugin>

위와 같이 pom.xml에 추가하면 프로젝트를 한번 Maven Build하여 줍니다. (boot06 프로젝트 오른쪽 버튼 클릭->Run As-> Maven Build

 

아래 그림과 같이 QWebBoard 클래스 파일 생성을 확인합니다.

 

1.8 테스트 코드 작성

작성한 WebBoardRepository는 가능하면 테스트를 이용하도록 합니다.

 

src/test/java/org.zerock.WebBoardRepository.java 생성 및 작성

import java.util.stream.IntStream;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.test.annotation.Commit;
import org.zerock.domain.WebBoard;
import org.zerock.persistence.WebBoardRepository;

import lombok.extern.java.Log;

@SpringBootTest
@Log
@Commit
class WebBoardRepositoryTests {

	@Autowired
	WebBoardRepository repo;
	
    // 게시판의 게시물 샘플 데이터 300개 생성하는 테스트
	@Test
	public void insertBoardDummies() {
		IntStream.range(0, 300).forEach(i->{
			WebBoard board = new WebBoard();
			
			board.setTitle("Sample Board Title " + i);
			board.setContent("Content Sample ..."+i+" of Board");
			board.setWriter("user0"+(i%10));
			
			repo.save(board);
		});
	}

}

 

2. MySQL 데이터베이스 스키마 및 유저 생성

2.1 데이터베이스 스키마 생성

MySQL을 설치하고 MySQL WorkBench를 접속합니다. 그리고 root로 로그인합니다.

 

SCHEMAS 영역 마우스 오른쪽 버튼 클릭->Create Schema.. 클릭

jpa_ex라는 이름으로 데이터베이스 스키마를 생성합니다.

2.2 유저 생성

jpa_ex 데이터베이스 스키마를 사용할 때 root로 사용해도 되나 jpa_ex 스키마만 사용할 수 있도록 전용 유저를 생성해봅니다.

 

root로 접속한 상태에서 Administration->Users and Privilieges 클릭->Add Account 클릭->아래와 같이 설정

Login Name : jpa_user

Password : mysql_jpa_user

위의 아이디와 패스워드는 사용자 마음대로 설정하시면 됩니다. 단, 위와 같이 다르게 할시 1.3 application.properties 파일 설정도 그에 맞게 변경하시면 됩니다.

jpa_user 클릭->Schema Privileges 클릭->Add Entry->Selected Schema 라디오 버튼 클릭->jpa_ex 스키마 선택->권한을 아래와 같이 선택

 

3. 테스트 코드 실행

SpringBoot 프로젝트 기본구조 및 데이터베이스 연결 테스트를 위해 테스트를 수행합니다.

 

1.7에서 테스트 코드 작성한 것을 수행합니다. Spring Data JPA를 사용하기 때문에 MySQL에 미리 테이블을 생성할 필요 없이 JPA가 엔티티 클래스인 WebBoard 클래스를 기반으로 자동으로 생성할 것입니다.

 

src/test/java/org.zerock.WebBoardRepositoryTests.java 실행

1.7의 테스트 코드를 실행하면 아래 그림과 같이 MySQL로 확인하면 게시판의 게시물 샘플 데이터가 삽입된 것을 확인이 가능합니다.

위의 그림과 같은 결과가 나온다면 SpringBoot와 MySQL 데이터베이스 연결이 성공함을 의미합니다.

 

References

source code : https://github.com/yonghwankim-dev/SpringBoot-Study
스타트 스프링 부트, 구멍가게코딩단 지음
[리액트, 스프링부트 연동하여 CRUD 구현] #8 - 스프링부트에서 환경설정하기 (8/10) : https://corini.tistory.com/entry/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-%EC%97%B0%EB%8F%99%ED%95%98%EC%97%AC-CRUD-%EA%B5%AC%ED%98%84-8-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8%EC%97%90%EC%84%9C-%ED%99%98%EA%B2%BD%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0-8n?category=836393