프로그래밍/vue

인텔리제이(intellij) 스프링 부트(spring boot) vue.js 연동 8080 포트 방법

소행성왕자 2021. 11. 23. 15:11
인텔리제이(intellij) 스프링 부트(spring boot) vue.js 연동 8080 포트 방법

 

보통 백엔드서버 8081 프론트엔드 8081 두개의 서버를 가동하지만

 

본 문서에서는 백엔드 서버 8080 으로 연동하는 방법을 사용하고자 한다.

 

필요사항
  • intellij
  • spring boot
  • vue.js

 


백엔드 (spring boot) 설정



build.gradle
plugins {
    id 'org.springframework.boot' version '2.5.6'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'
    id "com.github.node-gradle.node" version "3.1.1"
    id 'war'
}

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

node {
    download = true
    version = "14.6.0"
    npmVersion = "6.14.7"
    distBaseUrl = "https://nodejs.org/dist"
    npmInstallCommand = "install"
    workDir = file("${project.projectDir}/.gradle/nodejs")
    npmWorkDir = file("${project.projectDir}/.gradle/npm")
    nodeProjectDir = file('./front')
}


task setUp(type: NpmTask) {
    description = "Install Node.js Packages"
    args = ['install']
}

task buildFrontEnd(type: NpmTask, dependsOn: setUp) {
    description = "build Vue"
    args = ['run', 'build']
}

sourceSets {
    main {
        resources {
            srcDir './src/resources/static'
        }
    }
}

processResources.dependsOn 'buildFrontEnd'

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
    all {
        exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-web-services'
    implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.0'
    implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect' /* Thymeleaf Layout */
    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    runtimeOnly 'com.h2database:h2'
    runtimeOnly 'mysql:mysql-connector-java'
    annotationProcessor 'org.projectlombok:lombok'
    providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    implementation 'org.springframework.boot:spring-boot-starter-log4j2'
    implementation 'org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16'

}

test {
    useJUnitPlatform()
}
 
application.properties
server.port=8080

# DB Setting
spring.datasource.username=idid
spring.datasource.password=password
spring.datasource.url=jdbc:log4jdbc:mysql://1.1.0.7:3306/idid?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Seoul
spring.datasource.driver-class-name=net.sf.log4jdbc.sql.jdbcapi.DriverSpy

# MyBatis
#mybatis.mapper-locations=mybatis/mapper/**/*.xml
#mybatis.mapper-locations=resources/mybatis/mapper/**/*.xml
mybatis.mapper-locations=classpath:mapper/**/*.xml

# model 프로퍼티 camel case 설정
mybatis.configuration.map-underscore-to-camel-case=true

# xml파일 result type에 패키지명을 생략할 수 있도록 alias 설정
#mybatis.type-aliases-package=com.example.demo.domain
mybatis.type-aliases-package=com.**.domain

server.servlet.jsp.init-parameters.development=true

# log4j2
logging.config=classpath:log4j2.xml

# spring boot 재시작 없이 사용
spring.devtools.livereload.enabled=true
spring.freemarker.cache=false
spring.thymeleaf.cache=false

 

com.example.demo
MvcConfig.java
package com;

import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.resource.PathResourceResolver;

import java.io.IOException;

@Configuration
public class MvcConfig implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler()
                .addResourceLocations("classpath:/static/")
                .resourceChain(false)
                .addResolver(new PathResourceResolver(){
                    @Override
                    protected Resource getResource(String resourcePath, Resource location) throws IOException {
                        Resource resource = location.createRelative(resourcePath);
                        return resource.exists() && resource.isReadable() ? resource : new ClassPathResource("/static/index.html");
                    }
                });
    }


}

 

 

프론트엔드 (vue) 설정

 

front/vue.config.js

proxy 를 이용하여 백엔드 서버와 통신한다.(ajax)

module.exports = {
    outputDir: "../src/main/resources/static",
    indexPath: "../static/index.html",
    devServer: {
        port: 8080,
        proxy: "http://localhost:8080"
    },
    chainWebpack: config => {
        const svgRule = config.module.rule("svg");
        svgRule.uses.clear();
        svgRule.use("vue-svg-loader").loader("vue-svg-loader");
    }
};

 

front/src/main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')


실제 사용할 도메인 아래 baseURL 변경해주면 됨 (.gitignore 추가) 서버에서 생성해줘야함 

front/src/http-common.js
import axios from "axios"

export default axios.create({
    baseURL: "http://localhost:8080",  
    header:{
        "Content-type":"application/json",
    }
});
 
front/src/App.vue
<template>
  <div id="app">
    <div id="nav">
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link> |
      <router-link to="/list">DB List</router-link> |
    </div>
    <router-view/>
  </div>
</template>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

#nav {
  padding: 30px;
}

#nav a {
  font-weight: bold;
  color: #2c3e50;
}

#nav a.router-link-exact-active {
  color: #42b983;
}
</style>



front/src/router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(
        /* webpackChunkName: "about" */ '../views/About.vue'
        )
  },
  {
    path: '/list',
    name: 'List',
    component: () => import(
        /* webpackChunkName: "list" */ '../views/List.vue'
        )
  },

]

const router = new VueRouter({
  mode: "history",
  routes
})

export default router



front/src/views/List.vue
<template>
    <div class="hello">

        <h3 v-for="user in users" :key="user.id">{{user.name}} {{user.email}}</h3>
        <p>
            For a guide and recipes on how to configure / customize this project,<br>
            check out the
            <a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
        </p>

    </div>
</template>

<script>
    import http from "../http-common";

    export default {
        name: 'HelloWorld',
        data(){
            return{
                users:[]
            }
        },
        methods:{
            retrieveUsers(){
                http
                    .get("/api/v1/list")
                    .then(response=>{
                        this.users = response.data;
                        console.log(response.data);
                    })
                    .catch(e=>{
                        console.log(e);
                    })
            }
        },
        mounted(){
            this.retrieveUsers();
        }
    }
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
    h3 {
        margin: 40px 0 0;
    }
    ul {
        list-style-type: none;
        padding: 0;
    }
    li {
        display: inline-block;
        margin: 0 10px;
    }
    a {
        color: #42b983;
    }
</style>


배포할때에만 하나의 포트 8080 으로 사용하고

개발시에는 백엔드 8081 프론트앤드 8080 으로 사용하는게 좋겠다.
왜? 수정후 빌드하는데 시간이 오래 걸린다.

 

BackEnd 서버시작(8081)

인텔리제이 시작


FrontEnd 서버 시작 (8080)

$ npm run serve

웹브라우져 접속

http://localhost:8080/