홈페이지 만들기 프로젝트 part2 - 회원가입을 구현해보자

안녕하세요

이번 시간에는 홈페이지 만들기에서 정말 필수적인 부분이죠

회원가입과 로그인 예제를 올려봅니다.


저번 포스팅에 올린 top.jsp에 보면,

참조하는 부분이 세개입니다.


첫번째가 css 파일입니다.

소스코드는 아래와 같이 있습니다.

<link rel="stylesheet" type="text/css" href="<%=myctx%>/css/layout.css">
<link rel="stylesheet" type="text/css" href="<%=myctx%>/css/calendar.css">

즉 css 폴더 아래에 layout.css, calendar.css가 있어야 색상이나 크기 같은 것을

지정 할 수 있습니다.


두 번째 파일은 자바스크립트 파일로..

<script src="./js/calendar.js"></script> 파일로

js 폴더 아래에 calendar 자바스크립트 파일이 있어야 하며

이 파일은 달력을 만드는 파일입니다.

이것은 직접 구현하시길 바라며 따로 공개는 안하겠습니다.

(전에도 블로그에 올렸기 때문에)


그리고 세번째 파일은 jsp 파일로 4개로 구성되어 있습니다.

<li><a href="<%=myctx%>/index.jsp">HOME</a></li>
<li><a href="<%=myctx%>/member/memberJoin.jsp">JOIN</a></li>
<li><a href="<%=myctx%>/login/login.jsp">LOGIN</a></li>
<li><a href="<%=myctx%>/board/board.jsp">BOARD</a></li>

첫번째 index.jsp는 저번 시간에 올렸고,

이번 시간에는 memberJoin.jsp와 login.jsp 두 개를 구현하겠습니다
(board.jsp는 시간이 되면 추후에 올리도록 하겠습니다 - 아직 미구현 ㅜ)


원래는 회원가입과 로그인 두 개 모두 다 올리려고 했는데

회원가입만 해도 관련된 클래스, jsp 파일이 많아 일단 이번 시간에는

memberJoin.jsp 부분만 올리겠습니다.

중요한 소스 부분은 빨간줄로 표시를 하겠습니다.

========================================================

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
   
<jsp:include page="/top.jsp"/>

<style>
td,th{
padding:5px;
}
input{
height:20px;
}
</style>

<script type="text/javascript">

/*아이디 중복체크 팝업 띄우기*/
var idCheck=function(){
var url="idCheck.jsp";
win=window.open(url,"idCheck","width=400, height=400, left=100, top=100");
}

/*입력 값 유효성 체크*/
  var check=function(){
//이름, 아이디, 비번, 연락처1,2,3

if(!f.name.value){
alert('이름을 입력하세요');
f.name.focus();
return;
}

if(!f.userid.value){
alert('아이디를 입력하세요');
f.userid.focus();
return;
}

if(!f.pwd.value){
alert('비밀번호를 입력하세요');
f.pwd.focus();
return;
}

if(f.pwd.value != f.pwd2.value){
alert('비밀번호와 비밀번호 확인이 달라요');
f.pwd2.select();
return;
}

if(!f.hp1.value || !f.hp2.value || !f.hp3.value){
alert('연락처를 모두 입력하세요');
f.hp2.focus();
return;
}

// 연락처, 우편번호 숫자 여부.. <- 내가 해야 할 몫..

// 이용약관 동의 체크 여부
if(!f.agree.checked){
alert('이용약관에 동의해야 해요');
f.agree.focus();
return;
}

f.submit();
}

</script>

<!-- 다음 api를 활용하여 우변펀호 등록하는 스크립트 사용  -->
<script src="http://dmaps.daum.net/map_js_init/postcode.js"></script>
    <script>
        function openDaumPostcode() {
            new daum.Postcode({
                oncomplete: function(data) {
                    // 팝업에서 검색결과 항목을 클릭했을때 실행할 코드를 작성하는 부분. 우편번호와 주소 정보를 해당 필드에 넣고, 커서를 상세주소 필드로 이동한다.
                    document.getElementById("addr1").value = data.postcode1;
                    document.getElementById("addr2").value = data.postcode2;
                    document.getElementById("addr1").value = data.address;
                    document.getElementById("addr2").focus();
                }
            }).open();
        }
    </script>

