예약 관리 시스템 - Spring + Vue

예약 관리 시스템 (Spring Boot 3 + Vue 3) - 사용자 인증 프론트엔드 (Vue 3 + Vuetify)

그랜파 개발자 2025. 5. 26. 11:01

Spring Boot 백엔드와 연동 가능한 Vue 3 + Vuetify 기반의 간단한 홈, 회원가입, 로그인 예제입니다.
기본적인 페이지와 API 연동 코드, 라우터, Vuetify UI를 포함합니다.

 

1. 프로젝트 

npm init vue@latest

Project name (target directory):
│  reservation

cd reservation
npm install
npm install vue-router@4 vuetify@3 axios

2. main.js

import { createApp } from 'vue';
import App from './App.vue';
import router from './router';

import 'vuetify/styles';
import { createVuetify } from 'vuetify';
import * as components from 'vuetify/components';
import * as directives from 'vuetify/directives';

const vuetify = createVuetify({
  components,
  directives,
});

createApp(App).use(router).use(vuetify).mount('#app');

3. router.js

import { createRouter, createWebHistory } from 'vue-router';
import Home from '@/views/HomeView.vue'    //./HomeView.vue';
import SignUp from '@/views/SignUp.vue';
import Login from '@/views/Login.vue';

const routes = [
  { path: '/', name: 'Home', component: Home },
  { path: '/signup', name: 'SignUp', component: SignUp },
  { path: '/login', name: 'Login', component: Login },
];

const router = createRouter({
  history: createWebHistory(),
  routes,
});

export default router;

4. api/auth.js (Axios로 Spring Boot API 호출)

import axios from 'axios';

const API_URL = 'http://localhost:8080/api/auth'; // Spring Boot 백엔드 주소

export function signUp(user) {
  // user = { username, email, password }
  return axios.post(`${API_URL}/register`, user);
}

export function login(credentials) {
  // credentials = { username, password }
  return axios.post(`${API_URL}/login`, credentials);
}

5. App.vue

<template>
  <v-app>
    <v-app-bar app color="primary" dark>
      <v-toolbar-title>예약관리 시스템</v-toolbar-title>
      <v-spacer />
      <v-btn text to="/">홈</v-btn>
      <v-btn text to="/login">로그인</v-btn>
      <v-btn text to="/signup">회원가입</v-btn>
    </v-app-bar>

    <v-main>
      <v-container class="mt-5">
        <router-view />
      </v-container>
    </v-main>
  </v-app>
</template>

<script setup>
</script>

 


6. views/Home.vue

<template>
  <v-container class="fill-height" fluid>
    <v-row align="center" justify="center">
      <v-col cols="12" md="6">
        <v-card>
          <v-card-title>홈 페이지</v-card-title>
          <v-card-text>
            <p>Spring Boot + Vue 3 + Vuetify 예제 홈 화면입니다.</p>
          </v-card-text>
        </v-card>
      </v-col>
    </v-row>
  </v-container>
</template>

7. views/SignUp.vue

<template>
  <v-container>
    <v-row justify="center">
      <v-col cols="12" md="6">
        <v-card>
          <v-card-title>회원가입</v-card-title>
          <v-card-text>
            <v-form @submit.prevent="submitSignUp" ref="form">
              <v-text-field v-model="user.email" label="이메일" type="email" required />
              <v-text-field v-model="user.password" label="비밀번호" type="password" required />
              <v-text-field v-model="user.username" label="사용자 이름" required />
              <v-btn type="submit" color="primary" :loading="loading" block>가입하기</v-btn>
            </v-form>
            <v-alert v-if="error" type="error" class="mt-4">{{ error }}</v-alert>
            <v-alert v-if="success" type="success" class="mt-4">{{ success }}</v-alert>
          </v-card-text>
        </v-card>
      </v-col>
    </v-row>
  </v-container>
</template>

<script setup>
import { ref } from 'vue'
import { signUp } from '../api/auth'

const user = ref({
  name: '',
  email: '',
  password: '',
})

const loading = ref(false)
const error = ref('')
const success = ref('')

const submitSignUp = async () => {
  loading.value = true
  error.value = ''
  success.value = ''
  try {
    const response = await signUp(user.value)
    success.value = response.data.message || '회원가입 성공! 로그인 페이지로 이동합니다.'
    setTimeout(() => {
      window.location.href = '/login'
    }, 1500)
  } catch (e) {
    error.value = e.response?.data?.message || '회원가입 실패'
  } finally {
    loading.value = false
  }
}
</script>

8. views/Login.vue

<template>
  <v-container>
    <v-row justify="center">
      <v-col cols="12" md="6">
        <v-card>
          <v-card-title>로그인</v-card-title>
          <v-card-text>
            <v-form @submit.prevent="submitLogin">
              <v-text-field v-model="email" label="이메일" type="email" required />
              <v-text-field v-model="password" label="비밀번호" type="password" required />
              <v-btn type="submit" color="primary" :loading="loading" block>로그인</v-btn>
            </v-form>
            <v-alert v-if="error" type="error" class="mt-4">{{ error }}</v-alert>
          </v-card-text>
        </v-card>
      </v-col>
    </v-row>
  </v-container>
</template>

<script setup>
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { login } from '../api/auth'

const email = ref('')
const password = ref('')
const loading = ref(false)
const error = ref('')

const router = useRouter()

const submitLogin = async () => {
  loading.value = true
  error.value = ''
  try {
    const response = await login({ email: email.value, password: password.value })

    // 로그인 성공 시 토큰 저장 및 이동
    const token = response.token
    localStorage.setItem('token', token)

    router.push('/')
  } catch (e) {
    error.value = e.response?.data?.message || '로그인 실패'
  } finally {
    loading.value = false
  }
}
</script>

 

✅ 개발 서버 실행

npm run dev

 

브라우저에서 http://localhost:5173 열어 확인하세요.