๋ก๊ทธ์ธ๊น์ง ๋ง๋ค์๋ค.
์ฌ์ฉ์๊ฐ ๋ก๊ทธ์ธ์ ํ๊ฒ๋๋ฉด
๋ฉ์ธํ๋ฉด์ ์ฌ์ฉ์ ์์ด๋๊ฐ ๋ณด์ด๋๋ก
์ค์ ํด๋ณด์!
[ ๋ก๊ทธ์ธ ๋ง๋ค๊ธฐ ]
๋ธ๋ก๊ทธ์ ์ ์๋ vue์ฝ๋๊ฐ ์กฐ๊ธ ๋ฐ๋์์ต๋๋ค
[SpringBoot, Vue.js] ๋ก๊ทธ์ธ ํ๋ฉด ๋ง๋ค๊ธฐ, passwordEncoder.matches๋ฅผ ํตํด ์ํธํ๋ ๋น๋ฐ๋ฒํธ ๋น๊ตํ๊ธฐ.
ํ์๊ฐ์ ๊น์ง ๋ง๋ค์๋ค.์ด์ ํ์๊ฐ์ ํ ์์ด๋์ ๋น๋ฐ๋ฒํธ๋ก๋ก๊ทธ์ธ์ ํด๋ณด์! [ ํ์๊ฐ์ 1ํธ + 2ํธ ] [SpringBoot] (IntelliJ, vue.js, H2) ํ์๊ฐ์ ํ์ด์ง ๋ง๋ค๊ธฐ 1ํธ : dto ๋ง๋ค๊ณ ์ด๋ฆ, ํจ์ค์๋, ์ ํ
post-this.tistory.com
โป
์ด ์ฝ๋๋ ๊ทธ๋ฅ ์ฐ์ต์ฉ์ผ๋ก ๊ฒ๋ชจ์ต๋ง ๋ก๊ทธ์ธ ๋ ๊ฒ์ฒ๋ผ ๋ง๋ ๊ฒ์ ๋๋ค.
๊ทธ๋ ๊ธฐ์ ์ค์ ๋ก ๋ก๊ทธ์ธ๋ ํ๋ฉด์ด๋ผ๊ณ ๋ณด๊ธด ์ด๋ ต์ต๋๋ค.
๋ง์ฝ ์ ๋๋ก๋ ๋ก๊ทธ์ธ์ ๊ตฌํํ๊ณ ์ถ์ผ์๋ค๋ฉด,
์คํ๋ง์์ ์ฒ๋ฆฌํ๋๋ก ํ๋ฉฐ ํ ํฐ ํน์ ์ธ์ ์ ๋ฐ๊ธํ๋ ๊ฑธ ๊ถ์ฅํฉ๋๋ค.
1. ํ๋ฉด ๋์๊ณผ ์ ์ฒด ์ฝ๋
- ํ๋ฉด ๋์
- ์ฝ๋๋ ๋ค๋ฅธ ๋ถ๋ถ ๋๋ฌธ์ ์์ ์ค์ด๋ผ ํ์ ์์ฑ๋๋ฉด ์ฌ๋ฆฌ๋๋ก ํ๊ฒ ์ต๋๋ค.
2. ์ด๋ป๊ฒ ๋ง๋ค๊น?
- ๋ฉ์ธํ๋ฉด

