Java Source

Node 와 SPRING BOOT 연동

환타스틱 2024. 4. 21. 10:38

모던 웹 개발의 근간이 되는 Node 서버는 자체적으로 http 서버를 내장하고 있어서 엄밀하게 front-end 와 back-end 를 구분할 필요없이 빠르게 개발할 수 있다는 장점이 있는 듯하다.

1. 노드 웹 서버

index.js 파일을 아래와 같이 만들어 저장하고

const http = require('http')
const port = process.env.PORT || 3000
const server = http.createServer((req, res) => {
    res.writeHead(200, {'Content-Type' : 'text/plain'})
    res.end('Hello Node~')
})

server.listen(port, () => console.log(`server started on port ${port}; 종료 하려면 Ctrl-C 를 누르세요...`))

 

node.exe 로 이 파일을 실행하면 http://localhost:3000 에서 실행 결과를 확인할 수 있다. 

> node index.js

node 에 http 서버가 내장되어 있음을 보여주는 코드이다.

 

 2. 번들러

application 소스코드와 이 소스코드가 의존하는 여러 라이브러리들의 의존성을 파악하고 이를 하나의 파일로 생성한다.

예를 들어 소스코드가 아래와 같이 되어 있으면 

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <link rel="icon" href="/favicon.ico">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>VUE 연동</title>
  </head>
  <body>
    <div id="app"></div>
  </body>
  <script type="module" >
     import { createVueApp } from '/index.js'
     import webApp  from '/src/MainFrame.vue'
     createVueApp(webApp)
  </script>
</html>

index.html

import { createApp } from 'vue'
import { createVuetify } from 'vuetify'
import * as components from 'vuetify/components'
import * as directives from 'vuetify/directives'
import '@mdi/font/css/materialdesignicons.css'
import 'vuetify/styles'
export function createVueApp (vueApp) {
    const vuetify = createVuetify({ components, directives })
    createApp(vueApp).use(vuetify).mount('#app')
}

index.js

<template>
  <v-data-table
    v-model="selected"
    :headers="headers"
    :items="items"
    item-value="exposureNo"
    items-per-page="5"
    density="compact"
    show-select
    fixed-header
    height="85vh"
  ></v-data-table>
</template>

<script>
  export default {
    data() {
      const hWidth = '150px'
      return  {
        headers: [
            { title: '익스포저 번호', value: 'exposureNo', key: 'exposureNo' , minWidth: hWidth},
            { title: '익스포저 이름', value: 'exposureName' , minWidth: hWidth},
            { title: '사업장', value: 'bizPlace' , minWidth: hWidth},
            { title: '거래상대방', value: 'counterPart' , minWidth: hWidth},
            { title: '신용등급', value: 'creditGrade' , minWidth: hWidth},
            { title: '보증인', value: 'guarantor' , minWidth: hWidth},
            { title: '보증인 신용등급', value: 'guarantorCredit' , minWidth: hWidth},
            { title: '대체투자 유형', value: 'aiType', key: 'aiType' , minWidth: hWidth},
            { title: '투자 형태', value: 'aiForm' , minWidth: hWidth},
            { title: '사업단계', value: 'bizStep' , minWidth: hWidth},
            { title: '변제순위', value: 'payOrder' , minWidth: hWidth},
            { title: 'EXIT 분양률', value: 'exitRate', key: 'exitRate' , minWidth: hWidth},
            { title: '차환만기', value: 'refundMaturity' , minWidth: hWidth},
            { title: '원만기', value: 'sourceMaturity' , minWidth: hWidth},
            { title: '익스포저 금액', value: 'exposureAmount', key: 'exposureAmount' , minWidth: hWidth},
            { title: '주석', value: 'comment' , minWidth: hWidth},
        ],
        selected : [],
        items: [],
    }},
    mounted() {
        fetch('/api/aiState')
        .then((response)=>response.json())
        .then((json)=>this.items = json);
    },
  }
</script>
<style scoped>
@import url("../../base.css");
</style>

MainFrame.vue

 

번들러를 통해 빌드하고 나면

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <link rel="icon" href="/favicon.ico">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vite App - Build </title>
    <script type="module" crossorigin src="/assets/index-BEb411hP.js"></script>
    <link rel="stylesheet" crossorigin href="/assets/index-BaMTLMsk.css">
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>

와 같은 내용의 리소스 파일이 배포 디렉토리 (보통 dist) 에 생성된다.

 

 2.1 번들러 종류

webpack / browserfy / esbuild / parcel / rollup / vite 등등

 

당연히 사용하고자 하는 라이브러리에 의존하는 소스코드를 빌드하기 위해서는 해당 라이브러리를 이해하는 번들러의 플러그인이 설치되어 있어야 한다. webpack 의 장점을 소개할 때 늘 하는 말이 가장 오래된 번들러이고 따라서 지원하는 플러그인이 가장 많다고 한다. 

여기서는 vue 를 사용하였고 따라서 vite 번들러의 vue 플러그인이 필요한다. 

 

3. vite 및 vue 설치

vite 번들러 및 vue 플러그인 설치

 

4. SPRING BOOT 연동

현재 거의 모든 javascript 라이브러리들, 특히 UI 컴포넌트 라이브러리들이 번들러를 이용하여 빌드되는 환경으로 제공되는  모던 웹 개발 방식은 나처럼 java 기반 웹/WAS 개발 방식에 익숙한 노땅 개발자들에게는 당황스러운 트렌드일 수 밖에 없다. 이런 방식의 개발은 JAVA  개발자들로 하여금 필연적으로 MSA 를 이용해서 node 기반의 front-end 와 spring 기반의 back-end 를 구분해서 개발하게 강제하는 듯하다.

4.1 개발 환경에서 프록시 설정

앞의 예제에서 데이터를 가져오는 부분의 코드를 다시 보면 

mounted() {
        fetch('/api/aiState')
        .then((response)=>response.json())
        .then((json)=>this.items = json);
    },

이 코드를 개발환경에서 실행 (npm run dev) 하면  http://localhost:5173 에서 실행 결과를 볼 수 있는데  실행 결과중에 ajax 를 통해 가져오는 데이터는 localhost:8080/api/aiState 에서 아래와 같이 조회된다.

http://localhost:8080/api/aiState

따라서 localhost:5173/api/aiState 라는 URL 을 localhost:8080/api/aiState 로 연결시키도록 프록시 설정할 필요가 있다. 

 

export default defineConfig({
  plugins: [
    vue(),
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    },
  },
  server: {
    proxy: {
      '/api': {
        target: 'http://localhost:8080/api',
        changeOrigin: true,
        secure: false,     
        rewrite: (path) => path.replace(/^\/api/, '')
      },
    }
  }
})

vite.config.js

 

개발환경 구성

4.2 운영환경 

개발에서 개발 및 테스트가 완료되면 번들러를 통해 빌드하고 빌드한 결과물을 SPRING BOOT 의 static 디렉토리로 복사한 다음 SPPRING BOOT 를 다시 빌드하면 된다. 

또는 처음부터 번들러의 output directory 를 SPRING BOOT 의 static 디렉토리로 설정해서 복사하는 번거로움을 없앨 수 도 있다.