<div align="center">
    <h1>:::Member Join:::</h1>
    <form name="f" id="f" action="memberJoinEnd.jsp" method="post">
    <table style="width:90%">
    <tr>
    <th width="20%">이름</th>
    <td width="80%" style="text-align: left;">
    <input type="text" name="name">
    </td>
    </tr>
    <tr>
    <th width="20%">아이디</th>
    <td width="80%" style="text-align: left;">
    <input type="text" name="userid" readonly style="background-color:#efefef;">
    <button type="button" onclick="idCheck()">아이디 중복체크</button>
    </td>
    </tr>
    <tr>
    <th width="20%">비밀번호</th>
    <td width="80%" style="text-align: left;">
    <input type="password" name="pwd">
    </td>
    </tr>
    <tr>
    <th width="20%">비밀번호 확인</th>
    <td width="80%" style="text-align: left;">
    <input type="password" name="pwd2">
    </td>
    </tr>
    <tr>
    <th width="20%">이메일</th>
    <td width="80%" style="text-align: left;">
    <input type="text" name="email" style="width:50%">
    </td>
    </tr>
    <tr>
    <th width="20%">연락처</th>
    <td width="80%" style="text-align: left;">
    <select name="hp1">
    <optgroup label="연락처">
    <option value="010">010</option>
    <option value="011">011</option>
    <option value="019">019</option>
    </optgroup>
    </select>
    <input type="text" name="hp2" size="4" maxlength="4">-
    <input type="text" name="hp3" size="4" maxlength="4">
    </td>
    </tr>
    <tr>
    <th width="20%">우편번호</th>
    <td width="80%" style="text-align: left;">
    <input type="text" name="post" maxlength="5" size="15">
    <button type="button" class="btngray btn" onclick="openDaumPostcode()">우편번호 찾기</button>
    </td>
    </tr>
    <tr>
    <th width="20%">주소</th>
    <td width="80%" style="text-align: left;">
    <input type="text" name="addr1" id="addr1" style="width:70%"><br>
    <input type="text" name="addr2" id="addr2" style="width:70%">
    </td>
    </tr>
    <tr>
    <td colspan="2" style="text-align:right; padding-right:30px">이용 약관에 동의하십니까?
    <input type="checkbox" name="agree"></td>
    </tr>
    <tr>
    <td colspan="2">
    <iframe src="agree.html" style="width:90%; heigth:120px"></iframe>
    </td>
    </tr>
    <tr>
    <td colspan="2">
    <button type="button" onclick="check()">회원가입</button>
    <button types="reset">다시쓰기</button>
    </td>
    </tr>
    </table>
    </form>
</div>

<jsp:include page="/foot.jsp"/>



일단 보면 아시겠지만 제가 밑줄로 그은 빨간색 .jsp 파일이 있습니다.

idCheck.jsp, memberJoinEnd.jsp

이 두개를 또 추가적으로 구현해야 합니다.

참고로 idCheck.jsp에서는



user.member 패키지에 MemberDAO.java가 있어야 소스코드가 오류없이 작동합니다.

MemberDAO.java는 db에 쿼리문을 수행하는 소스 코드입니다.

앞으로 많이 나올 예정입니다 ㅜ


========================================================

idCheck.jsp


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<link rel="stylesheet" type="text/css" href="../css/layout.css">
<script type="text/javascript">
function setUid(uid){
//uid 값을 팝업창을 띄워준 부모창의 userid 텍스트박스에 넣어주자.
//window(최상위 객체)-->document-->form(최하위)
//부모창=> opener (window 객체)
opener.document.f.userid.value=uid;
//팝업창 닫기
self.close();
//자기창=> self로 참조

}

function checkId(){
if(!frm.userid.value){
alert('아이디를 입력하세요');
frm.userid.focus();
return;
}
frm.submit();
}