์ฒ์์ ๊ตฌ์ํ๋ ๊ฒ์ ํ์ด์ง๋ฅผ ์๋กญ๊ฒ ํ๋ ๋ง๋ค์ด์ ๋ก๊ทธ์ธ์ด ๋๋ฉด ํด๋น ํ์ด์ง๋ก ๋์ด๊ฐ๋๋ก ๋ง๋ค์๋ค. ๊ทธ๋ฐ๋ฐ ์๊ฐํด๋ณด๋ ๊ทธ๋ ๊ฒ ๋๋ฉด ์์์ ๋ ์ฌ์ฉํ๊ฒ ๋๋ ๊ฒ ๊ฐ์ ํ์ ์์ ํ๋ค. (๋ง์ฝ ๋ฉ์ธ ํ์ด์ง์ ๊ฒ์๊ธ์ด ๋ณด์ด๋๋ก ๋์ด์์ผ๋ฉด ๋ก๊ทธ์ธ ํ ๋ค์ด๊ฐ ํ์ด์ง์๋ ๊ฐ์ ๊ฒ์๊ธ์ด ๋ณด์ด๋๋ก ์ฝ๋๋ฅผ ์ถ๊ฐํ๊ณ ๊ทธ๋งํผ ์์์ด ๋ญ๋น๋๋ค๊ณ ์๊ฐํ์)
์๋ ๊ฐ์ง๊ณ ์๋ MainView ํ์ด์ง๋ ์ค๋ฅธ์ชฝ ์์ด์ฝ์ ๋๋ฅด๋ฉด ํ์๊ฐ์ ํ์ด์ง๋ก ์ฐ๊ฒฐ๋๋ ๋ฒํผ๊ณผ ๋ก๊ทธ์ธ ํ์ด์ง๋ก ์ฐ๊ฒฐ๋๋ ๋ฒํผ์ด ์์๋ค. ๊ทธ๋ฆฌ๊ณ ์ด๋ฐ ๋ถ๋ถ์ ๋ณด์ฌ์ฃผ๋ vue๊ฐ RightSide.vue์๋ค. ์ฌ์ฉ์๊ฐ ๋ก๊ทธ์ธ์ ํ๊ณ , ๋ก๊ทธ์ธ ํ๋ค๋ ๊ธฐ๋ก(?)์ด ๋ค์ด์ค๋ฉด RightSide.vue๊ฐ ๋ค๋ฅธ vue๋ก ๋ฐ๋๋๋ก ๋ง๋ค์๋ค.
3. LoginView.vue
<script> ์ฝ๋
methods: {
async login() {
try {
const res = await axios.post("http://localhost:8080/api/login", {
userId: this.userId,
pw: this.pw
});
localStorage.setItem("displayName", this.userId());
alert("๋ก๊ทธ์ธ๋์์ต๋๋ค.");
this.$router.replace("/main");
} catch (e) {
alert(e.response.data);
}
},
๋ก๊ทธ์ธ ๋ง๋๋ ํฌ์คํ ์์ ๋ณด์ฌ์คฌ๋ ์ฝ๋๋ ์กฐ๊ธ ๋ฌ๋ผ์ก๋ค.
localStorage.setItem("displayName", this.userId); /* ๋ก๊ทธ์ธ ์ฑ๊ณตํ๋ฉด path์ ์ ํ ๊ฒฝ๋ก๋ก ๋๊น, query์ ์ ์ ๋ฐ์ดํฐ์ ํจ๊ป */ this.$router.push({ path: "/customer-view", query: { userId: this.userId } });
์ด ์ฝ๋๊ฐ ์ฝ๋๋ฅผ ๋ณ๊ฒฝํ๊ธฐ ์ ์ด๋ค. ๋ก๊ทธ์ธ์ด ์ฑ๊ณตํ๋ฉด ํ์ด์ง๊ฐ /customer-view๋ก ๋์ด๊ฐ๋๋ก ํ๋ฉด์, userId๊ฐ ์ฟผ๋ฆฌ๋ก ๊ฐ์ด ๊ฐ๊ฒ๋๋ค. ์ด๋ ๊ฒ ๋ง๋๋ ๋ง์์ ๋ค์ง ์์๋ ์ ์ด url์ ์ฌ์ฉ์ ์์ด๋๊ฐ ๋ณด์ฌ์ง๋ค๋ ๊ฒ์ด๋ค. ๊ทธ๋์ ํ์ ์ฝ๋๋ฅผ ์์ ํ๋ค.
์์ ๋ ์ฝ๋๋ฅผ ๋ณด๊ฒ ๋ค. localStorage๋ฅผ ์ผ๋๋ฐ, ์ด๊ฑด ์๋ฐ์คํฌ๋ฆฝํธ์์ ์ง์ํ๋ ๊ฒ์ด๋ค. vue๋ ์๋ฐ์คํฌ๋ฆฝํธ ๋ฌธ๋ฒ์ ์ง์ํ๊ธฐ ๋๋ฌธ์ ๋น์ฐํ ์ฌ์ฉํ ์ ์๋ค. localStorage๋ฅผ ์ฌ์ฉํ๋ฉด ๋ธ๋ผ์ฐ์ ์ key-value ๊ฐ์ Storage์ ์ ์ฅํ ์ ์๋ค. ์ ์ฅํ ๋ฐ์ดํฐ๋ ์ธ์ ๊ฐ์ ๊ณต์ ๋๋ค. ์ฆ, ์ธ์ ์ด ๋ฐ๋์ด๋ ์ ์ฅํ ๋ฐ์ดํฐ๊ฐ ์ ์ง๋๋ค. localStorage๋ setItem(์์ดํ ์ถ๊ฐ), getItem(์์ดํ ์ฝ๊ธฐ), removeItem(item ์ญ์ ), clear(๋๋ฉ์ธ ๋ด์ localStrage ๊ฐ ์ญ์ ), length(์ ์ ์์ดํ ๊ฐฏ์), key(index๋ก key ๊ฐ ์ฐพ๊ธฐ)๊ฐ ์๋ค. ๊ทธ ์ค setItem์ ์ฌ์ฉํ์ฌ ๋ก๊ทธ์ธํ ์ฌ์ฉ์ ์์ด๋๋ฅผ ์ ์ฅํ๋๋ก ํ๊ฒ ๋ค. key์ ๋ค์ด๊ฐ๋๊ฒ displayName์ด ๋๊ณ value์ ๋ค์ด๊ฐ๋๊ฒ userId๊ฐ ๋๋ค.
this.$router.push๋ฅผ this.$router.replace๋ก ์ฝ๋๋ฅผ ๋ณ๊ฒฝํ๋ค. push๋ ๋ธ๋ผ์ฐ์ ํ์คํ ๋ฆฌ์ ์ ํญ๋ชฉ์ ์ถ๊ฐํ๋ค. ์ฌ์ฉ์๊ฐ ๋ค๋ก ๊ฐ๊ธฐ๋ฅผ ๋๋ฅด๋ฉด ๋ก๊ทธ์ธ ํ์ด์ง๋ก ๋์๊ฐ ์ ์๋ค. ์ด๋ถ๋ถ์ด ๋ง์์ ์๋ค์ด์ replace๋ก ๋ณ๊ฒฝํ๋ค. replace๋ ํ์ฌ ํ์คํ ๋ฆฌ ํญ๋ชฉ์ ๋์ฒดํ๋ค. ๋ค๋ก ๊ฐ๊ธฐ๋ฅผ ๋๋ฌ๋ ๋ก๊ทธ์ธ ํ์ด์ง๋ก ๋์๊ฐ ์ ์๋ค. ๋ณดํต replace๋ฅผ ์จ์ ๋ก๊ทธ์ธ ์ฑ๊ณต ํ์ ๋ค๋ก ๊ฐ๊ธฐ๋ฅผ ๋ฐฉ์งํ๋ค.
4. MainView.vue
<script> ์ฝ๋
data() {
return {
isRightSideOpen: false,
isLeftSideOpen: false,
/* ๋ก๊ทธ์ธ ์ ํ๋ฉด์ ๋ํ๋ผ ์ฌ์ฉ์ ์์ด๋ ํน์ธ ๋๋ค์ */
displayName: null,
}
},
localStorage์ ์ ์ฅํ๋ displayName ํค๋ฅผ null๋ก ์ค์ ํ๋ค.
<script>์ computed ์ฝ๋
loggedIn() {
/* ๋ก๊ทธ์ธ ์ฌ๋ถ, displayname์ด ์์ผ๋ฉด ๋ก๊ทธ์ธ ์ํ๋ก ๊ฐ์ฃผ */
return Boolean(this.displayName);
},
displayName์ ๋ฌธ์์ด์ด ๋ค์ด์์ null์ด ์๋๊ฒ ๋๋ฉด true๋ฅผ ๋ฐํํ๋ค. ๋ง์ฝ null์ด๋ฉด, false๋ฅผ ๋ฐํํ๋ค.
<script> ์ฝ๋ ์ค methods
// ๋ก๊ทธ์์ ํ๋๊ฑฐ.
loggedOut() {
localStorage.removeItem('displayName'); // ์ ์ฅ์ ๋น์ฐ๊ธฐ
this.displayName = null; // null๋ก ๋ง๋ค์ด์ ์ค๋ฅธ์ชฝ ์ฌ์ด๋๋ฐ ๋ฐ๊พธ๊ณ
this.$router.replace('/main'); // main ํ๋ฉด
},
๋ก๊ทธ์ธ์ ํ๊ณ ๋๋ฉด RightSide.vue๊ฐ CustomerRight.vue๋ก ๋ณ๊ฒฝ๋๋ค. ์์ง CustomerRight.vue์ ๋ํด ์ค๋ช ํ์ง ์์์ง๋ง ๊ทธ ์์๋ ํ์์ ์์ด๋๋ฅผ ๋ํ๋ด๊ณ ๋ก๊ทธ์์์ ํ ์ ์๋ ํด๋ฆญ์ ๋ง๋ค ๊ฒ์ด๋ค. ๋ก๊ทธ์์ ํ ์คํธ๋ฅผ ๋๋ฅด๋ฉด CustomerRight.vue๊ฐ ๋ถ๋ชจ์๊ฒ ๋ก๊ทธ์์์ ์๋ฆฐ๋ค.(์ฌ์ฉ์๊ฐ ๋ก๊ทธ์์์ ๋๋ ์ด์~) ๊ทธ๋์ ๊ทธ ๋ก๊ทธ์์ ๋ก์ง์ ๋ถ๋ชจ์ธ MainView.vue์์ ์ฒ๋ฆฌํ๋ ๊ฒ์ด๋ค.
displayName์ ๋ค์ด์จ key์ value ๊ฐ์ removeItem์ผ๋ก ์ง์์ค๋ค. ๊ทธ๋ฆฌ๊ณ displayName ๊ฐ์ null๋ก ์ค์ ํ๋ค. ๊ทธ๋ฆฌ๊ณ main ํ๋ฉด์ ๋ค์ ๋ถ๋ฌ์จ๋ค. ์๊น๋ ์ค๋ช ํ์ง๋ง this.$router.push๋ฅผ ์ฐ๋ฉด ๋ค๋ก ๊ฐ๊ธฐ ๋๋ ์ ๋ ๋ก๊ทธ์ธ ์ํ๊ฐ ๋ํ๋๋ค. ๊ทธ๋์ replace๋ก ์์ฑํ๋ค.
<template> ์ฝ๋
<RightSide v-if="!loggedIn" :open="isRightSideOpen" />
<CustomerRight v-else :open="isRightSideOpen"
:display-name="displayName" @logged-out="loggedOut" />
์ฌ๊ธฐ์ ๊ฐ ์กฐ๊ฑด์ ๋ง์ถฐ RightSide๋ฅผ ๋ณด์ด๊ฒ ํ ์ง, CustomerRight๋ฅผ ๋ณด์ด๊ฒ ํ ์ง ๊ฒฐ์ ํ ๊ฒ์ด๋ค. ์ฐ๋ฆฌ์ ์กฐ๊ฑด์ ๋ก๊ทธ์ธ์ด ๋์์ ๋ CustomerRight์ด ๋ณด์ด๋๋ก ํ๋ ๊ฒ์ด๋ค. ๋ก๊ทธ์ธ์ด ๋ ๊ฑธ ์ด๋ป๊ฒ ์๊ฒ ํ๋์ง ๋๋์๋ณด๋ฉด, ํ์์ displayName์ null์ ๋ฃ์๋ค๊ฐ ๋ก๊ทธ์ธ์ด ๋๋ฉด displayName์ key์ value๊ฐ ์ค๋ฉด์ loggenIn( )์ผ๋ก ์์ ๊ฐ์ ์ฌ๋ถ๋ฅผ ํ์ธํ๋ค.
์ฝ๋๋ฅผ ์ดํด๋ณด์. ๋ง์ฝ์(v-if) loggedIn์ return ๊ฐ์ด false์ด๋ฉด RightSide ๋ทฐ๋ฅผ isRightSideOpenํ๋ค๊ณ ํ๋ค. isRightSideOpen์ ์ด๋ฆผ/๋ซํ ์ํ๋ฅผ ์ ๋ฌํ๋ ์ญํ ์ ํ๋ค.
๋ง์ฝ์(v-else) v-if์์ ์ง์ ํ ๊ฐ ์ธ์ ๋ค๋ฅธ ๊ฐ์ด ๋์ค๋ฉด CustomerRight์ด open๋๋ค. :display-name="displayName"์ผ๋ก ์ฌ์ฉ์ id ๊ฐ์ด ๋์ด๊ฐ๋๋ก ํ๋ค. ์ฌ๊ธฐ์ ์ ์์๋ฌ์ผํ ๊ฒ์ ์ฌ์ฉ์ id๊ฐ ํ์ฌ vue์ธ MainView.vue์์ CustomerRight.vue๋ก ๋์ด๊ฐ๋ค. ์ฌ์ฉ์ id๋ฅผ ๋ณด์ฌ์ค ๊ณณ์ MainView๊ฐ ์๋ CustomerRight์ด๊ธฐ ๋๋ฌธ์ ๊ทธ๋ ๋ค. ๊ทธ ๋ค์ ์ฝ๋๋ฅผ ์ดํด๋ณด์. CustomerRight์์ ๋ก๊ทธ์์์ ํด๋ฆญํ๋ ๋์์ด ์ํ๋๋ฉด, ๊ทธ ์ฌ์ค์ MainView๊ฐ ์๋๋ก ์ค์ ํ๋ค. ๊ทธ๋์ @logged-out์ ํตํด MainView๋ ๋ก๊ทธ์์์ ์ํํ๋์ง ์ํ๋์ง ์๊ฒ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ฌ์ฉ์๊ฐ ๋ก๊ทธ์์์ ๋๋ฅด๋ฉด loggedOut์ด๋ ๋ฉ์๋๊ฐ ์คํ๋๋ฉฐ ๋ก๊ทธ์์์ด ์ฒ๋ฆฌ๋๋ค.
+) ์ดํด๋ณด๋ฉด display-name์ด๋ผ๊ณ ๋์ด์๋ ๋ถ๋ถ์ด ์์๋ค. HTML์ ๋์๋ฌธ์ ๊ตฌ๋ณ์ ํ์ง ์๋๋ค. ๊ทธ๋ฐ๋ฐ props(์์ ์ปดํฌ๋ํธ๊ฐ ํ์ ์ปดํฌ๋ํธ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ๋ ๊ฒ)๋ ๋์๋ฌธ์๋ฅผ ๊ตฌ๋ณํ๋ค. ์ฝ๊ฒ ์ค๋ช ํ๋ฉด HTML๊ณผ props๋ ์๋ก ์ด๋ฆ์ ์ ํ๋ ๊ท์น์ด ๋ค๋ฅธ ๊ฒ์ด๋ค. ๊ทธ๋์ HTML์ displayName์ด๋ผ๊ณ ์ ์ผ๋ฉด ๋ด๋ถ์์ displayname์ผ๋ก ๋์๊ฐ์ props์ ์ด๋ฆ๊ณผ ์๋์ผ๋ก ๋งคํ์ ๋ชปํ ์ ์๋ค. ๊ทธ๋์ HTML์ ์ ์ ๋ kebab-case๋ก ์ ๊ณ props๋ camelCase๋ก ์ ๋๊ฒ ์ข๋ค.
Q. HTML์์๋ props์์๋ displayname์ด๋ผ๊ณ ํ๋ฉด?
A. ์ ๋์๊ฐ๋ค. ํ์ฌ ์ฝ๋์์ ๋ฌธ์ ๋๋ ๊ฑด ์๋๋ฐ, Vue๊ฐ ๊ถ์ฅํ๋ ํ์์ด ์๋๋ค. ์๋ง ๊ถ์ฅ ํ์๋๋ก ์ฌ์ฉํ์๋ ๋ถ๊ณผ ํ์ ์ ํ๊ฒ๋๋ค๋ฉด ์ค๋ฅ๊ฐ ๋ฐ์ํ ๊ฒ์ด๋, ๋น์ฅ์ ์ฐ์ง ์๋๋ผ๋ ํด๋น ๋ด์ฉ์ ์ผ๋จ ์์๋๋ฉด ์ข์ ๊ฒ ๊ฐ๋ค. ๊ทธ๋ฆฌ๊ณ Extraneous non-props attributes... ์ด๋ฐ ์๋ฌ๊ฐ ๋ฐ์ํ๋ค๋ฉด ์๋ก ๋งคํ์ด ์ ๋๋ก ๋๋์ง ํ์ธํด๋ณด์.
5. CustomerRight.vue
<script> ์ฝ๋
props: {
open: {
type: Boolean,
required: true,
},
displayName: {
type: String,
default: '',
}
},
๋ถ๋ชจ ์ปดํฌ๋ํธ์๋ MainView.vue๊ฐ ๋ณด๋ธ ์ ๋ณด๋ฅผ props์์ ๋ฐ๋๋ค. ํจ๋์ด ์ด๋ ธ๋์ง ์๋์ง์ ๋ํ ๊ฒ์ด open. ์ฌ์ฉ์ id๋ฅผ ๊ฐ์ ธ์ค๋ ๊ณณ์ด displayName์ด ๋๋ค. ์๊น ์ค๋ช ํด์ HTML์ ์ด๋ฆ ํ์๊ณผ props์ ์ด๋ฆ ํ์์ ๋ํด ๋งํ๋๋ฐ, props๊ฐ ์ด ๋ถ๋ถ์ด ๋๊ฒ ๋ค. ํ์ ์ String์ด๊ณ ๋ถ๋ชจ์๊ฒ์ ๋ฐ์์จ ๊ฒ์ด ์๋ค๋ฉด ๊ธฐ๋ณธ๊ฐ์ ๋น ๋ฌธ์์ด๋ก ํ๋ค.
<script> ์ฝ๋
computed: {
// ์ด๋ฆ์ ๋ณด์ฌ์ค๋ค.
nameToShow() {
return this.displayName;
}
},
computed๋ ๊ฐ์ด ๋ฐ๋๋ฉด ์๋์ผ๋ก ์ฌ๊ณ์ฐํด์ ํ ํ๋ ์ด ์ฆ์ ๋ณ๊ฒฝ๋๋๋ก ํด์ค๋ค. ์ด๋ฆ์ด ๋ฐ๋๋ฉด ์๋ก ์ฐ์ฐ์ ํด์ผํ๋ computed์ ์จ๋ดค๋ค. nameToShow๋ props๋ก ๋ฐ์์จ displayName์ ๋ณด์ฌ์ค๋ค.
<script> ์ฝ๋
methods: {
// ๋ถ๋ชจ์๊ฒ ๋ก๊ทธ์์ ์๋ฆฌ๊ธฐ
logout() {
this.$emit('logged-out');
}
<template> ์ฝ๋
<p class="logout" @click="logout">logout</p>
props๋ ๋ถ๋ชจ ์ปดํฌ๋ํธ์์ ์์ ์ปดํฌ๋ํธ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ผ ๋ ์ฌ์ฉํ๋ค. ๊ทธ๋ ๋ค๋ฉด emit๋? ์์ ์ปดํฌ๋ํธ๊ฐ ๋ถ๋ชจ ์ปดํฌ๋ํธ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ผ ๋ ์ฌ์ฉํ๋ค. ์๊น MainView์์ ๋ก๊ทธ์์์ ์ฒ๋ฆฌํ๋ ๋ก์ง์ ๋ง๋ค์๋ค.
// ๋ก๊ทธ์์ ํ๋๊ฑฐ. loggedOut() { localStorage.removeItem('displayName'); // ์ ์ฅ์ ๋น์ฐ๊ธฐ this.displayName = null; // null๋ก ๋ง๋ค์ด์ ์ค๋ฅธ์ชฝ ์ฌ์ด๋๋ฐ ๋ฐ๊พธ๊ณ this.$router.replace('/main'); // main ํ๋ฉด },โ
logout ํ ์คํธ๋ฅผ ๋๋ฅด๋ฉด logout์ด๋ ๋ฉ์๋๊ฐ ์คํ๋๊ณ , logout ๋ฉ์๋๋ $emit์ ํตํด ๋ถ๋ชจ ์ปดํฌ๋ํธ์๊ฒ ๋ก๊ทธ์์์ ์ฒ๋ฆฌํ๋๋ก ์๊ตฌํ๋ค.