2024. 1. 25. 20:42ㆍReact JS
이렇게 잘 돌아가는 리액트 프로젝트가 있다.
그리고 프로젝트가 스프링 부트 + 리액트 이 구조로 가다 보면 스프링 부트 안에 리액트를 결합시킬 때가 있다.
물론, 리액트 프로젝트의 변경사항이 반영되는 즉 hot loader가 스프링부트 애플리케이션에서 보이는 화면에 바로 적용되지 않는다는 단점이 있지만(이 부분에 대해서는 밑에서 더 설명하겠다.) 스프링 부트와 리액트를 함께 연동한다는 것에는 분명 장점 또한 있다.
1. 프로젝트를 하나만 들고 다니면 되니깐 관리하기가 용이하다.
2. 스프링 부트 서버만 키면 리액트 프로젝트도 함께 켜지니 배포 시에도 용이하다
그렇다면 이제 Spring Boot 내에서 React 어플리케이션 구동시키는 방법을 한 스텝씩 밟아보도록 하자.
1. 스프링 부트 프로젝트 안에 리액트 프로젝트를 넣을 폴더를 하나 만들어준다. 굳이 예시처럼 안 만들고 원하는 위치에 만들어도 된다. 어차피 '어디에 있는 리액트 프로젝트를 빌드할 것이다'는 pom.xml에서 지정해 줄 것이기 때문이다.
2. 그리고 리액트의 소스를 방금 만든 폴더에 넣어주자. 만약 스프링부트에도 .git이 있고 리액트 프로젝트에도 .git이 있다면 충돌이 날 수 있으니 빼주자. 또한 node_modules는 용량이 크고 어차피 스프링부트 프로젝트를 빌드할 때에 'npm install'로 인해 설치가 될 터이니 옮겨줄 필요가 없다.
마지막으로 스프링부트에 .gitignore가 있다면 리액트 프로젝트의 .gitignore를 참고하여 스프링부트의 .gitignore에 git에 올리지 말아야 할 파일들을 등록하자. 안 그럼 node_modules/의 그 대용량을 push 해버리는 참사가 일어날 것이다.
3. pom.xml 혹은 그래들 파일에(필자는 maven 프로젝트 이므로 pom.xml에) 빌드 시 실행할 플러그인을 작성해야 한다.
<project> 하단의 <build> 그리고 그 하단의 <plugins> 안에 이 코드를 추가하자.
첫 번째 플러그인은 com.github.eirslett을 이용하여 리액트 프로젝트를 빌드하겠다는 것이다. 그렇기 때문에 <configuration> 하단의 <workingDirectory>를 리액트 프로젝트가 존재하는 경로로 잡아야 한다.
그리고 각 <execution>은 각 단계에 해당하는 명령이다.
1. npm install and npm을 명령해 node와 npm을 설치하고
2. npm install을 명령해 frontend/package.json에 있는 라이브러리를 설치하고
3. npm run build를 명령해 리액트 프로젝트를 빌드한다.
두 번째 플러그인은 maven-antrun-plugin을 이용하여 frontend/ 폴더에 있는 build/를 (이는 빌드된 리액트 프로그램이 존재하는 곳이다.) target/의 public 폴더에 복사하겠다는 것이다.
<plugin>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<version>1.4</version>
<configuration>
<workingDirectory>src/main/frontend</workingDirectory>
<installDirectory>target</installDirectory>
</configuration>
<executions>
<execution>
<id>install node and npm</id>
<goals>
<goal>install-node-and-npm</goal>
</goals>
<configuration>
<nodeVersion>v18.18.0</nodeVersion>
<npmVersion>9.8.1</npmVersion>
</configuration>
</execution>
<execution>
<id>npm install</id>
<goals>
<goal>npm</goal>
</goals>
<configuration>
<arguments>install</arguments>
</configuration>
</execution>
<execution>
<id>npm run build</id>
<goals>
<goal>npm</goal>
</goals>
<configuration>
<arguments>run build</arguments>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>generate-resources</phase>
<configuration>
<target>
<copy
todir="${project.build.directory}/classes/public">
<fileset
dir="${project.basedir}/src/main/frontend/build" />
</copy>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
4. 그러면 한번 스프링부트 프로젝트를 띄워보자. 아래 사진처럼 sts를 사용한다면 [프로젝트 우클릭] - [Run As] - [Maven build]를 클릭하면 아래와 같은 화면이 나올 것이다. clean install명령어를 입력하여 mave clean - maven install을 실행해 주자.
만일 intellij를 사용한다면 터미널을 켜고 [ ./mvnw clean install ] 명령어를 입력하는 방법 말고는 모르겠다.
(아는 사람이 있다면 알려주세요...)
미리 결과를 말하자면, 안 되는 게 정상이다. 그러니 실망 마시길.
5. addViewController를 설정해주어야 한다. addViewController() 안에 적힌 url로 들어오는 것은 static 자원으로 url을 포워딩하겠다는 설정이다. 이렇게 하면 스프링부트에 띄워진 리액트 화면을 보다가 새로고침을 해도 404 에러가 나지 않는다. 왜냐하면 서버가 브라우저에서 받는 url을 서버가 처리하는 것이 아니라 클라이언트 자원(지금은 리액트 프로젝트)에 넘겨주기 때문이다. 만약 리액트 프로젝트에도 해당 url로 등록된 것이 없다면 404 에러가 나겠지만 있다면 해당 자원을 보여줄 것이다.
application.properties 혹은 .yaml 파일에 이 설정을 추가해 준다. 설정파일로 추가한 ServletConfig에서 ant-path-matcher를 사용하고 있기 때문에 아래와 같이 설정을 해주어야 한다.
spring.mvc.pathmatch.matching-strategy: ant-path-matcher
아래와 같이 자바콘피그도 추가해준다.
package com.example.demo.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class ServletConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/{spring:\\w+}")
.setViewName("forward:/");
registry.addViewController("/**/{spring:\\w+}")
.setViewName("forward:/");
// /api/로 시작하지 않는 url은 모두 client 화면으로 보내줄 것이다
registry.addViewController("/{x:^(?!api$).*$}/**/{y:[\\w\\-]+}")
.setViewName("forward:/");
}
}
여기까지 되었다면 화면이 잘 뜰 것이다.
6. 마지막으로 리액트 화면에서 스프링 부트 서버의 자원을 가져오려면 어떻게 해야 할까? 방법이 있다.
바로 프록시를 사용하는 것이다. 음... 프록시가 무엇인지에 대해서는 한번 알아보시길 바란다.
리액트 프로젝트를 vscode에서 열 때에는 이제 스프링부트 프로젝트 내에 있는 폴더를 열면 된다.
아까 hot loader가 스프링부트 애플리케이션에서 보이는 화면에 바로 적용되지 않는 단점이 있다고 했지만, 이렇게 스프링 부트 프로젝트를 vscode로 열고 똑같이 npm start가 되기 때문에 이렇게 hot loader를 이용해 개발을 진행할 수 있다. 포트도 별도로 3000번으로 이용가능하다. 스프링부트 서버와는 별개로 리액트 개발 서버가 켜지는 것이다.
다시 본론으로 들어와서, frontend/에 있는 리액트 프로젝트에서 src/ 안에 setupProxy.js를 만들어준다.
물론 http-proxy-middleware를 설치해주어야 한다.
npm install http-proxy-middleware를 명령해 주자.
이처럼 createProxyMiddleware를 통해 프록시를 설정해 주면 CORS 에러도 나지 않는다.
코드를 아래와 같이 작성한다.
만약 여러 개의 url에 같은 프록시를 사용할 경우 ["/api/", "/common/"] 같이 배열로 작성해도 된다.
7. 그럼 이제 리액트 프로젝트에서 서버에 요청을 보내보자.
npm install axios를 명령하여 axios 라이브러리를 설치한다.
그리고 스프링 부트에 간단한 컨트롤러를 만들어 본다.
@RestController
public class HelloController {
@GetMapping("/api/hello")
public String hello(){
return "hello";
}
}
그리고 리액트 프로젝트에서도 저 컨트롤러를 호출하는 함수를 하나 만들어준다.
import axios from "axios";
const ApiClient = axios.create({
withCredentials: true,
responseType: "json",
});
export const getHello = async () =>
ApiClient.get("/api/hello").then((res) => res.data);
그리고 띄워진 화면에 '보내기' 버튼을 누르면 저 함수가 실행되도록 해본다.
만약 응답이 성공적으로 온다면 console에 "hello"가 띄워져야 한다.
await getHello()
.then((data) => console.log(data))
.catch((err) => console.log("err", err));
8. 결과 확인 : 오 hello가 아주 잘 찍힌다.
이상으로 스프링 부트 프로그램 안에서 리액트 프로그램을 돌리는 방법을 알아보았다.
질문은 언제나 환영합니다!
'React JS' 카테고리의 다른 글
[React JS] 리액트 컴포넌트에서 public 폴더 내의 script 를 다시 불러오기 (0) | 2024.02.22 |
---|---|
[React JS] webpack으로 build 시 html에 환경변수 넣는 법 (1) | 2024.01.26 |
[React JS]Jquery fadeIn/Out javascript로 변경하기 (0) | 2023.12.18 |
[React JS] 무한히 늘어나는 숫자를 ###,###,### 형식으로 포매팅하기 (0) | 2023.06.23 |
[React JS] 1,000,000 형식의 가격에서 ,를 지웠을 때 그 앞 숫자도 지워지게 하는 법 (0) | 2023.03.30 |