</script>

    <%
    String method=request.getMethod();
    //out.println("<b>method="+method);
    //[1] 메소드 방식이 GET 방식이면 => 아이디 입력 폼을 보여준다
    if(method.equalsIgnoreCase("get")){ // 대소문자 상관안하고 get 문자이면..
    %>
    <div align="center" style="padding:10px;">
    <form name="frm" action="idCheck.jsp" method="POST">
    <label for="userid">아이디</label>
    <input type="text" name="userid" id="userid" style="border:1px solid silver">
    <button type="button" onclick="checkId()">확인</button>
    </form>
    </div>
    <%
    }else{
    //[2] POST 방식이면 => 아이디 중복 체크 결과를 보여준다
    // (1) 사용자가 입력한 아이디 값 받아오기
    String userid=request.getParameter("userid");
    if(userid==null||userid.trim().isEmpty()){
    %>
    <script type="text/javascript">
    alert('아이디를 입력해야 해요');
    history.back();
    </script>
    <%
    return;
    }
    %>

<!-- DAO는 웹브라우저 한번 당 세션으로 이어짐 / VO,DTO는 스코프를 페이지로 준다 -->
<jsp:useBean id="userDAO" class="user.member.MemberDAO" scope="session" />
    <%
    // (2) DB member 테이블에 해당 아이디가 있는지 체크
    boolean isUse=userDAO.idCheck(userid.trim());
    if(isUse){ // 사용 가능한 경우 = true
    %>
    <div align="center">
    <p>
    ID로 [<SPAN style="color:red"><b><%=userid%></b></SPAN>]를 사용할 수 있습니다.
    </p>
    <button type="button" onclick="setUid('<%=userid%>')">닫기</button>
    </div>
    <%
    }else{ // 사용 불가능한 경우 = false
    %>
    <div align="center">
    <p>
    ID로 [<SPAN style="color:red"><b><%=userid%></b></SPAN>]는 이미 사용중입니다.
    </p>
   
<form name="frm" action="idCheck.jsp" method="POST">
    <label for="userid">아이디</label>
    <input type="text" name="userid" id="userid" style="border:1px solid silver">
    <button type="button" onclick="checkId()">확인</button>
    </form>
   
    </div>
    <%
    }
    }
    %>


idCheck.jsp에서는 가장 중요한 부분은 역시

userDAO.idCheck(userid.trim());

부분입니다.

즉 user.member 패키지 아래에 있는 MemberDAO 소스에

idCheck() 메소드가 있어야 이 소스는 이상없이 작동됩니다.


그럼 바로 MemberDAO 소스 코드를 공개하겠습니다.

전체 골격 소스는 이번 한번만 공개하고, 다음에 쓰일 때는

메소드만 올리겠습니다.


package user.member;

import db.util.*;
import java.sql.*;
import java.util.*;

// DAO : Data Access Object
public class MemberDAO {

private Connection con;
private PreparedStatement ps;
private ResultSet rs;

public MemberDAO(){
System.out.println("MemberDAO() 생성자");
}

/** 아이디의 사용 가능 여부를 체크하는 메소드*/

public boolean idCheck(String userid) throws SQLException{
try{
con=DBUtil.getCon();
String sql="SELECT idx FROM member WHERE userid=?";
ps=con.prepareStatement(sql);
ps.setString(1, userid);
rs=ps.executeQuery();
//rs의 커서 이동
boolean isRs=rs.next();
return !isRs; // 밑에 4줄 짜리를 한줄로 줄임
/*if(isRs){
//해당 아이디가 member에 있는 경우
return false;
}else{
//없는 경우
return true;
}*/

}finally{
DBUtil.close(rs, ps, con);
}
}


참고로 여기서 db.util 패키지에 DBUtil 이라는 클래스가 또 있어야 합니다 ㅜ

package db.util;

import java.sql.*;
/*드라이버 로딩하고 커넥션을 하는 클래스*/

public class DBUtil {

private static String host="localhost";
private static String url="jdbc:oracle:thin:@"+host+":1521:ORCL";
private static String user="king", pwd="tiger";
private static String driver="oracle.jdbc.driver.OracleDriver";

static{
try{
Class.forName(driver);
System.out.println("Driver Loading Success...");
}catch(Exception e){
e.printStackTrace();
}

}//static initializer - 메모리에 가장 먼저 올라가는 블록으로 main() 보다도 먼저 실행됨

public static synchronized Connection getCon() throws SQLException{
System.out.println("url="+url);
Connection con = DriverManager.getConnection(url,user,pwd);
return con;
}

//setter, getter--

public static String getHost() {
return host;
}

public static void setHost(String host) {
DBUtil.host = host;
}

public static String getUrl() {
return url;
}

public static void setUrl(String url) {
DBUtil.url = url;
}

public static String getUser() {
return user;
}

public static void setUser(String user) {
DBUtil.user = user;
}

public static String getPwd() {
return pwd;
}

public static void setPwd(String pwd) {
DBUtil.pwd = pwd;
}

public static String getDriver() {
return driver;
}

public static void setDriver(String driver) {
DBUtil.driver = driver;
}

public static void close(ResultSet rs, Statement st, Connection con) {
try{
if(rs!=null) rs.close();
if(st!=null) st.close();
if(con!=null) con.close();
System.out.println("DB연결 종료");
}catch(SQLException e){
e.printStackTrace();
}

}
}

========================================================

자 이제 마지막 부분입니다.

memberJoinEnd.jsp 소스 부분인데요.

바로 공개하도록 하겠습니다.


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" errorPage="../example/error.jsp" %>

