[Spring + React] 게시판 프로젝트 - (1) 개발 환경 세팅하기

김희정·2024년 7월 25일
0

Spring+React

목록 보기
1/2

💎 들어가며

게시판 프로젝트를 하는 이유?!

단순한 CRUD 성의 프로젝트지만, Spring Boot 3와 React를 연동하고 결과물을 내는데 의의가 있습니다.

가벼운 프로젝트지만 여러가지를 내포하고 있습니다.

  • 회사에서 개발한 프로젝트는 비공개이기 때문에 공개성 프로젝트
  • Java 17, Spring Boot 3 기반 프로젝트
  • Spring Security 6 버전 연동
  • Spring + React 개발 환경 설정
  • Spring + React JWT 로그인

1. 개발환경

  • Java: 17
  • Spring Boot: 3.3.2
  • Build Tool: Gradle
  • Node: 20.15.1
  • React: 18.3.1
  • IDE: IntelliJ, WebStorm

위의 환경에서 개발하였습니다.
⚠️ 버전에 따라 코드가 다를 수 있습니다.


2. 개발환경 세팅

개발환경 세팅 먼저 시작해보도록 하겠습니다~!


2.1 Spring 프로젝트 설정

프로젝트 생성

Spring Initializer를 통해 프로젝트를 생성합니다.

새 프로젝트라이브러리 추가

Project 초기화면입니다.

IntelliJ 초기 화면


application.properties를 application.yml로 확장자를 변경하고, 아래와 같이 환경설정 정보를 넣어주었습니다.

spring:
  application:
    name: board
  # DataSource Configuration
  datasource:
    url: jdbc:postgresql://127.0.0.1:5432/board
    username: postgres
    password:
  jpa:
    database-platform: org.hibernate.dialect.PostgreSQLDialect
    hibernate:
      ddl-auto: create-drop
  devtools:
    restart:
      enabled: true
server:
  port: 8080
logging:
  level:
    org.springframework.web: info

현재 시간 API 추가: /api/time

프론트 연동을 테스트 하기 위해 현재 시간을 가져오는 간단한 API를 추가하였습니다.

패키지 구성 화면

ApiController 클래스를 생성하였습니다.

package io.github.twinklekhj.board.api;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@RestController
@Slf4j
public class ApiController {
    @GetMapping("/api/time")
    public ResponseEntity<String> getTime() {
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        return ResponseEntity.ok().body(LocalDateTime.now().format(dtf));
    }
}

2.2 React 프로젝트 설정

CRA 프로젝트 생성

터미널을 열어 React 프로젝트를 생성합니다.
저는 TypeScript 기반 프로젝트를 CRA로 생성하였습니다.

cd src/main
npx create-react-app frontend --template typescript
PS D:\Git\board\src\main> npx create-react-app frontend

Creating a new React app in D:\Git\board\src\main\frontend.

Installing packages. This might take a couple of minutes.
Installing react, react-dom, and react-scripts
with ccra-template-typescript...

Front IDE를 열어 프로젝트를 실행해줍니다.
(저는 WebStorm을 이용하였습니다.)

http://localhost:3000 로 접속할 수 있습니다.


API 호출

fetch 메소드를 이용하여 API를 호출하는 코드를 예시로 작성해보았습니다.

// 파일 위치: src/App.tsx
import React, {useEffect} from 'react';

const App = () => {
    const [time, setTime] = React.useState("");
    useEffect(() => {
        fetch("http://localhost:8080/api/time", {
            method: "GET"
        })
            .then(res => {
                if (!res.ok) {
                    throw new Error('Network response was not ok');
                }
                return res.text();
            })
            .then(res => {
                setTime(res)
            })
            .catch(err => console.error(err));
    }, [])
    return (
        <div>
            Hi, Server time is {time}
        </div>
    );
};

export default App;

냅다 호출코드에 url을 적으면 문제가 발생하리란 걸 아실 겁니다.

바로 CORS 문제!!

CORS 예시

CORS란?

CORS(Cross-Origin Resource Sharing)는 직역하면 "교차 출처 리소스 공유"로 URL에서 도메인만 뜻하는 게 아니라 프로토콜과 포트까지 포함하는 개념입니다.

