๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ’ป ํ”„๋กœ์ ํŠธ/๐Ÿ ํšŒ์›๊ฐ€์ž… ํŽ˜์ด์ง€๐Ÿ 

[SpringBoot] (IntelliJ, vue.js, H2) ํšŒ์›๊ฐ€์ž… ํŽ˜์ด์ง€ ๋งŒ๋“ค๊ธฐ 2ํŽธ : ์•„์ด๋””, ์ด๋ฉ”์ผ ์ค‘๋ณต์ฒดํฌ ๋งŒ๋“ค๊ธฐ.

by ._.sori 2025. 8. 17.

 

 

์ด๋ฆ„, ๋น„๋ฐ€๋ฒˆํ˜ธ, ์ „ํ™”๋ฒˆํ˜ธ๋ฅผ
ํŒจํ„ด ์ฒดํฌ๋ฅผ ํ–ˆ์—ˆ๋‹ค.
์ด๋ฒˆ์—๋Š” ์•„์ด๋””์™€ ์ด๋ฉ”์ผ์„
์ค‘๋ณต ์ฒดํฌ ํ•ด๋ณด์ž!

 

 

 

 

 

[ ํšŒ์›๊ฐ€์ž… ํŽ˜์ด์ง€ ๋งŒ๋“ค๊ธฐ 1ํŽธ : ์ด๋ฆ„, ํŒจ์Šค์›Œ๋“œ, ์ „ํ™”๋ฒˆํ˜ธ ํŒจํ„ด ์ฒดํฌ ]

์ด๊ณณ์— ๋“ค์–ด๊ฐ€์‹œ๋ฉด ํŽ˜์ด์ง€ ๋™์ž‘ ํ™”๋ฉด์ด ์žˆ๊ณ , ๊นƒํ—ˆ๋ธŒ ๋งํฌ๋ฅผ ํ†ตํ•ด ์ „์ฒด ์ฝ”๋“œ๋ฅผ ํ™•์ธํ•˜์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

 

[SpringBoot] (IntelliJ, vue.js, H2) ํšŒ์›๊ฐ€์ž… ํŽ˜์ด์ง€ ๋งŒ๋“ค๊ธฐ 1ํŽธ : dto ๋งŒ๋“ค๊ณ , ์ž…๋ ฅ๊ฐ’ ํŒจํ„ด์„ค์ •ํ•˜๊ธฐ.

๋Œ€๋ถ€๋ถ„์˜ ์›น์‚ฌ์ดํŠธ๋Š”ํšŒ์›๊ฐ€์ž…๊ณผ ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ์„ ๊ฐ€์ง„๋‹ค.๊ทธ ์ค‘ ํšŒ์›๊ฐ€์ž… ๊ธฐ๋Šฅ์„ ๋งŒ๋“ค์–ด๋ณด์ž! 1. ํ™”๋ฉด ๋™์ž‘๊ณผ ์ „์ฒด์ฝ”๋“œํšŒ์›๊ฐ€์ž… ์˜์ƒ ํšŒ์›๊ฐ€์ž… ์ค‘๋ณต ๋””๋ ‰ํ† ๋ฆฌ์™€ ํด๋ž˜์Šค Vue์™€ Spring์„ ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” dto

post-this.tistory.com

 

 


 

 

 

 

1.  ์–ด๋–ป๊ฒŒ ๋งŒ๋“ค์ง€ ๊ตฌ์ƒ

  • ์ฒ˜์Œ์— ์ƒ๊ฐํ•œ ํ™”๋ฉด

 

 

 

 

  • ์‹ค์ œ๋กœ ๋งŒ๋“  ํ™”๋ฉด

 

  • ๋งŒ๋“ค ๋ฐฉ๋ฒ•
๋งจ ์ฒ˜์Œ์—๋Š” ์•„๋ž˜ ์บก์ณ๋ณธ์ฒ˜๋Ÿผ ๊ตฌ์ƒํ•˜๊ธด ํ–ˆ๋Š”๋ฐ, ๋งŒ๋“ค๋ฉด์„œ ์ˆ˜์ •๋œ ๋ถ€๋ถ„์ด ๋งŽ๋‹ค. (์‚ฌ์‹ค ๋งŒ๋“ ์ง€ ์ข€ ๋ผ์„œ ์ž˜ ๊ธฐ์–ต์ด ์•ˆ๋‚œ๋‹ค...) ์•„๋ฌดํŠผ! ์ฝ”๋“œ ์ข€ ์ฐพ์•„๋ณด๋‹ค๊ฐ€ ๋Œ€์ถฉ ์–ด๋–ป๊ฒŒ ๋งŒ๋“œ๋Š”์ง€ ๊ตฌ์กฐ ํŒŒ์•…ํ•˜๊ณ  ๊ทธ๋ƒฅ ์ง์ ‘ ํ•˜๋‚˜ํ•˜๋‚˜ ์ฝ”๋“œ๋ฅผ ์น˜๊ธฐ๋กœ ๊ฒฐ์‹ฌํ–ˆ๋‹ค.(๋Œ€ํ•™์ƒ๋•Œ๋ถ€ํ„ฐ ํ”„๋กœ์ ํŠธ ํ•ด๋ณด๋ฉด์„œ ๊นจ๋‹ฌ์€ ๊ฒฐ๊ณผ๋Š” ๋‚ด๊ฐ€ ์ง์ ‘ ๊ณต๋ถ€ํ•ด์„œ ์ฝ”๋“œ ์น˜๋Š”๊ฒŒ ๋น ๋ฅด๋‹ค๋Š” ๊ฒƒ์ด๋‹ค) ์–ด๋””์„œ ๋ณต๋ถ™ํ•  ์ƒ๊ฐ์ด์—ˆ๋Š”๋ฐ, ์—ญ์‹œ ๋‚ ๋กœ ๋จน๊ธฐ ์‰ฝ์ง€ ์•Š๋‹ค. 

userId๊ฐ€ ๋ฐฑ์—”๋“œ๋กœ ๋„˜์–ด๊ฐ€๋ฉด ๊ฑฐ๊ธฐ์„œ ์ค‘๋ณต ์ฒดํฌ๋ฅผ ๊ฒ€์‚ฌํ•  ๊ฒƒ์ด๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์ค‘๋ณต ์ฒดํฌ๋ฅผ ๊ฒ€์‚ฌํ–ˆ๋Š”์ง€ ์•ˆํ–ˆ๋Š”์ง€๋ฅผ idDuplicate์™€ emailDuplicate์˜ boolean ๊ฐ’์„ ํ†ตํ•ด ํ™•์ธํ•  ๊ฒƒ์ด๋‹ค. ์•„๋ž˜ ์บก์ณ๋ณธ์—์„œ๋Š” ๊ธฐ๋ณธ๊ฐ’์„ false๋กœ ์„ค์ •ํ–ˆ๋Š”๋ฐ, ์‹ค์ œ ์ฝ”๋“œ๋Š” true๋ฅผ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์คฌ๋‹ค.

์ค‘๋ณต ์ฒดํฌ์— ๋ฌธ์ œ๊ฐ€ ์—†์—ˆ์œผ๋ฉด vue์—์„œ false ๊ฐ’์œผ๋กœ ๋ฐ”๊ฟ”์ค„ ๊ฒƒ์ด๊ณ , ์ค‘๋ณต ์ฒดํฌ์— ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ์œผ๋ฉด ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅํ•  ๊ฒƒ์ด๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์ฒ˜์Œ ๊ตฌ์ƒํ•  ๋• ์ƒ๊ฐ์„ ๋ชปํ–ˆ๋Š”๋ฐ, ์•„์ด๋””์™€ ์ด๋ฉ”์ผ์„ ์ค‘๋ณต ์ฒดํฌ๋ฅผ ํ•ด๋‘” ๋’ค ์•„์ด๋””์™€ ์ด๋ฉ”์ผ์„ ์ˆ˜์ •ํ•˜๊ฒŒ๋˜๋ฉด ์ด๋ฏธ idDuplicate์™€ emailDuplicate๊ฐ€ false๊ฐ’์œผ๋กœ ๋ฐ”๋€Œ์–ด์„œ ๊ฐ€์ž…์ด ์„ฑ๊ณตํ•œ๋‹ค. ์ด ๋ถ€๋ถ„๋„ ํ•จ๊ป˜ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ๋‹ค.

 

ํ˜ผ์ž ์ด๋ ‡๊ฒŒ ๊ตฌ์ƒํ•ด๋ณด๋Š” ํŽธ, ๋งŒ๋“ค๋ฉด์„œ ์ˆ˜์ •ํ•จ

 

 


- ์ฐธ๊ณ 

 

SpringBoot+Vue.js - ํšŒ์›๊ฐ€์ž…

ํšŒ์›๊ฐ€์ž… ๊ตฌํ˜„ - ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์œ„ํ•ด ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณตํ•ด์ฃผ๋Š” :rules๋ฅผ ํ†ตํ•ด ๊ตฌํ˜„ - ์•„์ด๋”” ์ค‘๋ณต๊ฒ€์‚ฌ, ๋‹‰๋„ค์ž„ ์ค‘๋ณต ๊ฒ€์‚ฌ ์ถ”๊ฐ€ 1. ๋ฐฑ์—”๋“œ MemberController @RestController @RequiredArgsConstructor public class MemberCont

bsy-96.tistory.com

 

 

 

 


 

 

 

 

 

2.  ํ™•์ธํ•ด์•ผํ•  ๊ฒƒ

  ์ด๋ฆ„ ์•„์ด๋”” ๋น„๋ฐ€๋ฒˆํ˜ธ
1 ํ•œ๊ธ€๋งŒ ๊ฐ€๋Šฅ ์•ž๊ธ€์ž๋Š” ๋ฌด์กฐ๊ฑด ์˜์–ด ๋Œ€๋ฌธ์ž, ํŠน์ˆ˜๋ฌธ์ž ์‚ฌ์šฉํ•˜์—ฌ 8์ž ์ด์ƒ
2 2์ž์ด์ƒ 5์ž ์ดํ•˜ ์˜์–ด์™€ ์ˆซ์ž๊ฐ€ ํ•จ๊ป˜ ๋น„๋ฐ€๋ฒˆํ˜ธ์™€ ๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ์ด ๋‹ค๋ฅด๋ฉด
๊ฐ€์ž… ๋ถˆํ—ˆ
3 ์ •๋ณด ๋ฏธ๊ธฐ์ž…์‹œ ๊ฐ€์ž… ๋ถˆํ—ˆ ์ค‘๋ณต์ฒดํฌ ์ •๋ณด ๋ฏธ๊ธฐ์ž…์‹œ ๊ฐ€์ž… ๋ถˆํ—ˆ
4   ์•„์ด๋”” ๋ฏธ์ž…๋ ฅ์‹œ, ์ค‘๋ณต์ฒดํฌ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด
'์•„์ด๋””๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.' ๋ฉ˜ํŠธ ์ถœ๋ ฅ
 
5   ์•„์ด๋”” ์ˆ˜์ • ํ›„, ์ค‘๋ณต์ฒดํฌ ๋‹ค์‹œ ๋ˆŒ๋Ÿฌ์•ผํ•จ  
6   ์ •๋ณด ๋ฏธ๊ธฐ์ž…์‹œ ๊ฐ€์ž… ๋ถˆํ—ˆ  
7   ์ค‘๋ณต์ฒดํฌ ์•ˆํ•˜๋ฉด ๊ฐ€์ž… ๋ถˆํ—ˆ  

 

 

  ์ „ํ™”๋ฒˆํ˜ธ ์ด๋ฉ”์ผ
1 ํ•œ๊ตญ ์ „ํ™”๋ฒˆํ˜ธ ํ‘œ์ค€์— ๋งž์ถฐ ๊ธฐ์ž… ์ด๋ฉ”์ผ ํ‘œ์ค€์— ๋งž์ถฐ ๊ธฐ์ž…
2 ์ •๋ณด ๋ฏธ๊ธฐ์ž…์‹œ ๊ฐ€์ž… ๋ถˆํ—ˆ ์ด๋ฉ”์ผ ๋ฏธ์ž…๋ ฅ์‹œ, ์ค‘๋ณต์ฒดํฌ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด '์•„์ด๋”” ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.' ๋ฉ˜ํŠธ ์ถœ๋ ฅ
3   ์ด๋ฉ”์ผ ์ˆ˜์ • ํ›„, ์ค‘๋ณต์ฒดํฌ ๋‹ค์‹œ ๋ˆŒ๋Ÿฌ์•ผํ•จ
4   ์ •๋ณด ๋ฏธ๊ธฐ์ž…์‹œ ๊ฐ€์ž… ๋ถˆํ—ˆ
5   ์ค‘๋ณต์ฒดํฌ ์•ˆํ•˜๋ฉด ๊ฐ€์ž… ๋ถˆํ—ˆ

 

 

 

 


 

 

 

3. vue ์ฝ”๋“œ

<script>

import axios from "axios";

export default {
  name: 'BasicRegister',
  
/* ๋ฐ์ดํ„ฐ ์ •์˜ */
  data() {
    return {
      name: "",
      userId: "",
      pwd: "",
      pwdConfirm: "",
      tel: "",
      birth: "",
      email: "",
      /* ์ค‘๋ณต ์ฒดํฌํ•˜๋Š” ๋ฐ์ดํ„ฐ์˜ ๊ธฐ๋ณธ ๊ฐ’์€ true๋กœ ์„ค์ •ํ•จ */
      idDuplicate: true,
      emailDuplicate: true,
    };
  },

  /* ๋ณ€๊ฒฝ๋œ ๋ฐ์ดํ„ฐ๋Š” ๋‹ค์‹œ ์ค‘๋ณต ์ฒดํฌ๋ฅผ ํ•˜๋„๋ก true๋กœ ๋ณ€๊ฒฝ */
  watch: {
    userId(newVal, oldVal) {
      this.idDuplicate = true;
    },
    email(newVal, oldVal) {
      this.emailDuplicate = true;
    }
  },

  methods: {
    /* ํšŒ์›๊ฐ€์ž… */
    async register() {
      try {
       /* ์•„์ด๋””์™€ ์ด๋ฉ”์ผ ๊ฐ’์ด true์ด๋ฉด ์•„์ง ์ค‘๋ณต ์ฒดํฌ๊ฐ€ ๋˜์ง€ ์•Š์•˜์Œ */
       if(this.idDuplicate === true) {
          alert("์•„์ด๋”” ์ค‘๋ณต์ฒดํฌ๋ฅผ ํ•ด์ฃผ์„ธ์š”.")
          return;
        }

        if(this.emailDuplicate === true) {
          alert("์ด๋ฉ”์ผ ์ค‘๋ณต์ฒดํฌ๋ฅผ ํ•ด์ฃผ์„ธ์š”.")
          return;
        }
        /* ํ•ด๋‹น ๊ฒฝ๋กœ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด๊ณ  ์„ฑ๊ณต์‹œ ์•Œ๋ฆผ์ด ๊ฐ€๋„๋ก */
        const res = await axios.post("http://localhost:8080/api/register", {
          name: this.name,
          userId: this.userId,
          pwd: this.pwd,
          pwdConfirm: this.pwdConfirm,
          tel: this.tel,
          birth: this.birth,
          email: this.email,
        });
        alert("ํšŒ์›๊ฐ€์ž…์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.");
        this.$router.push({
          path: "/completeView",
          query: { userId: this.userId }
      })
      } catch (e) { /* ์‹คํŒจ์‹œ ๊ทธ์— ๋งž๋Š” ๋ฉ”์‹œ์ง€๊ฐ€ ์ถœ๋ ฅ */
        alert(e.response.data);
      }
    },
    /* id ์ค‘๋ณต ์ฒดํฌ */
    async checkIdDuplicate() {
      console.log("idDuplicate ๋ฒ„ํŠผ ํด๋ฆญ๋จ:", this.userId);
      try{  /* ํ•ด๋‹น ๊ฒฝ๋กœ์— userId ๋ฐ์ดํ„ฐ ๊ฐ’์ด ๊ฐ™์ด ๊ฐ */
        const res = await axios.post("http://localhost:8080/api/idDuplicate", {
          userId: this.userId
        });
        /* ์„ฑ๊ณต์ด๋ฉด idDuplicate ๊ฐ’์„ false๋กœ ๋ฐ”๊ฟˆ */
        alert("์‚ฌ์šฉ๊ฐ€๋Šฅํ•œ ์•„์ด๋””์ž…๋‹ˆ๋‹ค.");
        this.idDuplicate = false;
      } catch(e) { /* ์‹คํŒจ๋ฉด ์—ฌ์ „ํžˆ idDuplicate ๊ฐ’์€ true */
        alert(e.response.data);
        this.idDuplicate = true;
      }
    },
    /* ์ด๋ฉ”์ผ ์ค‘๋ณต ์ฒดํฌ */
    async checkEmailDuplicate() {
      try { /* ๊ฒฝ๋กœ์— email ๋ฐ์ดํ„ฐ๊ฐ€ ๊ฐ */
        const res = await axios.post("http://localhost:8080/api/emailDuplicate",{
          email: this.email
        }); /* ์„ฑ๊ณตํ•˜๋ฉด emailDuplicate ๊ฐ’์€ false๋กœ ๋ฐ”๋€œ */
        alert("์‚ฌ์šฉ๊ฐ€๋Šฅํ•œ ์ด๋ฉ”์ผ์ž…๋‹ˆ๋‹ค.");
        this.emailDuplicate = false;
      } catch (e) { /* ์‹คํŒจํ•˜๋ฉด ์—ฌ์ „ํžˆ true */
        alert(e.response.data);
        this.emailDuplicate = true;
      }
    }
  }
}
</script>
<template> ์ฝ”๋“œ

/* ํด๋ฆญํ•˜๋ฉด check~Duplicate ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋œ๋‹ค */

<label>เท† id:  </label>
<input v-model="userId" type="text" name="userId" placeholder="id"/>
<button class="id-duplicate-btn" @click="checkIdDuplicate"> id </button>

<label>เท† email:   </label>
<input v-model="email"  type="email" name="email" placeholder="example01@sori.com"/>
<button class="email-duplicate-btn" @click="checkEmailDuplicate"> email </button>

 

 

 


 

 

 

 

4.  IdDuplicate.class, EmailDuplicate.class (dto)

@Getter
@Setter
public class IdDuplicate {
    private String userId;
}
@Getter
@Setter
public class EmailDuplicate {
    private String email;
}
์•„์ด๋””์™€ ์ด๋ฉ”์ผ ์ค‘๋ณต์ฒดํฌ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด, ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜จ๋‹ค. ๋ฌผ๋ก  ์•„์ง์€ ํ‰๋ฒ”ํ•œ ํด๋ž˜์Šค์ง€๋งŒ, ์ค‘๋ณต์ฒดํฌ๋ฅผ ๋‹ด๋‹นํ•˜๋Š” ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ํ•ด๋‹น ํด๋ž˜์Šค๋ฅผ dto ํด๋ž˜์Šค๋กœ ์„ค์ •ํ•ด ์ค„ ๊ฒƒ์ด๋‹ค.

 

 

 

 


 

 

 

 

5. MemberRepository.interface

public interface MemberRepository extends JpaRepository<Member, Long> {
    boolean existsByUserId(String userId);
    boolean existsByEmail (String email);
}
MemberRepository๋Š” DB์— ์ง์ ‘ ์ ‘๊ทผํ•˜๋Š” ๊ณ„์ธต์ด๋‹ค. ์—ฌ๊ธฐ์„œ existsByUserId์™€ existByEmail์€ ์ž๋™์œผ๋กœ SQL์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. ์ด๋•Œ ์ค‘์š”ํ•œ ์ ์€ ๋ฉ”์„œ๋“œ ์ด๋ฆ„์„ ์ง€์„ ๋•Œ ๊ทœ์น™์„ ๊ผญ ์ง€์ผœ์•ผํ•œ๋‹ค. [existBy+ํ•„๋“œ๋ช…]์œผ๋กœ ์ง€์–ด์•ผ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค. (ํ•„๋“œ๋ช…์€ Member์— ์žˆ๋Š” ์ด๋ฆ„๋Œ€๋กœ ์ ์–ด์•ผ ํ•œ๋‹ค.)

 

 

 

 


 

 

 

 

6. MemberService.class

@Service
public class MemberService {

    // ๋ ˆํฌ์ง€ํ† ๋ฆฌ์™€ ์ปจํŠธ๋กค๋Ÿฌ์˜ ์ค‘๊ฐ„ ์—ญํ• ์ด๋ผ ์˜์กด์„ฑ ์ฃผ์ž…!
    @Autowired
    private MemberRepository memberRepository;
    
    // ํŒจ์Šค์›Œ๋“œ ์•”ํ˜ธํ™”
    @Autowired
    private PasswordEncoder passwordEncoder;

    // ๋ ˆํฌ์ง€ํ† ๋ฆฌ์—์„œ userId ์ค‘๋ณต ๊ฒ€์‚ฌํ•  ๋ฉ”์„œ๋“œ
    public Boolean existByUserId (String userId) {
        return memberRepository.existsByUserId(userId);
    }

    // ๋ ˆํฌ์ง€ํ† ๋ฆฌ์—์„œ email ์ค‘๋ณต ๊ฒ€์‚ฌํ•  ๋ฉ”์„œ๋“œ
    public Boolean existByEmail (String email) {
        return memberRepository.existsByEmail(email);
    }

   // ํŒจ์Šค์›Œ๋“œ ๋ ˆํฌ์ง€ํ† ๋ฆฌ์— ์ €์žฅํ•  ๋•Œ ์•”ํ˜ธํ™” ์‹œํ‚จ ํ›„ ๋„ฃ๋Š” ๋ฉ”์„œ๋“œ
    public Member save(Member member) {
        member.setPwd(passwordEncoder.encode(member.getPwd()));
        return memberRepository.save(member);
    }
}
MemberService๋Š” ์ปจํŠธ๋กค๋Ÿฌ์™€ ๋ ˆํฌ์ง€ํ† ๋ฆฌ ์‚ฌ์ด์—์„œ ์ค‘๊ฐ„ ์—ญํ• ์„ ํ•œ๋‹ค. ์—ฌ๊ธฐ์„œ existByUserId์™€ existByEmail์€ ์•„๊นŒ MemberRepository์—์„œ ์„ค์ •ํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ๊ทธ๋Œ€๋กœ ๊ฐ€์ ธ์˜ค๋Š” ์—ญํ• ์„ ํ•˜๊ณ  ์žˆ๋‹ค.

์ฒ˜์Œ์—๋Š” MemberServie๋ฅผ ๊ฑด๋„ˆ๋›ฐ๊ณ  ๋ฐ”๋กœ ๋ ˆํฌ์ง€ํ† ๋ฆฌ์—์„œ ์„ค์ •ํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ ธ์™€ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ–ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ด๋ ‡๊ฒŒ ๋ ˆํฌ์ง€ํ† ๋ฆฌ์—์„œ ๊ฐ€์ ธ์™€ ๋ฐ”๋กœ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด, existByUserId์™€ existByEmail์— ๋‹ค๋ฅธ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๊ธฐ ์–ด๋ ค์›Œ์งˆ ์ˆ˜ ์žˆ๋‹ค. ์ง€๊ธˆ์€ ์‹ค์ œ๋กœ ์„œ๋ฒ„๋ฅผ ์—ด๊ฒŒ ์•„๋‹ˆ๋‹ˆ๊นŒ ์บ์‹œ์ฒ˜๋ฆฌ ๋“ฑ ๋‹ค๋ฅธ ๋ถ€๊ฐ€์ ์ธ ๊ธฐ๋Šฅ์ด ์—†์–ด์„œ MemberService์— ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•œ ๊ฒŒ ์˜๋ฏธ ์—†์–ด ๋ณด์ด์ง€๋งŒ, ํ›„์— ํ™•์žฅ์„ฑ์„ ๊ณ ๋ คํ•˜๋ฉด MemberService๋ฅผ ํ†ตํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค๊ณ  ํ•œ๋‹ค.

 

 

 

 


 

 

 

 

7. CheckId.class, CheckEmail.class

public class CheckId {

    private static final String ID_PATTERN = "^(?=.*\\d)[A-Za-z][A-Za-z0-9]{3,19}$";

    private static final Pattern pattern = Pattern.compile(ID_PATTERN);

    public static String checkId(String userId) {

        if(userId == null || userId.isBlank()) {
            return "์•„์ด๋””๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.";
        }
        if (!pattern.matcher(userId).matches()) {
            return "์•„์ด๋””์˜ ์ฒซ๊ธ€์ž๋Š” ์˜์–ด์ด๋ฉฐ, ์˜์–ด์™€ ์ˆซ์ž๋ฅผ ์„ž์–ด 4์ž๋ฆฌ ์ด์ƒ 20์ž๋ฆฌ ์ดํ•˜๋งŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.";
        }

        return "ok";
    }
}
public class CheckEmail {

    private static final String EMAIL_PATTERN =
            "^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])+[.][a-zA-Z]{2,3}$";

    private static final Pattern pattern = Pattern.compile(EMAIL_PATTERN);

    public static String checkEmail(String email) {
        if(email == null || email.isBlank()) {
            return "์ด๋ฉ”์ผ์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.";
        }
        if (!pattern.matcher(email).matches()) {
            return "์ด๋ฉ”์ผ ์–‘์‹์„ ํ™•์ธํ•ด์ฃผ์„ธ์š”.";
        }

        return "ok";
    }
}
์•„์ด๋””์™€ ์ด๋ฉ”์ผ ํŒจํ„ด ์ฒดํฌ๋ฅผ ํ•ด์คฌ๋‹ค. ์•„์ด๋””๋Š” ๋งจ ์ฒซ๊ธ€์ž์— ์ˆซ์ž๊ฐ€ ์˜ฌ ์ˆ˜ ์—†๊ณ , ์ „์ฒด์ ์œผ๋กœ๋Š” ์˜์–ด์™€ ์ˆซ์ž๋งŒ ์˜ฌ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด๋ฉ”์ผ์€ ์šฐ๋ฆฌ๊ฐ€ ์•Œ๊ณ  ์žˆ๋Š” ๊ทธ๋Ÿฐ ์–‘์‹์˜ ํŒจํ„ด์„ ์„ค์ •ํ•ด์คฌ๋‹ค.

id์™€ email ์นธ์— null๊ณผ ๋„์–ด์“ฐ๊ธฐ ๋“ฑ ๊ณต๋ฐฑ์ด ์˜จ ์ฑ„ ์ค‘๋ณต ์ฒดํฌ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์•„์ด๋””์™€ ์ด๋ฉ”์ผ์„ ์ž…๋ ฅํ•ด๋‹ฌ๋ผ๋Š” ๋ฉ”์‹œ์ง€๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค.

 

 

 

 

 


 

 

 

 

8. MemberService.class

@RestController
@RequestMapping("/api")
@CrossOrigin(origins = "http://localhost:5173")
public class DuplicateController {

    // ์˜์กด์„ฑ ์ฃผ์ž…
    // MemberServic์— ์žˆ๋Š” ๋ฉ”์„œ๋“œ ์“ธ๊ฑฐ๋ผ์„œ
    @Autowired
    private MemberService memberService;
    
	// id ํŒจํ„ด ์ฒดํฌ ๋ฐ ์ค‘๋ณต ํ™•์ธ	
    @PostMapping("/idDuplicate")
    public ResponseEntity<String> idDuplicate(@RequestBody IdDuplicate request) {

        // userId๋ฅผ null, isblank, ํŒจํ„ด ๊ฒ€์‚ฌ
        String userId = request.getUserId();
        String checkResult = CheckId.checkId(userId);
        if (!"ok".equals(checkResult)) {
            return ResponseEntity.badRequest().body(checkResult);
        }

        // userId ์ค‘๋ณต ๊ฒ€์‚ฌ
        boolean existUserId = memberService.existByUserId(request.getUserId());
        if (existUserId == true) {
            return ResponseEntity.badRequest().body("id๊ฐ€ ์ค‘๋ณต๋˜์—ˆ์Šต๋‹ˆ๋‹ค.");
        } else {
            return ResponseEntity.ok("ok");
        }
    }
    
    // email ํŒจํ„ด ์ฒดํฌ ๋ฐ ์ค‘๋ณต ํ™•์ธ	
    @PostMapping("/emailDuplicate")
    public ResponseEntity<String> emailDuplicate(@RequestBody EmailDuplicate request) {

        // email null, isBlank, ํŒจํ„ด ๊ฒ€์‚ฌํ•˜๊ธฐ
        String email = request.getEmail();
        String checkResult = CheckEmail.checkEmail(email);
        if (!"ok".equals(checkResult)) {
            return ResponseEntity.badRequest().body(checkResult);
        }

        // email ์ค‘๋ณต ๊ฒ€์‚ฌ
        boolean existEmail = memberService.existByEmail(request.getEmail());
        if (existEmail == true) {
            return ResponseEntity.badRequest().body("email์ด ์ค‘๋ณต๋˜์—ˆ์Šต๋‹ˆ๋‹ค.");
        } else {
            return ResponseEntity.ok("ok");
        }
    }

}
๋ณดํ†ต์€ ์‚ฌ์šฉ์ž๊ฐ€ ์–ด๋–ค ์ •๋ณด๋„ ์ž…๋ ฅํ•˜์ง€ ์•Š์€ ์ƒํƒœ๋ผ๋ฉด, ์•„์ด๋”” ์ค‘๋ณต์„ ์ฒดํฌํ•˜๋Š” ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด์ง€ ์•Š์•˜์„ ๊ฒƒ์ด๋‹ค. ๊ทธ๋ž˜์„œ ์•„์ด๋”” ์ค‘๋ณต ์ฒดํฌ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๊ธฐ ์ „์€ ๋ฌด์กฐ๊ฑด ์•„์ด๋”” ์ค‘๋ณต ์ฒดํฌ๋ฅผ ๋ˆ„๋ฅด๋ผ๋Š” ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๊ฐ€ alert๋˜๋„๋ก ํ–ˆ๋‹ค. ๊ทธ๊ฑธ ๊ฐ€์žฅ ์ฒซ๋ฒˆ์งธ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋กœ ๋œจ๋„๋ก ์„ค๊ณ„ํ–ˆ๋‹ค.(vue์—์„œ ์„ค์ •ํ•จ) ์•„์ด๋””์™€ ์ด๋ฉ”์ผ์ด null, blank ๊ฒ€์‚ฌ๋„ ์ค‘๋ณต ๋ฒ„ํŠผ์—์„œ ์ˆ˜ํ–‰ํ–ˆ๋‹ค. ์™œ๋ƒ๋ฉด ์–ด์ฐจํ”ผ idDuplicate์™€ emailDuplicate ๋ฐ์ดํ„ฐ ๊ฐ’์ด false๋กœ ๋ฐ”๋€Œ์ง€ ์•Š์€ ์ด์ƒ SIGN UP ๋ฒ„ํŠผ์€ ์ค‘๋ณต์„ ๊ฒ€์‚ฌํ•˜๋ผ๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅ์‹œํ‚ฌํ…Œ๋‹ˆ๊นŒ.

 

 

    // ๋งคํ•‘!
    @PostMapping("/idDuplicate")
    public ResponseEntity<String> idDuplicate(@RequestBody IdDuplicate request) {
id ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๊ฒŒ ๋˜๋ฉด, vue์—์„œ const res = await axios.post("http://localhost:8080/api/idDuplicate", { userId: this.userId });๊ฐ€ ์‹คํ–‰๋˜๋„๋ก ์ฝ”๋“œ๋ฅผ ์ ์—ˆ๋‹ค. ์—ฌ๊ธฐ์— ๋ณด๋ฉด ํ•ด๋‹น ์ฃผ์†Œ๊ฐ€ ์œ„์˜ ์ฃผ์†Œ๋กœ ๋งคํ•‘๋˜๋Š”๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. 

๋ณด๋‚ด์ง„ JSON ๋ฐ”๋””๋Š” ์ด๋ ‡๊ฒŒ ์ƒ๊ฒผ์„ ๊ฒƒ์ด๋‹ค.
{
  "userId": "sori1234"
}โ€‹

 

๊ทธ๋Ÿฌ๋ฉด @RequestBody๋Š” HTTP  ์š”์ฒญ ๋ฐ”๋””๋ฅผ ์ž๋ฐ” ๊ฐ์ฒด(DTO)๋กœ ๋ณ€ํ™˜ํ•ด์ค€๋‹ค.  JSON์˜ "userId" : "sori1234" ๊ฐ’์ด IdDuplicate.userId ํ•„๋“œ์— ์ž๋™์œผ๋กœ ๋งคํ•‘๋œ๋‹ค. HttpMessageConverter๋Š” Jackson ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ธ๋ฐ ์ด๊ฒŒ JSON์„ ์ž๋ฐ” ๊ฐ์ฒด๋กœ ๋ฐ”๊ฟ”์ค€๋‹ค.

 

 

        String userId = request.getUserId();
        String checkResult = CheckId.checkId(userId);
        if (!"ok".equals(checkResult)) {
            return ResponseEntity.badRequest().body(checkResult);
        }
๊ทธ๋Ÿฌ๋ฉด ์ž๋™์œผ๋กœ ๋งคํ•‘๋œ userId๋ฅผ ๊ฐ€์ ธ์™”๊ณ ,  userId๋ฅผ CheckId ํด๋ž˜์Šค์˜ checkId ๋ฉ”์„œ๋“œ๋กœ ๋ณด๋‚ธ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด null๊ฐ’์ธ์ง€, isBlank์ธ์ง€, ํŒจํ„ด์€ ๋งž๋Š”์ง€ ๊ฒ€์‚ฌํ•˜๊ณ  ๊ฒฐ๊ณผ ๊ฐ’์„ checkResult์— ๋‹ด์„ ๊ฒƒ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  checkResult ๊ฐ’์ด ok์ด๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด ๊ทธ์— ๋งž๋Š” ๋ฉ”์‹œ์ง€๋ฅผ return ํ•œ๋‹ค.

idDuplicate ๋ฉ”์„œ๋“œ์˜ ๋ฐ˜ํ™˜ํƒ€์ž…์€ ResponseEntity<String>์ธ๋ฐ, ์ด ์ด์œ ๊ฐ€ ์ƒํƒœ ์ฝ”๋“œ์™€ ๋ฉ”์‹œ์ง€๋ฅผ ๊ฐ™์ด ๋ณด๋‚ด๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๋ ‡๊ฒŒ ์„ค์ •ํ–ˆ๋‹ค.

 

 

        boolean existUserId = memberService.existByUserId(request.getUserId());
        if (existUserId == true) {
            return ResponseEntity.badRequest().body("id๊ฐ€ ์ค‘๋ณต๋˜์—ˆ์Šต๋‹ˆ๋‹ค.");
        } else {
            return ResponseEntity.ok("ok");
        }
์ด์ œ ์ค‘๋ณต์„ ํ™•์ธํ•  ๊ฒƒ์ด๋‹ค. ์ค‘๋ณต์„ ์ฒดํฌํ•  ๋•Œ ํ•„์š”ํ•œ ํด๋ž˜์Šค๋Š” MemberService์— ๋ ˆํฌ์ง€ํ† ๋ฆฌ์˜ ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ ธ์™”๋˜ existByUserId์ด๋‹ค. vue์—์„œ ๋ฐ›์•„์˜จ userId๊ฐ€ (DTO ํด๋ž˜์Šค๋กœ ๋ฐ›์•„๋‘”) ๋ ˆํฌ์ง€ํ† ๋ฆฌ์— ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ existByUserId๊ฐ€ ๋œ๋‹ค.

์•„๋งˆ existByUserId์—๋Š” ์ด๋Ÿฐ ์ฝ”๋“œ๊ฐ€ ์ƒ๋žต๋˜์–ด ์žˆ์„ ๊ฒƒ์ด๋‹ค. 
select count(m) > 0
from Member m
where m.userId = :userIdโ€‹
 
๊ฐ™์€ userId๊ฐ€ ์žˆ์œผ๋ฉด true ๊ฐ’์„, ์—†์œผ๋ฉด false ๊ฐ’์„ existUserId๊ฐ€ ๊ฐ€์งˆ ๊ฒƒ์ด๋‹ค. ๊ทธ๋ž˜์„œ if ๋ฌธ์œผ๋กœ true ๊ฐ’์„ ๊ฐ€์ง€๋ฉด id๊ฐ€ ์ค‘๋ณต๋˜์—ˆ๋‹ค๋Š” ๋ฉ”์‹œ์ง€๊ฐ€ ๋ฆฌํ„ด๋˜๊ณ , false ๊ฐ’์ด๋ฉด ok๊ฐ€ ๋ฆฌํ„ด๋˜๋„๋ก ํ–ˆ๋‹ค.  

 

 

 

 


 

 

 

 

9. ๋‹ค์‹œ vue ์ฝ”๋“œ

/* ๋ฐ์ดํ„ฐ ์ •์˜ */
  data() {
    return {
      name: "",
      userId: "",
      pwd: "",
      pwdConfirm: "",
      tel: "",
      birth: "",
      email: "",
      /* ์ค‘๋ณต ์ฒดํฌํ•˜๋Š” ๋ฐ์ดํ„ฐ์˜ ๊ธฐ๋ณธ ๊ฐ’์€ true๋กœ ์„ค์ •ํ•จ */
      idDuplicate: true,
      emailDuplicate: true,
    };
  },
์ฒ˜์Œ์—” idDuplicate์™€ emailDuplicate๊ฐ€ true ๊ฐ’์„ ๊ธฐ๋ณธ ๊ฐ’์œผ๋กœ ๊ฐ€์ง„๋‹ค.

 

 

    /* id ์ค‘๋ณต ์ฒดํฌ */
    async checkIdDuplicate() {
      console.log("idDuplicate ๋ฒ„ํŠผ ํด๋ฆญ๋จ:", this.userId);
      try{  /* ํ•ด๋‹น ๊ฒฝ๋กœ์— userId ๋ฐ์ดํ„ฐ ๊ฐ’์ด ๊ฐ™์ด ๊ฐ */
        const res = await axios.post("http://localhost:8080/api/idDuplicate", {
          userId: this.userId
        });
        /* ์„ฑ๊ณต์ด๋ฉด idDuplicate ๊ฐ’์„ false๋กœ ๋ฐ”๊ฟˆ */
        alert("์‚ฌ์šฉ๊ฐ€๋Šฅํ•œ ์•„์ด๋””์ž…๋‹ˆ๋‹ค.");
        this.idDuplicate = false;
      } catch(e) { /* ์‹คํŒจ๋ฉด ์—ฌ์ „ํžˆ idDuplicate ๊ฐ’์€ true */
        alert(e.response.data);
        this.idDuplicate = true;
      }
    },
vue๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค. try๋Š” ์š”์ฒญ์ด ์„ฑ๊ณตํ–ˆ์„ ๋•Œ, catch๋Š” ์š”์ฒญ์— ์‹คํŒจํ–ˆ์„ ๋•Œ ์ฝ”๋“œ๋ฅผ ์ ์–ด์ฃผ๋ฉด ๋œ๋‹ค.

return ResponseEntity.ok("ok");๋ฅผ ์Šคํ”„๋ง์ด ๋ณด๋‚ด vue์—์„œ ๋ฐ›์œผ๋ฉด 200์ด๋ž€ ์ƒํƒœ์ฝ”๋“œ๋ฅผ ๋ฐ›์•„์„œ ์„ฑ๊ณตํ–ˆ์Œ์„ ์˜๋ฏธํ•œ๋‹ค. alert("์‚ฌ์šฉ๊ฐ€๋Šฅํ•œ ์•„์ด๋””์ž…๋‹ˆ๋‹ค.")๊ฐ€ ์ถœ๋ ฅ๋˜๋ฉด์„œ, this.idDuplicate๋ฅผ false๋กœ ๋ฐ”๊พผ๋‹ค. (์—ฌ๊ธฐ์„œ this.์€ ํ˜„์žฌ ์ด๊ณณ data์— ์ •์˜๋œ ๊ฐ’์„ ๋งํ•œ๋‹ค)


์‹คํŒจํ•˜๊ฒŒ๋˜๋ฉด ์Šคํ”„๋ง์—์„œ ์˜จ ๋ฉ”์‹œ์ง€๊ฐ€ ์ถœ๋ ฅ๋˜๋ฉฐ this.idDuplicate๋ฅผ true๋กœ ๋ฐ”๊พผ๋‹ค. ์‚ฌ์‹ค this.idDuplicate = true๋ฅผ ์•ˆ์ ์–ด๋„ ๋˜๋Š” ๊ฒƒ ๊ฐ™๊ธดํ•œ๋ฐ (๋‚ด ๋จธ๋ฆฟ ์† ์ด๋ก ์ƒ..ใ…Žใ…Ž) ๊ทธ๋ƒฅ ์ ์–ด์คฌ๋‹ค. ํ™•์‹คํžˆ ๋ฐ”๋€Œ์ง€ ์•Š์•˜์Œ์„ ๋‹ค์‹œ ํ•œ ๋ฒˆ ๊ฐ์ธํ•˜๊ธฐ ์œ„ํ•ด,,,

 

 

 

 


 


์ œ๊ฐ€ ์ดํ•ดํ•œ ๊ฑธ ์ตœ๋Œ€ํ•œ ์ž˜ ์ ์–ด๋ณด๋ ค๊ณ  ๋…ธ๋ ฅํ–ˆ์Šต๋‹ˆ๋‹ค.

๋‚ด์šฉ ์ค‘์— ํ‹€๋ฆฐ ๋‚ด์šฉ์ด ์žˆ์œผ๋ฉด ๋Œ“๊ธ€๋กœ ์•Œ๋ ค์ฃผ์„ธ์š” :-)
๋„์›€์ด ๋˜์…จ์œผ๋ฉด ์ข‹๊ฒ ์Šต๋‹ˆ๋‹ค.

 

๐Ÿณ ํ™”์ดํŒ… ๐Ÿณ

'๐Ÿ’ป ํ”„๋กœ์ ํŠธ > ๐Ÿ ํšŒ์›๊ฐ€์ž… ํŽ˜์ด์ง€๐Ÿ ' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[Vue.js] ๋ฒ„ํŠผ ๋กœ์ง์ด ์ œ๋Œ€๋กœ ๋™์ž‘์„ ์•ˆํ•˜๋Š” ๊ฒƒ ๊ฐ™์„ ๋•Œ, chunk-VZXQDS5F.js?v=5f04997f:2125 [Vue warn]: Data property "idDuplicate" is already defined in Methods.  (0) 2025.08.20
[SpringBoot] (IntelliJ, vue.js, H2) ํšŒ์›๊ฐ€์ž… ํŽ˜์ด์ง€ ๋งŒ๋“ค๊ธฐ 3ํŽธ: watch๋กœ ์•„์ด๋””์™€ ์ด๋ฉ”์ผ ๋ณ€๊ฒฝ ์‹œ ๋‹ค์‹œ ์ค‘๋ณต์ฒดํฌํ•˜๊ฒŒ ๋งŒ๋“ค๊ธฐ.  (4) 2025.08.18
[SpringBoot] (IntelliJ, vue.js, H2) ํšŒ์›๊ฐ€์ž… ํŽ˜์ด์ง€ ๋งŒ๋“ค๊ธฐ 1ํŽธ : dto ๋งŒ๋“ค๊ณ  ์ด๋ฆ„, ํŒจ์Šค์›Œ๋“œ, ์ „ํ™”๋ฒˆํ˜ธ ํŒจํ„ด ์ฒดํฌ ๋งŒ๋“ค๊ธฐ.  (9) 2025.08.14
[Spring] (IntelliJ, vue.js) Vue๋ฅผ ์ด์šฉํ•˜์—ฌ! ์•„์ด์ฝ˜์„ ๋ˆ„๋ฅด๋ฉด ํ™”๋ฉด ์Šฌ๋ผ์ด๋”ฉ ๋งŒ๋“ค๊ธฐ.  (6) 2025.08.03
[Spring] (MAC, IntelliJ, vue.js) org.h2.jdbc.JdbcSQLFeatureNotSupportedException: Feature not supported: "CHARACTER VARYING(255)"; ์˜ค๋ฅ˜๋Š” ์™œ ๋œจ๋Š”๊ฑธ๊นŒ?  (2) 2025.07.26