    <!-- memberJoinEnd.jsp : 회원가입 처리 페이지
      사용자가 입력한 값을 받아 DB member 테이블에 insert 처리한다.
    -->
   
    <%
    //1. post 방식일 경우 한글 처리
    request.setCharacterEncoding("UTF-8");
   
    //2. 사용자가 입력한 값을 받아온다
    //String name=request.getParameter("name");
    //String userid=request.getParameter("userid");
    //String pwd=request.getParameter("pwd");
    //String email=request.getParameter("email");
    //out.println(name+"/"+userid);
    //out.println("패스워드 : "+pwd);
   
    %>
   
    <jsp:useBean id="userVO" class="user.member.MemberVO" scope="page"/>
    <%--
    MemberVO userVO=new MemberVO()와 동일 -> 다만 MemberVO 클래스에 기본 생성자가 없으면 오류남
    --%>
   
    <jsp:setProperty name="userVO" property="*"/>
    <%--
    userVO.setName(request.getParameter("name"));와 동일
    즉 memberJoin.jsp에서 입력한 값을 각각 얻어오는 것이다.
    userVO.setUserid(...)
    ...
    와 동일
    --%>


    <B><%=userVO%></B>
   
    <%
    //3. 유효성 체크 (이름, 아이디)
    if(userVO.getName()==null||userVO.getUserid()==null){
response.sendRedirect("memberJoin.jsp"); // 이 코드를 작성하면 memberJoinEnd 클래스에서 실행해도 memberJoin으로 되돌아감
    return;
    }
    %>
   
    <jsp:useBean id="userDAO" class="user.member.MemberDAO" scope="session"/>
   
    <%
    int n=userDAO.insertMember(userVO);
    String msg=(n>0)?"회원가입 성공":"회원가입 실패";
    String loc=(n>0)?"memberList.jsp":"javascript:history.back()";
    %>
   
