<< 학습 목표 >>
1. CRUD를 설명할 수 있다.
2. 회원가입 서비스를 개발할 수 있다.
여기까지 서블릿의 2 / 3 을 배웠음
앞으로 남은건 Chapter5(쿠키, 세션), Chapter6(필터와 리스너)임
다음 챕터로 넘어가기 전에 지금까지 배운것들로 간단하게 프로젝트를 진행하자
세상에 있는 모든 서비스는 CRUD 라고 부르는 구성요소로 이루어져있음
C - Create
R - Read
U - Update
D - Delete
쿠팡, 네이버 같은 웹 서비스는 물론이고 게임도 카카오톡과 같은 앱도 CRUD 구성요소로 이루어져있음
CRUD 구성요소가 없는 서비스라거나 CRUD 중 무언가가 빠져있는 서비스는 없음
이제 우리도 서블릿을 거의 다 배워가니 서비스 다운 서비스 하나를 만들어보자
우리가 만들 서비스는 모든 서비스의 기초가 되는 회원가입, 로그인, 회원정보수정, 회원탈퇴 를 가지고 있는 서비스임
이를 통해 자바, 서블릿을 더 깊게 이해하고 이 서비스를 잘 복습하면 여러분이 만들고 싶은 서비스를 만들 수도 있을 것
먼저 이 글에서는 회원가입 서비스를 만들 것
회원 가입이란 사용자가 "회원 가입 화면에 입력한 정보(회원 정보)"를 DB에 저장하는 것을 말함
회원 가입은 C에 해당함 / Create는 "만들다" 라는 뜻을 가지고 있음
사용자가 회원 가입을 하면 우리 서비스에 없었던 회원 정보가 생성되는 것이므로 C에 해당함
어떤 서비스를 만들기 위해서는 항상 기획 -> 개발 -> 테스트 -> 완료 의 과정을 거침
우리는 간단한 서비스이므로 기획은 필요 없지만 일반적으로 기획 할 때는 "개발할 기능에 대한 정의" 와 "스토리보드(와이어프레임)", "인터페이스" 가 반드시 필요함
스토리보드란 내가 만들 서비스의 화면, 서비스를 이용하는 예상 시나리오를 작성하는 것
사용자가 스토리보드를 봤을 때 "내가 이런 기능을 사용하게 되는구나" 라고 명확히 알 수 있어야함
인터페이스란 내가 만들 서비스의 서블릿에 대한 계획임
회원 가입 화면에서 [ 회원 가입 ] 버튼을 누르면 회원 가입 서블릿이 동작해 회원 가입 요청을 받아 회원 가입 처리를 할 것
이때 이 서블릿을 어떻게 만들지에 대한 계획으로 URL, 요청 방식, 파라미터, 상태 코드 등을 기입함
<< 기능에 대한 정의 >> |
로그인 하지 않은 사용자가 사용할 수 있는 기능으로 아이디, 비밀번호, 비밀번호 확인, 닉네임, 연락처를 입력한 후 회원 가입을 함 아이디, 연락처는 중복 되지 않아야함 나이가 어린 사용자의 경우 핸드폰이 없어 연락처가 없을 수 있으므로 연락처는 없을 수도 있음 아이디는 영문 대소문자, 숫자로 이루어져있고 영문 대소문자로 시작해야함 또한 아이디는 최소 3자, 최대 20자까지 가능함 비밀번호는 영문 대소문자, 숫자, 특수문자(!, @, #, $, %, ^, &, *)로 이루어져있고 최소 6자, 최대 16자까지 가능함 닉네임은 한글, 영문 대소문자, 숫자로 이루어져있고 숫자로 시작할 수 없음 또한 닉네임은 최소 2자, 최대 10자까지 가능함 연락처는 010-1111-1111과 같은 형식이고 01X 로 시작하는 번호는 입력할 수 없음 ( 참고, https://www.ajunews.com/view/20210309141213275 ) |
<< 스토리 보드 >> |
![]() |
<< 인터페이스 >> |
![]() |
회원 정보를 저장할 테이블을 만들자
테이블은 practice DB에 추가함
CREATE TABLE `member` ( `idx` INT(11) NOT NULL AUTO_INCREMENT, `id` VARCHAR(20) NOT NULL, `pw` VARCHAR(16) NOT NULL, `nickname` VARCHAR(10) NOT NULL, `tel` CHAR(13) NOT NULL, `joinDateTime` TIMESTAMP NOT NULL DEFAULT current_timestamp(), PRIMARY KEY (`idx`), UNIQUE INDEX `id` (`id`), UNIQUE INDEX `tel` (`tel`) ) |
이 카테고리에서는 HTML, CSS, JS 의 기초 내용은 다루지 않으므로 웹 페이지는 별도 설명 없이 코드만 첨부함
먼저 JS 없이 HTML, CSS 만을 사용한 화면을 만들자
우선 공용 CSS 부터 보자
webapp 안에 css 폴더 만들고 css 폴더 안에 public 폴더를 만들자
public 폴더 안에 minireset.css 를 만들고 아래 코드를 추가하자
@charset "UTF-8";
/*! minireset.css v0.0.6 | MIT License | github.com/jgthms/minireset.css */
html,
body,
p,
ol,
ul,
li,
dl,
dt,
dd,
blockquote,
figure,
fieldset,
legend,
textarea,
pre,
iframe,
hr,
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 0;
padding: 0;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-size: 100%;
font-weight: normal;
}
ul {
list-style: none;
}
button,
input,
select {
margin: 0;
}
html {
box-sizing: border-box;
}
*, *::before, *::after {
box-sizing: inherit;
}
img,
video {
height: auto;
max-width: 100%;
}
iframe {
border: 0;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
td,
th {
padding: 0;
}
fieldset {
border: 0;
}
webapp -> css -> public -> common.css 를 추가하고 아래 코드를 추가하자
@charset "UTF-8";
@import "minireset.css";
header {
display: flex;
justify-content: center;
padding: 20px;
}
main {
padding: 20px;
padding-top: 0;
display: flex;
justify-content: center;
}
이번에는 회원 가입 페이지를 만들자
webapp 폴더 안에 member 폴더를 만들고 그 안에 join.html 을 추가한 뒤 아래 코드를 추가하자
<< 회원 가입 HTML >>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>연습 프로젝트</title>
<link rel="stylesheet" type="text/css" href="/studyProject/css/public/common.css">
<link rel="stylesheet" type="text/css" href="/studyProject/css/member/join.css">
</head>
<body>
<header><< 회원 가입 >></header>
<main>
<form action="/studyProject/member/join" method="POST">
<fieldset>
<label for="id">아이디</label>
<input type="text" name="id" id="id">
</fieldset>
<fieldset>
<div>
<label for="pw">비밀번호</label>
<input type="password" name="pw" id="pw">
</div>
<div>
<label for="pwchk">비밀번호 확인</label>
<input type="password" name="pw" id="pwchk">
</div>
</fieldset>
<fieldset>
<label for="nickname">닉네임</label>
<input type="text" name="nickname" id="nickname">
</fieldset>
<fieldset>
<label for="tel">연락처</label>
<input type="tel" name="tel" id="tel">
</fieldset>
<fieldset>
<button type="button">회원가입</button>
</fieldset>
</form>
</main>
</body>
</html>
webapp -> css -> member 폴더를 만들고 그 안에 join.css 를 추가한 뒤 아래 코드를 추가하자
<< 회원 가입 CSS >>
@charset "UTF-8";
fieldset {
margin-bottom: 10px;
}
body > main > form > fieldset:nth-child(5) {
display: flex;
justify-content: end;
}
label {
display: inline-block;
width: 102px;
text-align: right;
}
webapp -> member -> joinSuccess.html 을 추가한 뒤 아래 코드를 추가하자
<< 회원가입 완료 HTML >>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>연습 프로젝트</title>
<link rel="stylesheet" type="text/css" href="/studyProject/css/public/common.css">
<link rel="stylesheet" type="text/css" href="/studyProject/css/member/joinSuccess.css">
</head>
<body>
<header><< 회원 가입 완료 >></header>
<main>
<div id="content_wrapper">
<div id="image_wrapper">
<div><img src="/studyProject/images/signupSuccess_left.png"></div>
<div><img src="/studyProject/images/signupSuccess_right.png"></div>
</div>
<a href="#">로그인 페이지로 이동</a>
</div>
</main>
</body>
</html>
webapp -> css -> member -> joinSuccess.css 를 추가 하고 아래 코드를 추가하자
<< 회원 가입 완료 CSS >>
@charset "UTF-8";
#content_wrapper {
text-align: center;
}
#image_wrapper {
display: flex;
}
img {
width: 100px;
}
<< 회원 가입 완료 이미지 파일 >>
이미지 파일은 webapp -> images 폴더를 만들고 그 안에 넣어두자
페이지를 만들었으니 한번씩 확인하자
이제 서블릿(기능) 을 만들 차례
그 전에 파라미터를 한 차례 검증 후 꺼내줄 메서드를 추가하자
혹시 "파라미터 검증이 뭐지?" 라고 생각이 드시는 분은 https://codingaja.tistory.com/24 이 글을 읽고 오자
util 패키지 -> ParameterUtil 클래스를 추가한 후 아래 코드를 추가하자
package utility;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
public class ParameterUtil {
/**
* name 파라미터 값을 꺼내는 메서드
* 파라미터가 없거나 파라미터 값을 trim() 한 후 비어있다면 null을 반환
*
* @param request 파라미터를 담고 있는 객체
* @param name 값을 꺼낼 파라미터의 이름
* @return String 또는 null
*/
public static String getString(HttpServletRequest request, String name) {
String str = null;
str = request.getParameter(name);
if(str != null) {
str = str.trim();
if(str.length() == 0) {
str = null;
}
}
return str;
}
public static boolean isId(String id) {
String pattern = "[a-zA-Z0-9]{3,20}";
Pattern p = Pattern.compile(pattern);
Matcher m = p.matcher(id);
return m.matches();
}
public static boolean isPw(String pw) {
String pattern = "(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*])[a-zA-Z0-9!@#$%^&*]{6,16}";
Pattern p = Pattern.compile(pattern);
Matcher m = p.matcher(pw);
return m.matches();
}
public static boolean isNickname(String nickname) {
String pattern = "[가-힣a-zA-Z0-9]{2,10}";
Pattern p = Pattern.compile(pattern);
Matcher m = p.matcher(nickname);
return m.matches();
}
public static boolean isTel(String tel) {
String pattern = "010-([0-9]{4})-([0-9]{4})";
Pattern p = Pattern.compile(pattern);
Matcher m = p.matcher(tel);
return m.matches();
}
}
이제 회원 가입 기능을 만들자
회원 가입 기능을 만들 때는 인터페이스를 참고해야함
혹시 "왜?" 라는 생각이 들면 다시 이 글을 처음부터 읽고 오자
회원가입 인터페이스를 추가하기 위해 member 패키지를 추가하자
member 패키지 안에 MemberJoin 서블릿을 추가하고 우선 회원가입 인터페이스대로 대략적으로만 구성해놓자
package member;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import utility.ParameterUtil;
@WebServlet("/member/join")
public class MemberJoin extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 파라미터 검증
String id = ParameterUtil.getString(request, "id");
String pw = ParameterUtil.getString(request, "pw");
String nickname = ParameterUtil.getString(request, "nickname");
String tel = ParameterUtil.getString(request, "tel");
if(!ParameterUtil.isId(id)) {
response.setStatus(400);
return ;
} else if(!ParameterUtil.isPw(pw)) {
response.setStatus(400);
return ;
} else if(!ParameterUtil.isNickname(nickname)) {
response.setStatus(400);
return ;
} else if(!ParameterUtil.isTel(tel)) {
response.setStatus(400);
return ;
}
// 회원 가입
if(회원가입에 성공했다) {
// 상태 코드를 설정하지 않으면 자동으로 200으로 설정되므로
// 설정 생략
// response.setStatus(200);
} else if(아이디 또는 연락처가 중복됐다) {
response.setStatus(409);
} else {
response.setStatus(500);
}
}
}
앞서 언급했듯 서블릿은 컨트롤러(Controller / 제어자)의 역할임
컨트롤러의 역할은 다음과 같음
1. 클라이언트의 요청을 받는다.
2. 파라미터 검증을 한다.
3. 요청에 맞는 처리할 서비스를 호출한다.
4. 서비스가 반환한 결과에 따라 적절한 결과를 클라이언트에게 전달한다.
우리는 지금 1, 2, 4 를 가지고 있는 서블릿을 만들었음
3은 회원가입임
회원 가입할 서비스를 만들자
서비스는 자바 코드임
자바 코드를 다른 말로 POJO(Plain Old Java Object) 라고 부름
member 패키지에 MemberService 클래스를 추가하고 아래 코드를 입력하자
package member;
public class MemberService {
public String join(String id, String pw, String nickname, String tel) {
// 아이디 중복 여부 확인
if(아이디가 중복되었다) {
return "duplicate_id";
}
// 연락처 중복 여부 확인
if(연락처가 중복되었다) {
return "duplicate_tel";
}
// 회원가입
}
}
! 여기서 잠깐 ! 회원가입 서비스(join 메서드)가 가입할 회원 정보를 전달 받기 위해 4개의 매개변수를 사용하고 있음이를 더 효율적으로 바꾸자자바에서 정보를 저장할 때는 DTO 또는 VO 라고 부르는 자바 코드를 사용함DTO는 Data Transfer Object, VO는 ValueObject 의 약자로 정보를 담아 전달하기 위한 용도인 클래스를 말함컨트롤러에서 회원 정보를 담아 서비스로 전달하기 위해 memberDto 를 추가하자member 패키지에 memberDto 클래스를 추가하고 아래와 같이 코드를 입력하자
package member;
import java.time.LocalDateTime;
public class MemberDto {
private int idx;
private String id;
private String pw;
private String nickname;
private String tel;
private LocalDateTime joinDateTime;
public MemberDto(int idx, String id, String pw, String nickname, String tel, LocalDateTime joinDateTime) {
this.idx = idx;
this.id = id;
this.pw = pw;
this.nickname = nickname;
this.tel = tel;
this.joinDateTime = joinDateTime;
}
public MemberDto(String id, String pw, String nickname, String tel) {
this.id = id;
this.pw = pw;
this.nickname = nickname;
this.tel = tel;
}
public int getIdx() {
return idx;
}
public void setIdx(int idx) {
this.idx = idx;
}
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 getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel;
}
public LocalDateTime getJoinDateTime() {
return joinDateTime;
}
public void setJoinDateTime(LocalDateTime joinDateTime) {
this.joinDateTime = joinDateTime;
}
}
이제 컨트롤러와 서비스 코드에서 MemberDto 를 사용하도록 바꾸자<< MemberJoin 서블릿 >>
package member;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import utility.ParameterUtil;
@WebServlet("/member/join")
public class MemberJoin extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 파라미터 검증
String id = ParameterUtil.getString(request, "id");
String pw = ParameterUtil.getString(request, "pw");
String nickname = ParameterUtil.getString(request, "nickname");
String tel = ParameterUtil.getString(request, "tel");
if(!ParameterUtil.isId(id)) {
response.setStatus(400);
return ;
} else if(!ParameterUtil.isPw(pw)) {
response.setStatus(400);
return ;
} else if(!ParameterUtil.isNickname(nickname)) {
response.setStatus(400);
return ;
} else if(!ParameterUtil.isTel(tel)) {
response.setStatus(400);
return ;
}
// 회원 가입
MemberDto member = new MemberDto(id, pw, nickname, tel);
MemberService service = new MemberService();
String result = service.join(member);
if(회원가입에 성공했다) {
// 상태 코드를 설정하지 않으면 자동으로 200으로 설정되므로
// 설정 생략
// response.setStatus(200);
} else if(아이디 또는 연락처가 중복됐다) {
response.setStatus(409);
} else {
response.setStatus(500);
}
}
}
<< MemberService >>
package member;
public class MemberService {
public String join(MemberDto member) {
// 아이디 중복 여부 확인
if(아이디가 중복되었다) {
return "duplicate_id";
}
// 연락처 중복 여부 확인
if(연락처가 중복되었다) {
return "duplicate_tel";
}
// 회원가입
}
}
다시 서비스로 돌아가서 MemberService의 join 메서드가 서비스로 회원가입을 하기 위해 아이디 중복 여부 확인, 연락처 중복 여부 확인을 함
아이디, 연락처 모두 중복되지 않았다면 회원가입을 함
아이디, 연락처 중복 여부는 DB의 member 테이블에서 사용자가 입력한 아이디 또는 연락처와 같은 계정 정보가 있는지 SELECT 를 하면 됨
사용자가 입력한 아이디 또는 연락처와 같은 계정 정보가 있다면 중복되는 것이고 같은 계정 정보가 없다면 중복되지 않은 것임
회원가입은 회원 정보를 DB의 member 테이블에 INSERT 하면 됨
DB와 통신하는 서비스가 필요하므로 DAO 를 만들자
DAO 전에 DAO를 위해 utility 패키지에 DBUtil 클래스를 추가하고 아래 코드를 입력하자
package utility;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class DBUtil {
private static final String DRIVER_NAME = "org.mariadb.jdbc.Driver";
private static final String DB_URL = "jdbc:mariadb://localhost:3306/practice?user=root&password=0000";
public static Connection getConnection() {
Connection conn = null;
try {
Class.forName(DRIVER_NAME);
conn = DriverManager.getConnection(DB_URL);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
private static void close(Connection conn) {
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
private static void close(PreparedStatement pstmt) {
try {
if(pstmt != null) {
pstmt.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
private static void close(ResultSet rs) {
try {
if(rs != null) {
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void closes(Connection conn, PreparedStatement pstmt) {
closes(conn, pstmt, null);
}
public static void closes(Connection conn, PreparedStatement pstmt, ResultSet rs) {
close(rs);
close(pstmt);
close(conn);
}
}
member 패키지에 MemberDao 클래스를 추가하고 아래 코드를 추가하자
package member;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDateTime;
import utility.DBUtil;
public class MemberDao {
public MemberDto selectOneById(String id) {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
MemberDto member = null;
try {
conn = DBUtil.getConnection();
String sql = "SELECT * FROM member WHERE id = ?";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, id);
rs = pstmt.executeQuery();
if(rs.next()) {
int idx = rs.getInt("idx");
String pw = rs.getString("pw");
String nickname = rs.getString("nickname");
String tel = rs.getString("tel");
LocalDateTime joinDateTime = rs.getTimestamp("joinDateTime").toLocalDateTime();
member = new MemberDto(idx, id, pw, nickname, tel, joinDateTime);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtil.closes(conn, pstmt, rs);
}
return member;
}
public MemberDto selectOneByTel(String tel) {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
MemberDto member = null;
try {
conn = DBUtil.getConnection();
String sql = "SELECT * FROM member WHERE tel = ?";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, tel);
rs = pstmt.executeQuery();
if(rs.next()) {
int idx = rs.getInt("idx");
String id = rs.getString("id");
String pw = rs.getString("pw");
String nickname = rs.getString("nickname");
LocalDateTime joinDateTime = rs.getTimestamp("joinDateTime").toLocalDateTime();
member = new MemberDto(idx, id, pw, nickname, tel, joinDateTime);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtil.closes(conn, pstmt, rs);
}
return member;
}
}
우선 이 DAO 에는 회원 가입은 빼고 아이디 중복 여부를 확인하기 위한 메서드와 연락처 중복 여부를 확인하기 위한 메서드를 넣었음
위에서 언급한대로 selectOneById 메서드는 아이디로 계정 정보를 조회하고 조회된 결과가 있다면 반환함
selectOneByTel 메서드는 연락처로 계정 정보를 조회하고 조회된 결과가 있다면 반환함
서비스에서는 이 두 메서드를 사용해서 두 메서드가 반환한 계정 정보가 있다면 아이디 또는 연락처가 중복된 것으로 판단하고 반환한 계정 정보가 없다면 아이디 또는 연락처가 중복된 것이 아닌것으로 판단하면 됨
<< MemberService 클래스 >>
package member;
public class MemberService {
public String join(MemberDto member) {
MemberDao dao = new MemberDao();
// 아이디 중복 여부 확인
if(dao.selectOneById(member.getId()) != null) {
return "duplicate_id";
}
// 연락처 중복 여부 확인
if(dao.selectOneByTel(member.getTel()) != null) {
return "duplicate_tel";
}
// 회원가입
}
}
서비스에서 회원 가입할 때 사용할 INSERT 쿼리를 DAO에 추가하자
<< MemberDao 클래스 >>
DAO 안에 추가될 메서드만 복사해왔으니 memberDao 클래스 내 적절한 위치에 붙여넣자
public int insertByMemberDto(MemberDto member) {
Connection conn = null;
PreparedStatement pstmt = null;
int count = 0;
try {
conn = DBUtil.getConnection();
String sql = "INSERT INTO member(id, pw, nickname, tel) VALUES(?, ?, ?, ?)";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, member.getId());
pstmt.setString(2, member.getPw());
pstmt.setString(3, member.getNickname());
pstmt.setString(4, member.getTel());
count = pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtil.closes(conn, pstmt);
}
return count;
}
서비스에 회원가입 과정을 마무리 하자
package member;
public class MemberService {
public String join(MemberDto member) {
MemberDao dao = new MemberDao();
// 아이디 중복 여부 확인
if(dao.selectOneById(member.getId()) != null) {
return "duplicate_id";
}
// 연락처 중복 여부 확인
if(dao.selectOneByTel(member.getTel()) != null) {
return "duplicate_tel";
}
// 회원가입
if(dao.insertByMemberDto(member) == 1) {
return "OK";
} else {
return "unknown error";
}
}
}
정상적으로 회원 가입을 했다면 insertByMemberDto 메서드가 1을 반환함
따라서 회원가입의 if문을 해석해보면 "회원가입이 됐다면 OK 를 반환한다." 가 됨
else문은 "회원가입에 실패했다면 unknown error를 반환한다." 가 됨
이제 컨트롤러에서 서비스가 반환한 결괏값을 사용해 적절한 결괏값을 클라이언트에게 전달하도록 마무리하자
package member;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import utility.ParameterUtil;
@WebServlet("/member/join")
public class MemberJoin extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 파라미터 검증
String id = ParameterUtil.getString(request, "id");
String pw = ParameterUtil.getString(request, "pw");
String nickname = ParameterUtil.getString(request, "nickname");
String tel = ParameterUtil.getString(request, "tel");
if(!ParameterUtil.isId(id)) {
response.setStatus(400);
return ;
} else if(!ParameterUtil.isPw(pw)) {
response.setStatus(400);
return ;
} else if(!ParameterUtil.isNickname(nickname)) {
response.setStatus(400);
return ;
} else if(!ParameterUtil.isTel(tel)) {
response.setStatus(400);
return ;
}
// 회원 가입
MemberDto member = new MemberDto(id, pw, nickname, tel);
MemberService service = new MemberService();
String result = service.join(member);
if(result.equals("OK")) {
// 상태 코드를 설정하지 않으면 자동으로 200으로 설정되므로
// 설정 생략
// response.setStatus(200);
} else if(result.startsWith("duplicate")) {
response.setStatus(409);
} else {
response.setStatus(500);
}
}
}
여기까지 백엔드 구현이 완료됐음
이제 서버를 실행시키고 회원 가입 페이지에서 회원 가입을 해봐야할 차례인데!!
회원 가입 페이지에서 [ 회원가입 ] 버튼을 아무리 눌러도 반응이 없음
왜? [ 회원가입 ] 버튼의 HTML 태그를 보면 button 타입이기 때문에
[ 회원가입 ] 버튼이 submit 타입이라면 서버로 id, pw, pwchk, nickname, tel 을 보내 회원 가입 요청이 들어가겠지만 요청 결과로 서버는 상태 코드만 설정해 전달함
그래서 [ 회원가입 ] 버튼이 submit 타입이라면 사용자는 [ 회원가입 ] 버튼을 눌렀을 때 흰 화면만 보게됨
[ 회원 가입 ] 버튼의 타입을 button 타입으로 해 JS에서 Jquery의 ajax 를 사용해 회원 가입 요청을 보내고 결과를 받도록 할 것
서버가 보낸 결과가 409(아이디 또는 연락처가 중복)라면 "아이디 또는 연락처가 중복되었습니다" 를 출력할 것
서버가 보낸 결과가 200(회원 가입 성공)이라면 로그인 성공 페이지로 이동할 것
<< 회원 가입 HTML >>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>연습 프로젝트</title>
<link rel="stylesheet" type="text/css" href="/studyProject/css/public/common.css">
<link rel="stylesheet" type="text/css" href="/studyProject/css/member/join.css">
</head>
<body>
<header><< 회원 가입 >></header>
<main>
<form action="/studyProject/member/join" method="POST">
<fieldset>
<label for="id">아이디</label>
<input type="text" name="id" id="id" required="required" dp-name="아이디">
</fieldset>
<fieldset>
<div>
<label for="pw">비밀번호</label>
<input type="password" name="pw" id="pw" required="required" dp-name="비밀번호">
</div>
<div>
<label for="pwchk">비밀번호 확인</label>
<input type="password" name="pw" id="pwchk" required="required" dp-name="비밀번호 확인">
</div>
</fieldset>
<fieldset>
<label for="nickname">닉네임</label>
<input type="text" name="nickname" id="nickname" required="required" dp-name="닉네임">
</fieldset>
<fieldset>
<label for="tel">연락처</label>
<input type="tel" name="tel" id="tel" required="required" dp-name="연락처">
</fieldset>
<fieldset>
<button type="button" role="submit">회원가입</button>
</fieldset>
</form>
</main>
<script src="https://code.jquery.com/jquery-3.6.3.min.js" integrity="sha256-pvPw+upLPUjgMXY0G+8O0xUf+/Im1MZjXxxgOcBQBXU=" crossorigin="anonymous"></script>
<script>
$("button").on("click", function() {
let id = $("#id").val();
let pw = $("#pw").val();
let pwchk = $("#pwchk").val();
let nickname = $("#nickname").val();
let tel = $("#tel").val();
if(pw != pwchk) {
alert("비밀번호와 비밀번호 확인이 일치하지 않습니다.");
$("#pwchk").focus();
return false;
}
$.ajax({
url: "/studyProject/member/join",
type: "POST",
data: {"id": id, "pw": pw, "nickname": nickname, "tel": tel},
success: function() {
location.href = "/studyProject/member/joinSuccess.html";
},
error: function(response) {
if(response.status == 400) {
alert("모든 정보를 입력해주세요.");
} else if(response.status == 409) {
alert("아이디 또는 연락처가 중복되었습니다.");
} else {
alert("서버에 문제가 생겼습니다.\n잠시 후 다시 시도해주세요.");
}
}
});
});
</script>
</body>
</html>
이제 서버를 실행하고 아이디, 비밀번호, 비밀번호 확인, 닉네임, 연락처 규칙을 잘 확인하고 입력 후 가입을 해보자
여기까지~!
길고 길었던 회원 가입 서비스를 만들어봤음
회원 가입 서비스 하나를 만들기 위해 이렇게 많은 과정을 거쳐야하고 많은 것들을 알고 있어야하는것처럼 개발자가 되기 위해서는 많은 공부, 복습, 노력이 필요함
'Servlet + JSP > Serlvet-Chapter04' 카테고리의 다른 글
Chapter04. CRUD 프로젝트 / 로그인 (0) | 2023.03.08 |
---|---|
Chapter04. Connection Pool 을 사용한 DB 연동 (0) | 2023.03.08 |
Chapter04. 자바의 DB와 관련된 자원은 close 를 해줘야한다. (2) | 2023.03.06 |
Chapter04. 자바에서 쿼리 보내고 결과 받기 / SELECT (0) | 2023.03.06 |
Chapter04. 자바에서 쿼리 보내고 결과 받기 / INSERT, UPDATE, DELETE (0) | 2023.03.06 |