Spring & React 개발환경 연동

조숙희·2023년 11월 24일
0

웹 프로젝트

목록 보기
1/8
post-thumbnail

개발환경

SpringBoot 3.0.12
Gradle
H2 2.1.214
SDK 17
IDE IntelliJ
MacOS

진한 글씨 : 실행한 코드

1차 시도

1차 참고 블로그

npm install -g create-react-app

오류:npm WARN deprecated tar@2.2.2
-> tar version이 낮아서 생긴 오류

tar 최신 버전 다운로드

npm install tar@6 -g

근데 해결 안됨. 포기.

2차 시도

2차 참고 블로그

1차 블로그의 react 설치하기까지 진행 후 2차 참고 블로그 진행


bootstrap 설치 (css)

npm install bootstrap react-bootstrap --save

react-router-dom 설치

npm install react-router-dom --save

axios 설치

npm install axios --save

build.gradle 수정 (spring 실행시 react도 같이 build되도록)

plugins {
    id 'org.springframework.boot' version '2.6.1'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'
    id 'war'
####################### 추가 #######################
    id "com.moowork.node" version "1.3.1"
####################### 추가 #######################
}

####################### 추가 #######################
apply plugin: "com.moowork.node"
####################### 추가 #######################

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

test {
    useJUnitPlatform()
}

####################### 추가 #######################
def webappDir = "$projectDir/src/main/frontend"

task appNpmInstall(type: NpmTask) {
    workingDir = file("${webappDir}")
    args = ["run", "build"]
}

task copyWebApp(type: Copy) {
    from 'src/main/frontend/build'
    into "build/resources/main/static"
}

copyWebApp.dependsOn(appNpmInstall)
compileJava.dependsOn(copyWebApp)
####################### 추가 #######################

추가 해야하는 코드

id("com.moowork.node") version "1.3.1"
apply(plugin = "com.moowork.node")
tasks {
    val webappDir = "$projectDir/src/main/frontend"

    register<NpmTask>("appNpmInstall") {
        workingDir = file(webappDir)
        args = listOf("run", "build")
    }

    register<Copy>("copyWebApp") {
        from(webappDir.resolve("build"))
        into("build/resources/main/static")
    }

    getByName("compileJava") {
        dependsOn("copyWebApp")
    }
}

NpmTask 객체를 찾지 못함 (moowork에 있는 객체)

의존성에 추가로 삽입

implementation("com.moowork.gradle:gradle-node-plugin:1.3.1")

에러 발생 : Could not find com.moowork.gradle:gradle-node-plugin:1.3.1.

3차 참고 블로그

maven (url="https://plugins.gradle.org/m2/")
implementation("com.github.node-gradle:gradle-node-plugin:3.1.0")
subprojects{
	apply(plugin= "com.github.node-gradle.node")
}

여전히 Unresolved reference: NpmTask 에러 발생
->Gradle 7.0 이후 버전에서는 NpmTask가 제거

register("appNpmInstall") 코드 수정

register<com.moowork.gradle.node.npm.NpmTask>("appNpmInstall") 

버전이 달라져 함수도 달라짐

해결 안됨. 포기.

실패 코드

plugins {
	java
	id("org.springframework.boot") version "3.0.12"
	id("io.spring.dependency-management") version "1.1.3"
	id("com.moowork.node") version "1.3.1"
}

apply(plugin = "com.moowork.node")

group = "com.perfume-pedia"
version = "0.0.1-SNAPSHOT"

java {
	sourceCompatibility = JavaVersion.VERSION_17
}

configurations {
	compileOnly {
		extendsFrom(configurations.annotationProcessor.get())
	}
}

repositories {
	mavenCentral()
	maven (url="https://plugins.gradle.org/m2/")
}

dependencies {
	implementation("org.springframework.boot:spring-boot-starter-data-jpa")
	implementation("org.springframework.boot:spring-boot-starter-thymeleaf")
	implementation("org.springframework.boot:spring-boot-starter-validation")
	implementation("org.springframework.boot:spring-boot-starter-web")
	testImplementation("org.projectlombok:lombok:1.18.22")
	compileOnly("org.projectlombok:lombok")
	developmentOnly("org.springframework.boot:spring-boot-devtools")
//	runtimeOnly("com.h2database:h2")
	annotationProcessor("org.projectlombok:lombok")
	testImplementation("org.springframework.boot:spring-boot-starter-test")
	implementation ("com.fasterxml.jackson.core:jackson-databind")
	runtimeOnly("com.mysql:mysql-connector-j")
//	runtimeOnly("mysql:mysql-connector-java:8.0.33")
	implementation("com.moowork.gradle:gradle-node-plugin:1.3.1")
	implementation("com.github.node-gradle:gradle-node-plugin:3.1.0")


	//JUnit4 추가
	testImplementation("org.junit.vintage:junit-vintage-engine") {
		exclude("org.hamcrest", "hamcrest-core")

	}

}

