Springboot 프로젝트를 생성한다.
여기서는 Intellij 를 이용해 생성했고, Gradle과 Java 버전 11을 사용했다.
이 과정은 생략하겠다.
react를 설치하는 방법은 다양하지만 여기서는 Create react app 을 이용해 생성하고자 한다
관련 항목은 아래 링크에서 설명되어 있다
https://reactjs-kr.firebaseapp.com/docs/installation.html
node.js 6버전 이상이 설치되어 있어야 한다
npm을 이용해 create-react-app 을 설치한다
npm install -g create-react-app
frontend 폴더를 만들고 그 안에 리액트 프로젝트를 생성한다
mkdir frontend
cd frontend
create-react-app my-app
다음과 같은 로그가 나오고 완료된다.
Success! Created my-app at /Users/dgpark/git/project/react/frontend/my-app
Inside that directory, you can run several commands:
npm start
Starts the development server.
npm run build
Bundles the app into static files for production.
npm test
Starts the test runner.
npm run eject
Removes this tool and copies build dependencies, configuration files
and scripts into the app directory. If you do this, you can’t go back!
We suggest that you begin by typing:
cd my-app
npm start
Happy hacking!
폴더에 접근한 뒤 리액트를 실행한다.
cd my-app
npm start
> my-app@0.1.0 start /react/frontend/my-app
> react-scripts start
ℹ 「wds」: Project is running at http://192.168.2.139/
ℹ 「wds」: webpack output is served from /
ℹ 「wds」: Content not from webpack is served from /Users/dgpark/git/project/react/frontend/my-app/public
Compiled successfully!
You can now view my-app in the browser.
Local: http://localhost:3000/
On Your Network: http://192.168.2.139:3000/
Note that the development build is not optimized.
To create a production build, use npm run build.
localhost:3000 으로 접속하면 다음 화면이 뜬다.
폴더구성은 다음과 같다
# React 를 작성한다
편의를 위해 react-bootstrap와 react-router-dom을 설치, 사용한다
그리고 API 호출을 위해 axios 도 설치한다
npm install bootstrap react-bootstrap --save
npm install react-router-dom --save
npm install axios --save
2개 메뉴를 생성(Main, Dashboard)
MainComponent.jsx
import React, {Component} from "react";
class MainComponent extends Component {
render() {
return(
<div>
Main 페이지
</div>
)
}
}
export default MainComponent
Dashboard.jsx
import React, {Component} from "react";
class DashboardComponent extends Component {
render() {
return(
<div>
Dashboard 페이지
</div>
)
}
}
export default DashboardComponent
router 를 이용해 페이지를 연결한다
TopMenuComponent.jsx
import React, {Component} from "react";
import {Navbar} from "react-bootstrap";
import {BrowserRouter as Router, Route} from "react-router-dom";
import MainComponent from './MainComponent'
import DashboardComponent from './DashboardComponent'
class TopMenuComponent extends Component {
render() {
return (
<Router>
<Navbar
bg="dark"
variant="dark"
className="mb-4" >
<Navbar.Brand href="/">
Home
</Navbar.Brand>
<Navbar.Brand href="/main">
Main
</Navbar.Brand>
<Navbar.Brand href="/dashboard">
Dashboard
</Navbar.Brand>
</Navbar>
<Route path="/main" component={MainComponent} />
<Route path="/dashboard" component={DashboardComponent} />
</Router>
)
}
}
export default TopMenuComponent;
설정된 것을 App.js 에 넣어 마무리한다
import React from 'react';
import 'bootstrap/dist/css/bootstrap.min.css'
import './App.css';
import TopMenuComponent from "./component/TopMenuComponent";
function App() {
return (
<div className="App">
<div>
<TopMenuComponent>
</TopMenuComponent>
</div>
</div>
);
}
export default App;
react 서버를 새로 실행한다
npm start
그럼 이제 axios를 이용해 호출해보자
# 서버와 통신하기 (API)
ApiController 를 생성하여 매핑한다
@RestController
public class ApiController {
@GetMapping("/api/hello")
public HashMap hello() {
HashMap result = new HashMap();
result.put("message", "안녕하세요");
return result;
}
}
MainComponent.jsx 파일을 열어 통신코드를 추가한다.
import React, {Component} from "react";
import axios from "axios";
class MainComponent extends Component {
constructor(props) {
super(props)
this.state = {
message: ""
}
}
componentDidMount() {
this.getApi();
}
getApi = () => {
axios.get("http://localhost:8080/api/hello")
.then(res => {
console.log(res);
this.setState({
message: res.data.message
})
})
.catch(res => console.log(res))
}
render() {
return(
<div>
Main 페이지
</div>
)
}
}
export default MainComponent
브라우저에서 확인하면 브라우저 로그에 다음 에러를 확인할 수 있다
Access to XMLHttpRequest at 'http://localhost:8080/api/hello' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
MainComponent.jsx:11 Error: Network Error
at createError (createError.js:16)
at XMLHttpRequest.handleError (xhr.js:83)
CORS는 Cross Origin Resource Sharing의 약자로 도메인 또는 포트가 다른 서버의 자원을 요청하는 매커니즘이다
상세한것은 아래 페이지 참조한다
https://velog.io/@wlsdud2194/cors
이것을 해제하기 위해선 서버측에 작업이 필요하다
WebConfig.java 를 생성하여 다음과 같이 설정한다
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry
.addMapping("/api/**")
.allowedOrigins("http://localhost:3000")
;
}
}
서버를 새로 실행한 후 새로고침해보면 다음처럼 데이터를 받아오는데 성공한다
{data: {…}, status: 200, statusText: "", headers: {…}, config: {…}, …}
data: {message: "안녕하세요"}
status: 200
statusText: ""
headers: {content-type: "application/json"}
config: {url: "http://localhost:8080/api/hello", method: "get", headers: {…}, transformRequest: Array(1), transformResponse: Array(1), …}
request: XMLHttpRequest {readyState: 4, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, onreadystatechange: ƒ, …}
__proto__: Object
# frontend 와 backend 같이 build 하기
frontend 빌딩하기
# 터미널로 frontend/my-app 폴더로 접근한 후
npm run build
실행하고 나면 아래와같이 폴더가 생성된다
다만 이대로 bootJar 로 만들면 frontend 의 build 내용이 포함되지 않는다
그래서 gradle 설정을 변경해야 한다
build.gradle 파일은 열어 다음을 수정하면 npm run build 와 자바 컴파일을 동시에 한다
plugins {
...
# moowork.node 추가
id "com.moowork.node" version "1.3.1"
}
apply plugin: "com.moowork.node"
...
# (아래 추가)
def webappDir = "$projectDir/frontend/my-app"
task appNpmInstall(type: NpmTask) {
workingDir = file("${webappDir}")
args = ["run", "build"]
}
task copyWebApp(type: Copy) {
from 'frontend/my-app/build'
into "build/resources/main/static"
}
copyWebApp.dependsOn(appNpmInstall)
compileJava.dependsOn(copyWebApp)
이제 bootJar 를 생성하면 build/resources/main/static 에 파일이 생성되 있음을 확인할 수 있다.
build/libs 폴더에 있는 jar 파일을 실행하면 localhost:8080 으로도 react가 연결됨을 확인할 수 있다.
문제는 Main, Dashboard 의 연결이 안된다는 점이다.
다음과 같이 404에러가 발생한다. Spring 에서 해당 URL Mapping 을 찾을 수 없기 때문이다
서버쪽에서 WebController를 생성하여 error가 발생해도 index.html 로 이동하도록 유도한다
WebController.java
@Controller
public class WebController implements ErrorController {
@GetMapping({"/", "/error"})
public String index() {
return "index.html";
}
@Override
public String getErrorPath() {
return "/error";
}
}
이제 다시 bootJar 를 실행하고 만들어진 jar 파일을 실행해보자
java -jar build/libs/react-0.0.1-SNAPSHOT.jar
제대로 이동되는 것을 확인할 수 있다.
github:
https://github.com/lemontia/springboot_react
'공부 > 프로그래밍' 카테고리의 다른 글
[spring security oauth] 403이 아닌 406 에러가 나는 경우 (Accept 설정에 따른 문제) (0) | 2020.01.30 |
---|---|
[java] builder 패턴, 객체를 안전하게 생성하기 (0) | 2020.01.29 |
[개발] 2019년 하반기 회고록 (0) | 2019.12.29 |
[개발] 2019년 상반기 회고록 (0) | 2019.12.29 |
[gitlab-telegram] gitlab 의 메세지를 telegram으로 받기 (0) | 2019.12.20 |
댓글