출처를 구성하는 세 요소는 프로토콜·도메인(호스트 이름)·포트로, 이 중 하나라도 다르면 CORS 에러를 만나게 됩니다.
CORS 란?


Proxy 설정

React에서 다른 애플리케이션을 호출할 때 생기는 CORS를 해결하기 위해서 Proxy 설정이 꼭 필요합니다.

React에서는 두가지 방법을 제공합니다.

  1. package.json에 proxy 프로퍼티에 url 추가
  2. http-proxy-middle 라이브러리 설치 및 설정 스크립트 추가

package.json

package.json에 프로퍼티를 추가하는 방법은 간단합니다.

package.json


http-proxy-middleware

아래 명령어를 통해 http-proxy-middleware 모듈을 설치해줍니다.

npm install http-proxy-middleware --save
npm install @types/http-proxy-middleware

아래와 같이 설정합니다.

  • React 프로젝트 아래에 .env 파일 생성
  • src 폴더 아래에 setupProxy.js 파일 생성

파일을 넣기만 하면 자동으로 설정합니다.

주의! ts 파일로 생성하면 자동으로 생성되지 않습니다.

// 파일 위치: frontend/.env
REACT_APP_API_URL=http://localhost:8080/api
// 파일위치: frontend/src/setupProxy.js

import { createProxyMiddleware } from 'http-proxy-middleware';

const { REACT_APP_API_URL } = process.env;
module.exports = function (app: any) {
    app.use(
        '/api',
        createProxyMiddleware({
            target: REACT_APP_API_URL || 'http://localhost:8080/api',
            changeOrigin: true,
        })
    );
};

이제 fetch 코드에서 api url을 빼줍니다.

fetch("/api/time", {
  method: "GET",
})
.then(res => {
  if (!res.ok) {
    throw new Error('Network response was not ok');
  }
  return res.text();
})
.then(res => {
  setTime(res)
})
.catch(err => console.error(err));

결과 화면

React 결과 화면


2.3 Gradle 빌드 설정

Spring Boot 빌드 배포시 자동으로 react 파일을 import 하도록 배포 자동화를 설정할 수 있습니다. build.gradle 파일을 열어 하단에 아래 내용을 추가해줍니다.

빌드 스크립트 작성

processResources {
	dependsOn "copyReactBuildFiles"
	duplicatesStrategy = DuplicatesStrategy.INCLUDE
}

// react 설치
tasks.register('installReact', Exec) {
	workingDir("$frontendDir")
	inputs.dir("$frontendDir")
	group = BasePlugin.BUILD_GROUP
	if (System.getProperty('os.name').toLowerCase(Locale.ROOT).contains('windows')) {
		commandLine "npm.cmd", "audit", "fix"
		commandLine 'npm.cmd', 'install'
	} else {
		commandLine "npm", "audit", "fix" commandLine 'npm', 'install'
	}
}

// react 빌드
tasks.register('buildReact', Exec) {
	dependsOn "installReact"
	workingDir "$frontendDir"
	inputs.dir "$frontendDir"
	group = BasePlugin.BUILD_GROUP
	if (System.getProperty('os.name').toLowerCase(Locale.ROOT).contains('windows')) {
		commandLine "npm.cmd", "run-script", "build"
	} else {
		commandLine "npm", "run-script", "build"
	}
}

// react build 파일 static 폴더로 복사
tasks.register('copyReactBuildFiles', Copy) {
	dependsOn "buildReact"
	from "$frontendDir/build"
	into "$project.projectDir/src/main/resources/static"
}

Spring Boot 프로젝트가 build 될 때 실행시키는 스크립트 입니다.

  • React 프로젝트가 먼저 build
  • 결과물을 SpringBoot 프로젝트 build 결과물에 포함

결과 화면

Spring 프로젝트를 실행만 하더라도 아래와 같이 화면이 구성된 것을 볼 수 있습니다.

Spring Boot 프로젝트 화면


💎 References


💎 마치며

이것으로 환경 설정이 마무리 되었습니다!! 다음 포스팅에서는 JWT를 이용한 Spring + React 로그인에 대해 포스팅하겠습니다🙌

profile
Java, Spring 기반 풀스택 개발자의 개발 블로그입니다.

0개의 댓글