subprojects{
	apply(plugin= "com.github.node-gradle.node")
}

tasks.withType<Test> {
	useJUnitPlatform()
}

tasks {
	val webappDir = "$projectDir/src/main/frontend"

	register<com.moowork.gradle.node.npm.NpmTask>("appNpmInstall") {
		workingDir = file(webappDir)
		args = listOf("run", "build")
	}

	register<Copy>("copyWebApp") {
		from(webappDir.resolve("build"))
		into("build/resources/main/static")
	}

	getByName("compileJava") {
		dependsOn("copyWebApp")
	}
}

gradle 파일 수정 전으로 돌아간 후 1차 참고 블로그 Proxy 설정

npm install http-proxy-middleware --save

코드 추가

// src/main/frontend/src/setProxy.js

const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function(app) {
app.use(
  '/api',
  createProxyMiddleware({
    target: 'http://localhost:8080',	# 서버 URL or localhost:설정한포트번호
    changeOrigin: true,
  })
);
};

App.js 코드

// src/main/frontend/src/App.js

import React, {useEffect, useState} from 'react';
import axios from 'axios';

function App() {
 const [hello, setHello] = useState('')

  useEffect(() => {
      axios.get('/api/hello')
      .then(response => setHello(response.data))
      .catch(error => console.log(error))
  }, []);

  return (
      <div>
          백엔드에서 가져온 데이터입니다 : {hello}
      </div>
  );
}

export default App;

HelloWorldController 코드

// src/main/java/com.demogroup.demoweb/Controller/HelloWorldController.java

package com.demogroup.demoweb.Controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloWorldController {

  @GetMapping("/api/hello")
  public String test() {
      return "Hello, world!";
  }
}

DemoWebApplication 코드

// src/main/java/com.demogroup.demoweb/DemoWebApplication.java
package com.demogroup.demoweb;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoWebApplication {
  public static void main(String[] args) {
      SpringApplication.run(com.demogroup.demoweb.DemoWebApplication.class, args);
  }
}

8080포트 안열림 (H2 DB때문)
build.gradle의 의존성에 코드 추가

implementation ("com.h2database:h2")
implementation ("org.springframework.boot:spring-boot-starter-jdbc")

해결됨
react 포트(localhost:3000)에 값 전달이 안됨
(=연결 안됨) ㅅㅂ

=> CORS 에러

포트 재실행하는데 전에 사용했던 포트가 안닫혀서 또 문제 발생함
터미널에서 아래 코드 입력 후 PID 확인

sudo lsof -i :8080

해당 포트(8080) 강제 종료

sudo kill -9 [PID]

✨ 해결 ✨

setProxy.js에 코드 추가 (=근데 이거 원래 코드에 있었는데 왜 중간에 없어진거..?)

const { createProxyMiddleware } = require('http-proxy-middleware');

다음 1차 참고 블로그의 빌드하기를 참고함

빌드하기 코드를 kts로 변환했을 때

val frontendDir = "$projectDir/src/main/frontend"

sourceSets {
  main {
      resources { srcDirs("$projectDir/src/main/resources") }
  }
}

tasks.processResources { dependsOn("copyReactBuildFiles") }

tasks.register<Exec>("installReact") {
  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")
  }
}

tasks.register<Exec>("buildReact") {
  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")
  }
}

tasks.register<Copy>("copyReactBuildFiles") {
  dependsOn("buildReact")
  from("$frontendDir/build")
  into("$projectDir/src/main/resources/static")
}

이러한 코드가 나오게 되는데
에러 발생 : Unresolved reference: Locale

MacOs 환경에서 사용하는 코드로 변환

val globalFrontendDir = "$projectDir/src/main/frontend"

sourceSets {
  main {
      resources { srcDirs("$projectDir/src/main/resources") }
  }
}

tasks.processResources { dependsOn("copyReactBuildFiles") }

tasks.register<Exec>("installReact") {
  workingDir(globalFrontendDir)
  inputs.dir(globalFrontendDir)
  group = BasePlugin.BUILD_GROUP

  commandLine("npm", "audit", "fix")
  commandLine("npm", "install")
}

tasks.register<Exec>("buildReact") {
  dependsOn("installReact")
  workingDir(globalFrontendDir)
  inputs.dir(globalFrontendDir)
  group = BasePlugin.BUILD_GROUP

  commandLine("npm", "run-script", "build")
}

tasks.register<Copy>("copyReactBuildFiles") {
  dependsOn("buildReact")
  from("$globalFrontendDir/build")
  into("$projectDir/src/main/resources/static")
}

...끝!

0개의 댓글