Coding History/Team Project

팀플) 타임리프 폐기, React로 전환.

BlackBirdIT 2024. 10. 8. 21:36

이걸 진행중에 깨달은게 있는데 우리 웹사이트가 제대로 동적처리가 되려면 리액트를 쓰는게 더욱 유리하다는 것을 알게되어서 구조를 전면 수정할 필요가 생겼다.

그래서 이 포스트는 프로젝트 구조 수정이 될 것.

우선은 여기에 세개의 js파일을 생성한 리액트로 옮겨줘야함.

아! React생성은 글 쓰기전에 프로젝트에 해버려서 이건 넘어가자. 터미널로 진행했다.

저기 보이는 starinfo-app이 리액트 루트 디렉토리다.

리팩토링 해주었고.

이제는 로그인 페이지를 다시 대충 그려보고 구글 로그인이 망가지지 않았는지를 확인해야된다.

리액트에서 페이지를 그려주고 버튼을 따로 생성했다.

import React from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import LoginPage from './components/LoginPage';
import MainPage from './components/MainPage'; // 예시로 MainPage 추가

function App() {
  return (
      <Router>
          <Routes>
              <Route path="/" element={<MainPage />} />
              <Route path="/login" element={<LoginPage />} />
          </Routes>
      </Router>
  );
}

export default App;

이후에 Router 설치하고 Router로 로그인 페이지와 메인을 구분시켜줬다.

일단 시큐리티도 대규모 수술에 들어갔고, memberContoller도 전면수정했다.

그리고 이제 로그인 시도를 해봤는데,

이런 오류가 떴고,

오류 메시지에 따르면 현재 리액트 라우터에서 "/oauth2/authorization/google" 
경로에 대한 라우트가 설정되지 않았기 때문에 해당 경로를 찾을 수 없다는 경고가 발생한 거야.
이 경로는 Google OAuth 인증을 위해 백엔드(Spring Security)에서 사용되고 있어, 
그러니 리액트에서 이 경로를 처리하지 않도록 설정해야 돼.

뭐 아무튼 이렇다고 하니... 방법을 찾아봐야지.

import React from 'react';

const backendUrl = process.env.REACT_APP_BACKEND_URL || "http://localhost:7777";
window.location.href = `${backendUrl}/oauth2/authorization/google`;

const GoogleLoginButton = () => {
    const googleLogin = () => {
        console.log('%c[INFO] Google 로그인 시도 중...', 'color: blue');
        window.location.href = `${backendUrl}/oauth2/authorization/google`;  // Google OAuth2 로그인 경로
    };

    return (
        <button onClick={googleLogin}>
            Google 로그인
        </button>
    );
};

export default GoogleLoginButton;

여기서 경로를 이렇게 명시 해줬는데 문제가 하나 생겼다.

무조건 로그인을 하라고 구글 계정들이 뜨는 것, 로그인을 해도 7777로 리디렉션 되는 것..

그니까 쉽게 말해서 백과 프론트가 명확히 분리가 되지 않는 상황을 맞이했다.

이걸 해결 하기 위해서

api로 시작하지 않는 모든 경로 요청을 React의 index.html로 포워딩하게 하는 로직이 필요하다는 것을 알았다.

그래서 WebConfig에 해당 코드 추가.

@Override
public void addViewControllers(ViewControllerRegistry registry) {
    registry.addViewController("/{spring:\\w+}")
            .setViewName("forward:/");
    registry.addViewController("/**/{spring:^(?!api$).*$}")
            .setViewName("forward:/");
}

그리고 properties에 레거시 경로 매칭 방식을 적용시켰다. (뭔진 모름 ㅋㅋ)

# Apply legacy relationship methods.
spring.mvc.pathmatch.matching-strategy=ant_path_matcher

다시 해보자.

음 이렇게 해도 똑같다. 더 알아보니까, 수동으로 처리를 할 수 있다고 한다.

@Controller
public class ReactRoutingController {

    // 모든 경로를 React의 index.html로 포워딩
    @RequestMapping(value = {"/{path:[^.]*}", "/**/{path:^(?!api).*$}"})
    public String forwardToReact() {
        return "forward:/index.html";
    }
}

이렇게 했다.

그래도 역시 안된다.

분명 뭔가 빼먹은게 존재할 것 같아서 좀 더 알아보니까. React파일을 Spring 프로젝트에 빌드해주고 사용해야된다고 한다.

그럼 해보자.

npm run build 

으로 build를 생성한다.

그럼 리액트 앱에 build 폴더가 생성되고 그 안에 파일들이 있는데 이 폴더 자체를 복사해서,
src/main/resource/static/에 붙여넣기 해준다.

그리고 properties