    <script type="text/javascript">
    alert('<%=msg%>');
    location.href='<%=loc%>';
    </script>
   


하아.. 여기서도 참고하고 있는 부분이 세 부분입니다.

첫번째가 에러 화면을 보여주는 error.jsp

두번째가 사용자가 입력한 회원정보 값을 불러들이는 MemberVO 클래스

세번째는 아까 위에서 활용했던 DB를 처리하는 MemberDAO 클래스의 insertMember 메소드


이 세 부분도 바로 소스 코드를 올리겠습니다.

1. error.jsp

<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<jsp:include page="/top.jsp"/>

<%@ page isErrorPage="true" %>
<%
response.setStatus(response.SC_OK);
//ie에서는 위 코드를 지정해야 에러 처리 페이지가 동작한다
%>

<%-- error.jsp 페이지에서는 page 지시어에 반드시 isErrorPage 라는 속성값으로 true를 주어야 한다.
그래야 exception 이라는 내장 객체를 사용할 수 있다. --%>

<!DOCTYPE html>
<html>
<head><title>error 처리 페이지</title></head>
<body>
<div align="center">
<table style="width:600px;height:400px;background-color:#efefef">
<tr>
<td style="color:red;text-align:center">
<%
if(exception instanceof java.sql.SQLException){
out.println("서버오류: "+exception.getMessage());
}else{
out.println("오류발생: "+exception.getMessage());
}
exception.printStackTrace(); // 스택 기록 찍기(서버 콘솔에)
%>
</td>
</tr>
<tr>
<td>[<a href="javascript:history.back()">이전 페이지</a>]</td>
</tr>
</table>
</div>
<jsp:include page="/foot.jsp"/>



2. MemberVO

package user.member;

import java.io.*;
import java.sql.Date;

//dto, dao 직렬화 하는 것이 좋다
public class MemberVO implements Serializable {
// 멤버변수(인스턴스 변수) => jsp에서는 프로퍼티(property) 라고 부른다.
// 프로퍼티들은 가능하면 html form의 input name과 일치시켜 주는 것이 좋다

private Integer idx; // 회원번호
private String name;
private String userid;
private String pwd;
private String email;
private String hp1, hp2, hp3;
private String post;
private String addr1, addr2;
private java.sql.Date indate;
private int mileage;
private int mstate; // 회원 상태 정보

public MemberVO(){
System.out.println("MemberVO() 생성자");
//기본 생성자 반드시 필요
//기본 생성자가 없으면 jsp에서 useBean으로 객체 생성을 할 수 없다.
}

// 생성자 오버로드

public MemberVO(Integer idx, String name, String userid, String pwd, String email, String hp1, String hp2,
String hp3, String post, String addr1, String addr2, Date indate, int mileage, int mstate) {
super();
this.idx = idx;
this.name = name;
this.userid = userid;
this.pwd = pwd;
this.email = email;
this.hp1 = hp1;
this.hp2 = hp2;
this.hp3 = hp3;
this.post = post;
this.addr1 = addr1;
this.addr2 = addr2;
this.indate = indate;
this.mileage = mileage;
this.mstate = mstate;
}

//setter, getter

public Integer getIdx() {
return idx;
}

public void setIdx(Integer idx) {
this.idx = idx;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getUserid() {
return userid;
}

public void setUserid(String userid) {
this.userid = userid;
}

public String getPwd() {
return pwd;
}

public void setPwd(String pwd) {
this.pwd = pwd;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public String getHp1() {
return hp1;
}

public void setHp1(String hp1) {
this.hp1 = hp1;
}

public String getHp2() {
return hp2;
}

public void setHp2(String hp2) {
this.hp2 = hp2;
}

public String getHp3() {
return hp3;
}

public void setHp3(String hp3) {
this.hp3 = hp3;
}

public String getPost() {
return post;
}

public void setPost(String post) {
this.post = post;
}

public String getAddr1() {
return addr1;
}

public void setAddr1(String addr1) {
this.addr1 = addr1;
}

public String getAddr2() {
return addr2;
}

public void setAddr2(String addr2) {
this.addr2 = addr2;
}

public java.sql.Date getIndate() {
return indate;
}

public void setIndate(java.sql.Date indate) {
this.indate = indate;
}

public int getMileage() {
return mileage;
}

public void setMileage(int mileage) {
this.mileage = mileage;
}

public int getMstate() {
return mstate;
}

public void setMstate(int mstate) {
this.mstate = mstate;
}

// 연락처를 하나로 합침
public String getAllHp(){
return hp1+"-"+hp2+"-"+hp3;
}

// 주소도 하나로 합침
public String getAllAddr(){
return addr1+" "+addr2;
}


//toString() 오버라이드

@Override
public String toString() {
return "MemberVO [idx=" + idx + ", name=" + name + ", userid=" + userid + ", pwd=" + pwd + ", email=" + email
+ ", hp1=" + hp1 + ", hp2=" + hp2 + ", hp3=" + hp3 + ", post=" + post + ", addr1=" + addr1 + ", addr2="
+ addr2 + ", indate=" + indate + ", mileage=" + mileage + ", mstate=" + mstate + "]";
}

}


3. MemberDAO 클래스의 insertMember 메소드

public int insertMember(MemberVO user) throws SQLException{
try {
con=DBUtil.getCon();
String sql="INSERT INTO MEMBER(idx,name,userid,email,pwd,hp1,hp2,hp3,post,addr1,addr2,indate,mileage,mstate)"
+ " values (member_idx_seq.nextval,?,?,?,?,?,?,?,?,?,?,sysdate,?,?)";
ps=con.prepareStatement(sql);

// ? 값 셋팅
ps.setString(1, user.getName());
ps.setString(2, user.getUserid());
ps.setString(3, user.getEmail());
ps.setString(4, user.getPwd());
ps.setString(5, user.getHp1());
ps.setString(6, user.getHp2());
ps.setString(7, user.getHp3());
ps.setString(8, user.getPost());
ps.setString(9, user.getAddr1());
ps.setString(10, user.getAddr2());
ps.setInt(11, user.getMileage());
ps.setInt(12, user.getMstate());

// 실행 excuteXXX()
int n = ps.executeUpdate();
return n;
} finally {
DBUtil.close(rs, ps, con);
}
}


========================================================




자 그럼 직접 한번 회원가입을 해보겠습니다.









댓글 2개: