ajax - ajax를 이용해 아이디 중복체크 하는 예제 (2022-10-24)

2022. 10. 25. 00:373층 1구역 - 개발의 장/ajax통신

1. 서론

이번엔 예제2번을 활용하여 회원가입 시 아이디 중복체크를 해보도록하자.

 

2. 본론

수업 들으면서 get방식으로 중복체크를 했는데

필자는 post로 해보고 싶어서 고민했다.

 

근데?

open객체를 사용할 때,

open('post', "doubleCheck") 라고 작성했을 때

post의 doubleCheck를 찾아 열어달라는 뜻이니

@PostMapping을 주고 value값을 doubleCheck로 해주면?

알아서 Controller를 찾아서 서비스에서 검증받고 서비스의 반환값을 doubleCheckmsg라는 녀석에게

줄 거 같았다

 

좋아 당장 해보자.

 

 

이전에 했던 프로젝트를 사용해보도록 하자.

 

DBConfig.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package com.care.db.basic.config;
 
 
 
import java.io.IOException;
 
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
 
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
 
//클래스를 등록해주는데 얘는 설정파일의 용도야
@Configuration
//<mybatis-spring:scan base-package="com.care.db.basic.repository"/>
@MapperScan(basePackages = {"com.care.db.basic.repository"})
public class DBConfig {
    
//    <bean class="com.zaxxer.hikari.HikariConfig" id="hikariConfig">
//    <property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
//    <property name="jdbcUrl" value="jdbc:oracle:thin:@localhost:1521:xe"/>
//    <property name="username" value="oracle"/>
//    <property name="password" value="oracle"/>
//    </bean>    
//    위에꺼 대신에 아래꺼
    @Bean
    public HikariDataSource dataSource() {
        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setDriverClassName("oracle.jdbc.OracleDriver");
        hikariConfig.setJdbcUrl("jdbc:oracle:thin:@localhost:1521:xe");
        hikariConfig.setUsername("oracle");
        hikariConfig.setPassword("oracle");
        
//        <bean class="com.zaxxer.hikari.HikariDataSource" id="dataSource">
//        <constructor-arg ref="hikariConfig"/>
//        </bean>
//        위에꺼 대신에 아래꺼
        HikariDataSource dataSource = new HikariDataSource(hikariConfig);
        return dataSource;
    }
    
//    <bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sessionFactory">
//    <property name="dataSource" ref="dataSource"/>
//    <property name="mapperLocations" value="classpath:/mappers/**/*Mapper.xml" />
//    </bean>
    
    @Bean
    public SqlSessionFactoryBean sessionFactory() throws IOException {
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        PathMatchingResourcePatternResolver resolver = 
                new PathMatchingResourcePatternResolver();
        Resource[] mapper = resolver.getResources("classpath:/mappers/**/*Mapper.xml");
        sessionFactory.setMapperLocations(mapper);
        return sessionFactory;
        
    }
}
cs

config는 이전 예제와 같다.

 

testMapper.xml

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 
<mapper namespace="com.care.db.basic.repository.IMemberDAO">
    
    <insert id="register" parameterType="com.care.db.basic.dto.MemberDTO" >
        INSERT INTO db_basic VALUES(#{id},#{pw},#{name},#{email})
    </insert>
    
    <select id="login" 
            parameterType="String" 
            resultType="com.care.db.basic.dto.MemberDTO">
        SELECT * FROM db_basic WHERE id=#{id}
    </select>
    
    <select id="list" resultType="com.care.db.basic.dto.MemberDTO">
        SELECT * FROM db_basic
    </select>
    
    <update id="update" parameterType="com.care.db.basic.dto.MemberDTO">
        UPDATE db_basic SET pw=#{pw},name=#{name},email=#{email} WHERE id=#{id}
    </update>
    
    <delete id="delete" parameterType="String">
        DELETE FROM db_basic WHERE id=#{id}
    </delete>
    
    <select id="doubleCheck" resultType="Integer">
        SELECT count(id) FROM db_basic WHERE id=#{id}
    </select>
    
</mapper>
cs

 

<select id="doubleCheck" resultType="Integer">
SELECT count(id) FROM db_basic WHERE id=#{id}
</select>

 

이전 예제에서 위 코드만 추가되었다.

 

MemberService.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package com.care.db.basic.service;
 
import java.util.ArrayList;
 
import javax.servlet.http.HttpSession;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
 
import com.care.db.basic.dto.MemberDTO;
import com.care.db.basic.repository.IMemberDAO;
import com.care.db.basic.repository.MemberDAO;
 
@Service
public class MemberService {
    @Autowired
    private HttpSession session;
    @Autowired
    private IMemberDAO dao;
    
//    아이디 중복확인 검증 시작=========================================================
    public String doubleCheck(String id) {
        int conut = dao.doubleCheck(id);
        if(conut == 0) {
            return "사용가능한 아이디";
        }
        return "중복된 아이디";
    }
//    아이디 중복확인 검증 도착=========================================================
 
//    회원가입 검증 시작========================================================
    public String register(MemberDTO dto, String confirmPw) {
        if (dto.getId() == null || dto.getId().isEmpty()) {
            return "필수 정보 입니다.";
        }
 
        if (dto.getPw() == null || dto.getPw().isEmpty()) {
            return "필수 정보 입니다.";
        }
 
        if (dto.getPw().equals(confirmPw) == false) {
            return "입력하신 두 비밀번호가 서로 다릅니다.";
        }
 
        MemberDTO check = dao.login(dto.getId());
        if (check != null) {
            return "다른 아이디로 가입을 시도하세요.";
        }
        //모든 if문에서 걸러지지 않았다면 register에 입력값이 저장되며
        dao.register(dto);
        //"가입 성공!" 이라는 문자열을 반환시켜준다.
        //이 반환값은 Controller에서 service.register라는 녀석이 소유하게 된다.
        return "가입 성공!";
    }
//    회원가입 검증 끝==========================================================
 
//    로그인 검증 시작==========================================================
    public String login(MemberDTO dto) {
        if (dto.getId().isEmpty()) {
            return "필수 정보 입니다.";
        }
 
        MemberDTO check = dao.login(dto.getId());
        if (check == null) {
            return "아이디를 확인 후 다시 시도하세요.";
        }
 
        if (check.getPw().equals(dto.getPw()) == false) {
            return "비밀번호를 확인 후 다시 시도하세요.";
        }
        
        //모든 if문에서 걸러지지 않았다면 아래와 같이 session값이 생성되며
        session.setAttribute("id", check.getId());
        session.setAttribute("pw", check.getPw());
        session.setAttribute("name", check.getName());
        session.setAttribute("email", check.getEmail());
        //"로그인 성공" 이라는 문자열을 반환시켜준다.
        //이 반환값은 Controller에서 service.login이라는 녀석이 소유하게 된다.
        return "로그인 성공";
        }
//    로그인 검증 끝============================================================
 
//    회원목록 검증 시작==========================================================
    public ArrayList<MemberDTO> list() {
        ArrayList<MemberDTO> list = dao.list();
        return list;
    }
//    회원목록 검증 끝============================================================
    
//    회원수정 검증 시작===========================================================
    public String update(MemberDTO dto, String confirmPw) {
        //현재 로그인되어 있는 아이디의 세션값을 sessionId라는 변수에 저장한다.
        String sessionId = (String)session.getAttribute("id");
        //변수가 비어있다면 로그인이 안되어 있는 것이기 때문에 아래와 같은 문자열을 반환
        if(sessionId.isEmpty()) {
            return "로그인 후 이용해주세요.";
        }
        
        //input에 입력한 setter를 dto.getPw로 getter로 가져와 비밀번호확인과 같지 않다면
        //아래와 같은 문자열을 반환
        if(dto.getPw().equals(confirmPw) == false) {
            return "입력하신 비밀번호가 서로 다릅니다.";
        }
        
        //모든 if문에서 걸러지지 않았다면 sessionID를 dto에 setter로 보내지며, 같이 딸려온 정보도 저장한다.
        dto.setId(sessionId);
        //dao가 dto가 가져온 아이디값을 조회하여 아이디값과 같이 딸려온 setter값들을 쿼리문에 맞게
        //회원정보를 수정한다.
        dao.update(dto);
        //그 후 세션정보를 모두 삭제하고, 
        //아래와 같은 문자열을 반환한다.
        session.invalidate();
        return "수정 완료";
    }
//    회원수정 검증 끝=============================================================
    
//    회원삭제 검증 시작============================================================
    public String delete(String pw, String confirmPw) {
        String sessionId = (String)session.getAttribute("id");
        if(sessionId.isEmpty()) {
            return "로그인 후 이용해주세요.";
        }
        if(pw.isEmpty()) {
            return "필수 정보 입니다.";
        }
        
        if(pw.equals(confirmPw) == false) {
            return "입력하신 두 비밀번호를 확인하세요";
        }
        
        MemberDTO result = dao.login(sessionId);
        if(result.getPw().equals(pw) == false)
            return "비밀번호를 확인하세요.";
        
        //모든 if문에서 걸러지지 않았다면 dao가 sessionId와 동일한 아이디값을
        //찾아 delete쿼리문을 실행한다.
        dao.delete(sessionId);
        //삭제하고 세션정보를 모두 지우고
        session.invalidate();
        //아래와 같은 문자열을 반환한다.
        return "삭제 완료";
    }
//    회원삭제 검증 끝==============================================================
 
}
cs

 

//	아이디 중복확인 검증 시작=========================================================
	public String doubleCheck(String id) {
		int conut = dao.doubleCheck(id);
		if(conut == 0) {
			return "사용가능한 아이디";
		}
		return "중복된 아이디";
	}
//	아이디 중복확인 검증 도착=========================================================

이전 예제에서 위 코드만 추가되었다.

 

MemberController.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package com.care.db.basic.controller;
 
 
import javax.servlet.http.HttpSession;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
 
import com.care.db.basic.dto.MemberDTO;
import com.care.db.basic.service.MemberService;
 
@Controller
public class MemberController {
    
    @Autowired private MemberService service;
    
//    아이디 중복확인 시작==================================================================
    @ResponseBody
    @PostMapping(value = "doubleCheck", produces = "text/html; charset=UTF-8")
    public String doubleCheck(@RequestBody String id) {
        System.out.println("아이디" + id);
        return service.doubleCheck(id);
    }
//    아이디 중복확인 도착==================================================================
    
//    인덱스 시작========================================================================
    //시작페이지, get이든 post든 그냥 requestMapping 해달라
    @RequestMapping("index"public void index() {}
//    인덱스 끝==========================================================================
 
//    회원가입 시작=======================================================================
    
    //get맵핑으로 받은 것은 단지 회원가입 폼 페이지를 열기 위해서임.
    @GetMapping("register"public void register() {}
    
    //post맵핑으로 회원가입 폼 페이지에서 입력값을 받고 서비스로 뿌려 검증하고 이상 없는 결과를 받아 클라이언트에게 보여주는 곳
    @PostMapping("register")
    //DTO로 필요한 요소를 불러올 수 있음, 굳이 String변수를 하나하나 선언할 필요가 없어짐.
    public String register(MemberDTO dto, String confirmPw, Model model, RedirectAttributes ra) {
        
        //msg 변수는 service.register에서 반환 받은 문자열을 소유하고 있다.
        String msg = service.register(dto, confirmPw);
        //Model을 사용하여 msg변수를 "msg"라는 이름으로 셋팅
        model.addAttribute("msg", msg);
        //만약에 반환받은 문자열이 "가입 성공!"과 같다면
        if(msg.equals("가입 성공!")) {
        //회원가입이 성공하며 index.jsp를 반환한다.
        //(가입성공과 동시에 DB에 저장되는 과정은 service에서 처리함.)
            return "index";
        }
        //"가입 성공!" 외에 다른 문자열이 올 경우, register.jsp페이지를 반환하게 된다.
        return "register";
    }
//    회원가입 끝========================================================================
    
//    회원목록 시작======================================================================
    
    //시작페이지, get이든 post든 그냥 requestMapping 해달라
    @RequestMapping("list"
    public void list(Model model) {
        //service.list()값을 "lists" 라는 이름으로 Model를 통해 담아준다.
        //담아주는 이유는 list.jsp페이지에서 for문 혹은 <c:forEach>문을 통해 회원정보를 출력해야하기 때문임.
        model.addAttribute("lists", service.list());
    }
//    회원목록 끝========================================================================
    
//    회원수정 시작======================================================================
    
    //get맵핑으로 회원수정 폼 페이지를 열어준다.
    @GetMapping("update"public void update() {}
    
    //post맵핑으로 회원수정 폼 페이지에서 입력값을 받고 서비스로 뿌려 검증하고 이상 없는 결과를 받아 클라이언트에게 보여주는 곳
    @PostMapping("update")
    //DTO로 필요한 요소를 불러올 수 있음, 굳이 String변수를 하나하나 선언할 필요가 없어짐.
    public String update(MemberDTO dto, String confirmPw, Model model) {
    //msg변수는 service.update에서 반환 받은 문자열을 소유하고 있다.
        String msg = service.update(dto, confirmPw);
    //Model을 통해 msg의 값을 "msg"라는 이름에 넣도록 셋팅    
        model.addAttribute("msg", msg);
    //만약에 msg변수의 문자값이 "수정 완료"와 같다면    
        if(msg.equals("수정 완료")) {
    //회원 수정이 완료되며 index.jsp페이지를 반환한다.
    //(수정이 완료되는 동시에 DB에 저장되는 과정은 service에서 처리함.)        
            return "index";
        }
    //그 외에 문자열이 나오면 update.jsp 페이지를 반환한다.    
        return "update";
    }
//    회원수정 끝========================================================================
    
//    회원삭제 시작=======================================================================
    
    //get맵핑으로 회원삭제 폼 페이지를 열어준다.
    @GetMapping("delete"public void delete() {}
    
    
    //post맵핑으로 회원삭제 폼 페이지에서 입력값을 받고 서비스로 뿌려 검증하고 이상 없는 결과를 받아 클라이언트에게 보여주는 곳
    @PostMapping("delete")
    //비밀번호와 비밀번호확인 값을 비교한다.
    public String delete(String pw, String confirmPw, Model model) {
        
        //msg변수는 service.delete에서 반환 받은 문자열을 소유하고 있다.
        
        String msg = service.delete(pw, confirmPw);
        //Model을 통해 msg의 값을 "msg"라는 이름에 넣도록 셋팅        
        model.addAttribute("msg", msg);
        //만약에 msg변수의 문자값이 "삭제 완료"와 같다면    
        if(msg.equals("삭제 완료")) {
            //회원 삭제가 완료되며 index.jsp페이지를 반환한다.    
            //(회원삭제와 동시에 DB에 저장되는 과정은 service에서 처리함.)
            return "index";
        }
        //그 외에 문자열이 나오면 delete.jsp 페이지를 반환한다.    
        return "delete";
    }
//    회원삭제 끝=========================================================================
//    로그인 시작=========================================================================
    
    //get맵핑으로 로그인 폼 페이지를 열어준다.
    @GetMapping("login"public void login() {}
 
    //post맵핑으로 로그인 폼 페이지에서 입력값을 받고 서비스로 뿌려 검증하고 이상 없는 결과를 받아 클라이언트에게 보여주는 곳
    @PostMapping("login")
    public String login(MemberDTO dto, Model model) {
    
        //msg변수는 service.login에서 반환 받은 문자열을 소유하고 있다.
        String msg = service.login(dto);
        //Model을 통해 msg의 값을 "msg"라는 이름에 넣도록 셋팅        
        model.addAttribute("msg", msg);
        //만약에 msg변수의 문자값이 "로그인 성공"와 같다면    
        if(msg.equals("로그인 성공")) {
            //로그인이 완료되며 index.jsp페이지를 반환한다.
            //(로그인 성공과 동시에 DB에서 열람되는 과정은 service에서 처리함.)
            return "index";
        }
        //그 외에 문자열이 나오면 login.jsp 페이지를 반환한다.    
        return "login";
    }
//    로그인 끝===========================================================================
    
//    로그아웃 시작========================================================================
    @RequestMapping("logout")
    public String logout(HttpSession session, Model model) {
        session.invalidate();
        model.addAttribute("msg""로그 아웃");
        return "logout";
    }
//    로그아웃 끝==========================================================================
}
cs

 

//	아이디 중복확인 시작==================================================================
	@ResponseBody
	@PostMapping(value = "doubleCheck", produces = "text/html; charset=UTF-8")
	public String doubleCheck(@RequestBody String id) {
		System.out.println("아이디" + id);
		return service.doubleCheck(id);
	}
//	아이디 중복확인 도착==================================================================

이전 예제에서 위 코드만 추가되었다.

 

MemberDTO.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package com.care.db.basic.dto;
 
/*
  CREATE TABLE db_basic(
  id varchar2(20),
  pw varchar2(20),
  name varchar2(30),
  email varchar2(100),
  PRIMARY KEY(id)
  );
  */
 
public class MemberDTO {
    private String id;
    private String pw;
    private String name;
    private String email;
    
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getPw() {
        return pw;
    }
    public void setPw(String pw) {
        this.pw = pw;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    
}
 
cs

이전 예제이다.

 

IMemberDAO.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.care.db.basic.repository;
 
import java.util.ArrayList;
 
import org.springframework.stereotype.Repository;
 
import com.care.db.basic.dto.MemberDTO;
 
@Repository
public interface IMemberDAO {
//    매개변수는 무엇인지(MemberDTO에 dto나 String id에 id 같은...)
//    반환값은 뭔지(void인지 String인지 int인지)
    public void register(MemberDTO dto);
    public MemberDTO login(String id);
    public ArrayList<MemberDTO> list();
    public void update(MemberDTO dto);
    public void delete(String id);
    
    public int doubleCheck(String id);
}
 
cs

 

public int doubleCheck(String id);

이전 예제에서 위 코드만 추가되었다.

 

register.jsp

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>member</title>
<script>
    var req
    function doubleCheck() {
        req = new XMLHttpRequest();
        req.onreadystatechange = doubleCheckMsg
        req.open('post'"doubleCheck")
        var reqData = document.getElementById('id')
        req.send(reqData.value)
    }
    
    function doubleCheckMsg() {
        if(req.readyState == 4 && req.status == 200){
            var doubleCheckMsg = document.getElementById('doubleCheckMsg')
            doubleCheckMsg.innerHTML = req.responseText
        }
    }
</script>
</head>
<body>
<c:if test="${not empty msg }" >
    <script>alert("${msg}");</script>
</c:if>
 
    <font id="doubleCheckMsg" color="red"></font>
    <form action="register" method="post">
        <input type="text" name="id" id="id" placeholder="아이디">
        <input type="button" value="중복 확인" onclick="doubleCheck()">
        <br>
        <input type="password" name="pw" placeholder="비밀번호"><br>
        <input type="password" name="confirmPw" placeholder="비밀번호 확인"><br>
        <input type="text" name="name" placeholder="이름"><br>
        <input type="text" name="email" placeholder="이메일"><br>
        <input type="submit" value="회원 가입" >
        <input type="button" value="취소" onclick="location.href='index'">
    </form>
</body>
</html>
cs

 

 

대충 이런식으로 진행되지 않을까?

 

그러면 실행시켜보자.

 

일단 에러는 나지 않는다(휴....)

 

 

데이터베이스에 admin이라는 아이디는 없기 때문에 문자열이 잘 출력되는 것을 볼 수 있다.

 

미리 하나 만들어 두었다. test1은 데이터베이스에 존재하기 때문에 중복된 아이디라고 잘 나온다.

 

3. 결론

아이디 중복체크는 예제2번을 활용하여 무난하게 만들 수 있었다.

 

그러면 이제 값을 2개 받는것도 하지 않을까? 예를 들면 이메일 같은거....

이메일 같은 경우 test1@test.com이라면 @을 경계로 test1과 test.com이라는 2개의 데이터를 받아야 하니까....

아니면 input으로 text를 주고 거기엔 이메일의 아이디?를 적고 콤보박스 같은 걸로 @test.com같은 것을 고르겠지...

 

아무튼 다음에도 예제는 잘 쓰일거 같으니 잘 알아 두도록해야겠다.