# React file serving
spring.mvc.static-path-pattern=/static/**

해당 코드 넣어서 가르켜주고.

이러면 되는데, 일단 지금 접속 자체가 안된다. (500 에러)

Spring Boot와 React의 라우팅 충돌문제가 생긴 것 같다.

일단 계속 시도중에 오류 하나를 발견해서 이건 고쳤다.

보면 내가 위에 build폴더를 복사하라고 했는데 이게 아니였다.

  "scripts": {
    "start": "PORT=4444 react-scripts start",
    "build": "react-scripts build && mv build/static/* ../src/main/resources/static/ && mv build/* ../src/main/resources/static/ --except static",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },

여기서 npm run build 할 때 자동으로 파일들이 제대로 들어가게끔 로직을 만들어줬다.

이게 결과.

암튼 이렇게 오류 해결중에 이런걸 발견했다.

자동으로 빌드해주는 도구.

npm install fs-extra

"build": "react-scripts build && node ./moveFiles.js", Json에서 빌드도 이렇게 수정

const fs = require('fs-extra');

const srcDir = 'build';
const destDir = '../src/main/resources/static';

fs.copy(srcDir, destDir, { overwrite: true }, (err) => {
    if (err) {
        console.error('Error copying files:', err);
    } else {
        console.log('Build files successfully moved to static folder!');
    }
});

이제 빌드해보면..

아 스테틱 두개잖아..

const fs = require('fs-extra');
const path = require('path');

async function moveBuildFiles() {
    const buildDir = path.join(__dirname, 'build');
    const staticDir = path.join(__dirname, '..', 'src', 'main', 'resources', 'static');

    try {
        // static 폴더 내부의 모든 파일을 static 최상위 폴더로 이동
        await fs.copy(path.join(buildDir, 'static'), staticDir);

        // 최상위 파일들도 static 폴더로 이동 (index.html, manifest.json 등)
        const topLevelFiles = ['asset-manifest.json', 'favicon.ico', 'index.html', 'logo192.png', 'logo512.png', 'manifest.json', 'robots.txt'];
        for (const file of topLevelFiles) {
            await fs.copy(path.join(buildDir, file), path.join(staticDir, file));
        }

        console.log('Build files moved successfully!');
    } catch (err) {
        console.error('Error moving build files:', err);
    }
}

moveBuildFiles();

GPT한테 로직 내놓으라고 했다.

이걸로 하니까

아.. 자동화 너무 좋아..

다시 문제해결하러가보자.

일단 이제 한무 리디렉션은 해결했다. 지금 6시간째다.

웨 못찾냐고!!!!!!!

그래도 무한 리디렉션은 해결했으니까 이건 또 차차 해보자..

아무리 해도 도저히 읽어드리질 못해서 구글 겁나 뒤지다가 이런걸 찾았다.

이게 개발 환경 그러니까 react랑 spring을 동시에 실행시킬 수 있는 설정이랜다.

일단 하던거 멈추고 이걸 적용해보자.

react랑 spring 동시 실행 환경 설정.

우선
build.gradle.kts에 설정을 추가 해야된다. Kotlin 문법으로 작성했다.

val frontendDir = "$projectDir/starinfo-app"

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

tasks {
    val installReact by registering(Exec::class) {
        workingDir = file(frontendDir)
        group = BasePlugin.BUILD_GROUP
        commandLine = if (System.getProperty("os.name").toLowerCase().contains("windows")) {
            listOf("npm.cmd", "install")
        } else {
            listOf("npm", "install")
        }
    }

    val buildReact by registering(Exec::class) {
        dependsOn(installReact)
        workingDir = file(frontendDir)
        group = BasePlugin.BUILD_GROUP
        commandLine = if (System.getProperty("os.name").toLowerCase().contains("windows")) {
            listOf("npm.cmd", "run", "build")
        } else {
            listOf("npm", "run", "build")
        }
    }

    val copyReactBuildFiles by registering(Copy::class) {
        dependsOn(buildReact)
        from("$frontendDir/build")
        into("$buildDir/resources/main/static")
    }

    processResources {
        dependsOn(copyReactBuildFiles)
    }
}

하단에 추가하고 빌드했고 오류 없이 성공했다.

그다음으로는

./gradlew build

로 빌드 한번 해주고,

프로젝트에 맞는 jar파일이 /build/lib에 생성 되었을 것이다.

java -jar build/libs/star_info_web-0.0.1-SNAPSHOT.jar

이렇게 실행시켜주고 서버가 정상 작동하면 성공이다.

이걸로 무한 리디렉션과 빌드 문제는 해결 되었다...

참 오래도 걸렸다.

암튼 이제는, 로그인이 정상작동하게 만들면 된다.

일단 이제 로그인화면에서 로그인은 정상적으로 돌아가는 것 처럼 보이게 되었다.

그런데 DB로 접근하던 로직이 망가졌다.

이거 해결해야된다.


구글 로그인시 DB 접근하는 것 까지 확인했다.