관리 메뉴

거니의 velog

(5) 도서 쇼핑몰 만들기 5 본문

Java_Spring mini project 쇼핑몰

(5) 도서 쇼핑몰 만들기 5

Unlimited00 2023. 11. 24. 17:21

6. 로그인과 회원 가입하기

* 이번에는 모든 애플리케이션에서 사용하는 로그인 기능과 회원 가입 기능을 구현해 보자.


(1) 회원 정보 저장 테이블 생성하기

* 다음은 회원 가입 시 회원 정보가 저장되는 테이블의 논리적 구조와 물리적 구조이다.

* 먼저 로그인 기능부터 구현해 보자.


(2) 로그인 기능 구현하기

1. 로그인과 회원 가입 기능을 구현하기 위한 SQL문을 member.xml에 작성한다.

<?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="mapper.member">
	<!-- 회원 정보를 저장할 resultMap을 정의한다. -->
	<resultMap id="memberResult" type="MemberVO">
		<result property="member_id" column="member_id" />
		<result property="member_pw" column="member_pw" />
		<result property="member_name" column="member_name" />
		<result property="member_gender" column="member_gender" />
		
		<result property="member_birth_y" column="member_birth_y" />
		<result property="member_birth_m" column="member_birth_m" />
		<result property="member_birth_d" column="member_birth_d" />
		
		<result property="member_birth_gn" column="member_birth_gn" />
		<result property="tel1" column="tel1" />
		<result property="tel2" column="tel2" />
		<result property="tel3" column="tel3" />
		
		<result property="hp1" column="hp1" />
		<result property="hp2" column="hp2" />
		<result property="hp3" column="hp3" />
		<result property="smssts_yn" column="smssts_yn" />
		<result property="email1" column="email1" />
		<result property="email2" column="email2" />
		<result property="emailsts_yn" column="emailsts_yn" />
		
		<result property="zipcode" column="zipcode" />
		<result property="roadAddress" column="roadAddress" />
		<result property="jibunAddress" column="jibunAddress" />
		<result property="namujiAddress" column="namujiAddress" />
		<result property="joinDate" column="joinDate" />
	</resultMap>	

	<select id="login" resultType="memberVO"  parameterType="java.util.Map"  >
	    <![CDATA[
			select * from t_shopping_member 
			 where member_id=#{member_id}
			 and member_pw=#{member_pw}			
			 
		]]>
	</select>
	
	<select id="selectOverlappedID" parameterType="String" resultType="String">
	   select decode(count(*),1, 'true', 0, 'false')
	   from t_shopping_member
	   where member_id = #{id}
	</select>
	
  <insert id="insertNewMember"  parameterType="memberVO">
  <![CDATA[
    	insert into t_shopping_member(member_id,
				 					                  member_pw,
                                     member_name,
                                     member_gender,
                                     member_birth_y,
                                     member_birth_m,
                                     member_birth_d,
                                     member_birth_gn,
                                     tel1,
                                     tel2,
                                     tel3,
                                     hp1,
                                     hp2,
                                     hp3,
                                     smssts_yn,
                                     email1,
                                     email2,
                                     emailsts_yn,
                                     zipcode,
                                     roadAddress,
                                     jibunAddress,
                                     namujiAddress)
							 values(#{member_id},
									#{member_pw},
									#{member_name},
                                 	#{member_gender},
                                   	#{member_birth_y},
                                   	#{member_birth_m},
                                    #{member_birth_d},
                                    #{member_birth_gn},
                                    #{tel1},
                                    #{tel2},
                                    #{tel3},
                                    #{hp1},
                                    #{hp2},
                                    #{hp3},
                                    #{smssts_yn},
                                    #{email1},
                                    #{email2},
                                    #{emailsts_yn},
                                    #{zipcode},
                                    #{roadAddress},
                                    #{jibunAddress},
                                    #{namujiAddress})
                                  
                                      
   ]]>      
  </insert>
</mapper>

2. 로그인 및 회원 가입과 관련된 자바 클래스를 다음과 같이 준비한다.

3. 로그인창에서 전송된 ID와 비밀번호를 Map에 담아 SQL문으로 전달한다. 로그인하지 않은 상태에서 상품을 주문할 경우 로그인창으로 이동하면서 action 값으로 상품 주문 페이지 요청 URL을 저장하여 세션에 바인딩한다. 그리고 로그인 후 다시 action 값을 가져와 상품 주문 페이지로 이동하도록 설정한다.

[MemberControllerImpl.java]

package com.bookshop01.member.controller;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.bookshop01.common.base.BaseController;
import com.bookshop01.member.service.MemberService;
import com.bookshop01.member.vo.MemberVO;

@Controller("memberController")
@RequestMapping(value = "/member")
public class MemberControllerImpl extends BaseController implements MemberController {
	@Autowired
	private MemberService memberService;
	@Autowired
	private MemberVO memberVO;

	@Override
	@RequestMapping(value = "/login.do", method = RequestMethod.POST)
	public ModelAndView login(@RequestParam Map<String, String> loginMap, // ID와 비밀번호를 Map에 저장한다.
			HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		
		ModelAndView mav = new ModelAndView();
		memberVO = memberService.login(loginMap); // SQL문으로 전달한다.
		
		if (memberVO != null && memberVO.getMember_id() != null) {
			HttpSession session = request.getSession();
			session = request.getSession();
			session.setAttribute("isLogOn", true);
			session.setAttribute("memberInfo", memberVO); // 조회한 회원 정보를 가져와 isLogOn 속성을 true로 설정하고 memberInfo 속성으로 회원 정보를 저장한다.

			String action = (String) session.getAttribute("action");
			if (action != null && action.equals("/order/orderEachGoods.do")) {
				mav.setViewName("forward:" + action);
			} else {
				mav.setViewName("redirect:/main/main.do");
			} // 상품 주문 과정에서 로그인했으면 로그인 후 다시 주문 화면으로 진행하고 그 외에는 메인 페이지를 표시한다.

		} else {
			String message = "아이디나  비밀번호가 틀립니다. 다시 로그인해주세요";
			mav.addObject("message", message);
			mav.setViewName("/member/loginForm");
		}
		
		return mav;
		
	}

	@Override
	@RequestMapping(value = "/logout.do", method = RequestMethod.GET)
	public ModelAndView logout(HttpServletRequest request, HttpServletResponse response) throws Exception {
		ModelAndView mav = new ModelAndView();
		HttpSession session = request.getSession();
		session.setAttribute("isLogOn", false);
		session.removeAttribute("memberInfo");
		mav.setViewName("redirect:/main/main.do");
		return mav;
	}

	@Override
	@RequestMapping(value = "/addMember.do", method = RequestMethod.POST)
	public ResponseEntity addMember(@ModelAttribute("memberVO") MemberVO _memberVO, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		response.setContentType("text/html; charset=UTF-8");
		request.setCharacterEncoding("utf-8");
		String message = null;
		ResponseEntity resEntity = null;
		HttpHeaders responseHeaders = new HttpHeaders();
		responseHeaders.add("Content-Type", "text/html; charset=utf-8");
		try {
			memberService.addMember(_memberVO);
			message = "<script>";
			message += " alert('회원 가입을 마쳤습니다.로그인창으로 이동합니다.');";
			message += " location.href='" + request.getContextPath() + "/member/loginForm.do';";
			message += " </script>";

		} catch (Exception e) {
			message = "<script>";
			message += " alert('작업 중 오류가 발생했습니다. 다시 시도해 주세요');";
			message += " location.href='" + request.getContextPath() + "/member/memberForm.do';";
			message += " </script>";
			e.printStackTrace();
		}
		resEntity = new ResponseEntity(message, responseHeaders, HttpStatus.OK);
		return resEntity;
	}

	@Override
	@RequestMapping(value = "/overlapped.do", method = RequestMethod.POST)
	public ResponseEntity overlapped(@RequestParam("id") String id, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		ResponseEntity resEntity = null;
		String result = memberService.overlapped(id); // id 중복 검사를 한다.
		resEntity = new ResponseEntity(result, HttpStatus.OK);
		return resEntity;
	}
}

4. Service 클래스와 DAO 클래스는 다음과 같다.

package com.bookshop01.member.service;

import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.bookshop01.member.dao.MemberDAO;
import com.bookshop01.member.vo.MemberVO;

@Service("memberService")
@Transactional(propagation = Propagation.REQUIRED)
public class MemberServiceImpl implements MemberService {
	@Autowired
	private MemberDAO memberDAO;

	@Override
	public MemberVO login(Map loginMap) throws Exception {
		return memberDAO.login(loginMap);
	}

	@Override
	public void addMember(MemberVO memberVO) throws Exception {
		memberDAO.insertNewMember(memberVO);
	}

	@Override
	public String overlapped(String id) throws Exception {
		return memberDAO.selectOverlappedID(id);
	}
}
package com.bookshop01.member.dao;

import java.util.HashMap;
import java.util.Map;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Repository;
import com.bookshop01.member.vo.MemberVO;

@Repository("memberDAO")
public class MemberDAOImpl implements MemberDAO {
	@Autowired
	private SqlSession sqlSession;

	@Override
	public MemberVO login(Map loginMap) throws DataAccessException {
		MemberVO member = (MemberVO) sqlSession.selectOne("mapper.member.login", loginMap);
		return member;
	}

	@Override
	public void insertNewMember(MemberVO memberVO) throws DataAccessException {
		sqlSession.insert("mapper.member.insertNewMember", memberVO);
	}

	@Override
	public String selectOverlappedID(String id) throws DataAccessException {
		String result = sqlSession.selectOne("mapper.member.selectOverlappedID", id);
		return result;
	}

}

5. header.jsp에서는 로그인 상태에서는 '로그아웃'이, 로그아웃 상태에서는 '로그인'이 표시되도록 한다.

    <div id="head_link">
        <ul>
        	<%-- 로그인 시 '로그아웃'을 표시한다. --%>
            <c:choose>
                <c:when test="${isLogOn==true and not empty memberInfo }">
                    <li><a href="${contextPath}/member/logout.do">로그아웃</a></li>
                    <li><a href="${contextPath}/mypage/myPageMain.do">마이페이지</a></li>
                    <li><a href="${contextPath}/cart/myCartList.do">장바구니</a></li>
                    <li><a href="#">주문배송</a></li>
                </c:when>
                <%-- 로그아웃 시 '로그인'을 표시한다. --%>
                <c:otherwise>
                    <li><a href="${contextPath}/member/loginForm.do">로그인</a></li>
                    <li><a href="${contextPath}/member/memberForm.do">회원가입</a></li>
                </c:otherwise>
            </c:choose>
            <li><a href="#">고객센터</a></li>
            <%-- 관리자로 로그인 시 '관리자'를 표시한다. --%>
            <c:if test="${isLogOn==true and memberInfo.member_id =='admin' }">
                <li class="no_line"><a href="${contextPath}/admin/goods/adminGoodsMain.do">관리자</a></li>
            </c:if>

        </ul>
    </div>

6. 다음은 실행 결과이다. 상단 메뉴의 로그인을 클릭하고 로그인 창에서 ID와 비밀번호를 입력한 후 하단에 있는 로그인을 클릭한다.

- http://localhost/bookshop01/member/loginForm.do

7. 로그인에 성공하면 상단 메뉴에 '로그아웃'과 '마이페이지'항목이 표시된다.

8. 로그아웃을 클릭하면 다시 '로그인'이 표시된다.


(3) 회원 가입 기능 구현하기

* 이번에는 회원 가입 기능을 구현할 차례이다.

1. member.xml을 다음과 같이 작성한다.

	<!-- 회원 가입 시 입력한 ID로 ID 중복 검사를 한다. -->
	<select id="selectOverlappedID" parameterType="String"
		resultType="String">
		select decode(count(*),1, 'true', 0, 'false')
		from t_shopping_member
		where member_id = #{id}
	</select>

	<!-- 회원 가입 창에서 입력한 회원 정보를 테이블에 추가한다. -->
	<insert id="insertNewMember" parameterType="memberVO">
  	<![CDATA[
    	insert into t_shopping_member(member_id,
				 					                  member_pw,
                                     member_name,
                                     member_gender,
                                     member_birth_y,
                                     member_birth_m,
                                     member_birth_d,
                                     member_birth_gn,
                                     tel1,
                                     tel2,
                                     tel3,
                                     hp1,
                                     hp2,
                                     hp3,
                                     smssts_yn,
                                     email1,
                                     email2,
                                     emailsts_yn,
                                     zipcode,
                                     roadAddress,
                                     jibunAddress,
                                     namujiAddress)
							 values(#{member_id},
									#{member_pw},
									#{member_name},
                                 	#{member_gender},
                                   	#{member_birth_y},
                                   	#{member_birth_m},
                                    #{member_birth_d},
                                    #{member_birth_gn},
                                    #{tel1},
                                    #{tel2},
                                    #{tel3},
                                    #{hp1},
                                    #{hp2},
                                    #{hp3},
                                    #{smssts_yn},
                                    #{email1},
                                    #{email2},
                                    #{emailsts_yn},
                                    #{zipcode},
                                    #{roadAddress},
                                    #{jibunAddress},
                                    #{namujiAddress})
                                  
                                      
   	]]>
	</insert>

2. MemberControllerImpl 클래스를 다음과 같이 구현한다.

	@Override
	@RequestMapping(value = "/addMember.do", method = RequestMethod.POST)
	public ResponseEntity addMember(@ModelAttribute("memberVO") MemberVO _memberVO, // 회원 가입창에서 전송된 회원 정보를 _memberVO에 설정한다.
			HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		
		response.setContentType("text/html; charset=UTF-8");
		request.setCharacterEncoding("utf-8");
		String message = null;
		ResponseEntity resEntity = null;
		HttpHeaders responseHeaders = new HttpHeaders();
		responseHeaders.add("Content-Type", "text/html; charset=utf-8");
		
		try {
			memberService.addMember(_memberVO); // 회원 정보를 SQL문으로 전달한다.
			message = "<script>";
			message += " alert('회원 가입을 마쳤습니다.로그인창으로 이동합니다.');";
			message += " location.href='" + request.getContextPath() + "/member/loginForm.do';";
			message += " </script>";

		} catch (Exception e) {
			message = "<script>";
			message += " alert('작업 중 오류가 발생했습니다. 다시 시도해 주세요');";
			message += " location.href='" + request.getContextPath() + "/member/memberForm.do';";
			message += " </script>";
			e.printStackTrace();
		}
		
		resEntity = new ResponseEntity(message, responseHeaders, HttpStatus.OK);
		return resEntity;
		
	}
    
    ...
    
    	@Override
	@RequestMapping(value = "/overlapped.do", method = RequestMethod.POST)
	public ResponseEntity overlapped(@RequestParam("id") String id, 
			HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		
		ResponseEntity resEntity = null;
		String result = memberService.overlapped(id); // id 중복 검사를 한다.
		resEntity = new ResponseEntity(result, HttpStatus.OK);
		return resEntity;
		
	}

3. memberForm.jsp를 다음과 같이 구현한다. 회원 주소를 검색할 때는 다음(Daum)사이트에서 제공하는 우편번호 검색 API를 사용한다. 자세한 것은  http://postcode.map.daum.net/guide 를 참고 바란다.

<%@ page language="java" contentType="text/html; charset=utf-8"
	pageEncoding="utf-8"
	isELIgnored="false"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<c:set var="contextPath" value="${pageContext.request.contextPath}" />
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <!-- Daum에서 제공하는 주소 검색을 사용하기 위해 포함시킨다. -->
    <script src="http://dmaps.daum.net/map_js_init/postcode.v2.js"></script>
    <script>
        function execDaumPostcode() {
            new daum.Postcode({
                oncomplete: function(data) {
                    // 팝업에서 검색결과 항목을 클릭했을때 실행할 코드를 작성하는 부분.

                    // 도로명 주소의 노출 규칙에 따라 주소를 조합한다.
                    // 내려오는 변수가 값이 없는 경우엔 공백('')값을 가지므로, 이를 참고하여 분기 한다.
                    var fullRoadAddr = data.roadAddress; // 도로명 주소 변수
                    var extraRoadAddr = ''; // 도로명 조합형 주소 변수

                    // 법정동명이 있을 경우 추가한다. (법정리는 제외)
                    // 법정동의 경우 마지막 문자가 "동/로/가"로 끝난다.
                    if (data.bname !== '' && /[동|로|가]$/g.test(data.bname)) {
                        extraRoadAddr += data.bname;
                    }
                    // 건물명이 있고, 공동주택일 경우 추가한다.
                    if (data.buildingName !== '' && data.apartment === 'Y') {
                        extraRoadAddr += (extraRoadAddr !== '' ? ', ' + data.buildingName : data.buildingName);
                    }
                    // 도로명, 지번 조합형 주소가 있을 경우, 괄호까지 추가한 최종 문자열을 만든다.
                    if (extraRoadAddr !== '') {
                        extraRoadAddr = ' (' + extraRoadAddr + ')';
                    }
                    // 도로명, 지번 주소의 유무에 따라 해당 조합형 주소를 추가한다.
                    if (fullRoadAddr !== '') {
                        fullRoadAddr += extraRoadAddr;
                    }

                    // 우편번호와 주소 정보를 해당 필드에 넣는다.
                    document.getElementById('zipcode').value = data.zonecode; //5자리 새우편번호 사용
                    document.getElementById('roadAddress').value = fullRoadAddr;
                    document.getElementById('jibunAddress').value = data.jibunAddress;

                    // 사용자가 '선택 안함'을 클릭한 경우, 예상 주소라는 표시를 해준다.
                    if (data.autoRoadAddress) {
                        //예상되는 도로명 주소에 조합형 주소를 추가한다.
                        var expRoadAddr = data.autoRoadAddress + extraRoadAddr;
                        document.getElementById('guide').innerHTML = '(예상 도로명 주소 : ' + expRoadAddr + ')';

                    } else if (data.autoJibunAddress) {
                        var expJibunAddr = data.autoJibunAddress;
                        document.getElementById('guide').innerHTML = '(예상 지번 주소 : ' + expJibunAddr + ')';
                    } else {
                        document.getElementById('guide').innerHTML = '';
                    }


                }
            }).open();
        }

        function fn_overlapped() {
            var _id = $("#_member_id").val();
            if (_id == '') {
                alert("ID를 입력하세요");
                return;
            }
            $.ajax({
                type: "post",
                async: false,
                url: "${contextPath}/member/overlapped.do",
                dataType: "text",
                data: {
                    id: _id
                },
                success: function(data, textStatus) {
                    if (data == 'false') {
                        alert("사용할 수 있는 ID입니다.");
                        $('#btnOverlapped').prop("disabled", true);
                        $('#_member_id').prop("disabled", true);
                        $('#member_id').val(_id);
                    } else {
                        alert("사용할 수 없는 ID입니다.");
                    }
                },
                error: function(data, textStatus) {
                    alert("에러가 발생했습니다.");
                    ㅣ
                },
                complete: function(data, textStatus) {
                    //alert("작업을완료 했습니다");
                }
            }); //end ajax	 
        }
    </script>
</head>

<body>
    <h3>필수입력사항</h3>
    <form action="${contextPath}/member/addMember.do" method="post">
        <div id="detail_table">
            <table>
                <tbody>
                    <tr class="dot_line">
                        <td class="fixed_join">아이디</td>
                        <td>
                            <input type="text" name="_member_id" id="_member_id" size="20" />
                            <input type="hidden" name="member_id" id="member_id" />

                            <input type="button" id="btnOverlapped" value="중복체크" onClick="fn_overlapped()" />
                        </td>
                    </tr>
                    <tr class="dot_line">
                        <td class="fixed_join">비밀번호</td>
                        <td><input name="member_pw" type="password" size="20" /></td>
                    </tr>
                    <tr class="dot_line">
                        <td class="fixed_join">이름</td>
                        <td><input name="member_name" type="text" size="20" /></td>
                    </tr>
                    <tr class="dot_line">
                        <td class="fixed_join">성별</td>
                        <td><input type="radio" name="member_gender" value="102" />
                            여성<span style="padding-left:120px"></span>
                            <input type="radio" name="member_gender" value="101" checked />남성
                        </td>
                    </tr>
                    <tr class="dot_line">
                        <td class="fixed_join">법정생년월일</td>
                        <td>
                            <select name="member_birth_y">

                                <c:forEach var="year" begin="1" end="100">
                                    <c:choose>
                                        <c:when test="${year==80}">
                                            <option value="${ 1920+year}" selected>${ 1920+year} </option>
                                        </c:when>
                                        <c:otherwise>
                                            <option value="${ 1920+year}">${ 1920+year} </option>
                                        </c:otherwise>
                                    </c:choose>
                                </c:forEach>

                            </select>년
                            <select name="member_birth_m">
                                <c:forEach var="month" begin="1" end="12">
                                    <c:choose>
                                        <c:when test="${month==5 }">
                                            <option value="${month }" selected>${month }</option>
                                        </c:when>
                                        <c:otherwise>
                                            <option value="${month }">${month}</option>
                                        </c:otherwise>
                                    </c:choose>
                                </c:forEach>
                            </select>월
                            <select name="member_birth_d">
                                <c:forEach var="day" begin="1" end="31">
                                    <c:choose>
                                        <c:when test="${day==10 }">
                                            <option value="${day}" selected>${day}</option>
                                        </c:when>
                                        <c:otherwise>
                                            <option value="${day}">${day}</option>
                                        </c:otherwise>
                                    </c:choose>
                                </c:forEach>
                            </select>일 <span style="padding-left:50px"></span>
                            <input type="radio" name="member_birth_gn" value="2" checked />양력
                            <span style="padding-left:50px"></span>
                            <input type="radio" name="member_birth_gn" value="1" />음력
                        </td>
                    </tr>
                    <tr class="dot_line">
                        <td class="fixed_join">전화번호</td>
                        <td><select name="tel1">
                                <option>없음</option>
                                <option value="02">02</option>
                                <option value="031">031</option>
                                <option value="032">032</option>
                                <option value="033">033</option>
                                <option value="041">041</option>
                                <option value="042">042</option>
                                <option value="043">043</option>
                                <option value="044">044</option>
                                <option value="051">051</option>
                                <option value="052">052</option>
                                <option value="053">053</option>
                                <option value="054">054</option>
                                <option value="055">055</option>
                                <option value="061">061</option>
                                <option value="062">062</option>
                                <option value="063">063</option>
                                <option value="064">064</option>
                                <option value="0502">0502</option>
                                <option value="0503">0503</option>
                                <option value="0505">0505</option>
                                <option value="0506">0506</option>
                                <option value="0507">0507</option>
                                <option value="0508">0508</option>
                                <option value="070">070</option>
                            </select> - <input size="10px" type="text" name="tel2"> - <input size="10px" type="text" name="tel3">
                        </td>
                    </tr>
                    <tr class="dot_line">
                        <td class="fixed_join">휴대폰번호</td>
                        <td><select name="hp1">
                                <option>없음</option>
                                <option selected value="010">010</option>
                                <option value="011">011</option>
                                <option value="016">016</option>
                                <option value="017">017</option>
                                <option value="018">018</option>
                                <option value="019">019</option>
                            </select> - <input size="10px" type="text" name="hp2"> - <input size="10px" type="text" name="hp3"><br> <br>
                            <input type="checkbox" name="smssts_yn" value="Y" checked /> 쇼핑몰에서 발송하는 SMS 소식을 수신합니다.
                        </td>
                    </tr>
                    <tr class="dot_line">
                        <td class="fixed_join">이메일<br>(e-mail)</td>
                        <td><input size="10px" type="text" name="email1" /> @ <input size="10px" type="text" name="email2" />
                            <select name="email2" onChange="" title="직접입력">
                                <option value="non">직접입력</option>
                                <option value="hanmail.net">hanmail.net</option>
                                <option value="naver.com">naver.com</option>
                                <option value="yahoo.co.kr">yahoo.co.kr</option>
                                <option value="hotmail.com">hotmail.com</option>
                                <option value="paran.com">paran.com</option>
                                <option value="nate.com">nate.com</option>
                                <option value="google.com">google.com</option>
                                <option value="gmail.com">gmail.com</option>
                                <option value="empal.com">empal.com</option>
                                <option value="korea.com">korea.com</option>
                                <option value="freechal.com">freechal.com</option>
                            </select><br> <br> <input type="checkbox" name="emailsts_yn" value="Y" checked /> 쇼핑몰에서 발송하는 e-mail을 수신합니다.
                        </td>
                    </tr>
                    <tr class="dot_line">
                        <td class="fixed_join">주소</td>
                        <td>
                            <input type="text" id="zipcode" name="zipcode" size="10"> <a href="javascript:execDaumPostcode()">우편번호검색</a>
                            <br>
                            <p>
                                지번 주소:<br><input type="text" id="roadAddress" name="roadAddress" size="50"><br><br>
                                도로명 주소: <input type="text" id="jibunAddress" name="jibunAddress" size="50"><br><br>
                                나머지 주소: <input type="text" name="namujiAddress" size="50" />
                                <!--   <span id="guide" style="color:#999"></span> -->
                            </p>
                        </td>
                    </tr>
                </tbody>
            </table>
        </div>
        <div class="clear">
            <br><br>
            <table align=center>
                <tr>
                    <td>
                        <input type="submit" value="회원 가입">
                        <input type="reset" value="다시입력">
                    </td>
                </tr>
            </table>
        </div>
    </form>
</body>

</html>

4. 다음은 실행 결과이다. 브라우저에서 회원 가입창을 요청한 후 ID를 입력하고 중복체크를 클릭하여 사용 가능한 ID인지 확인한다. 그런 다음 회원 정보를 입력하고 우편번호 검색을 클릭한다.

- http://localhost/bookshop01/member/memberForm.do

5. '한남동'처럼 검색할 동 이름을 입력하고 엔터를 누른다.

6. 조회된 주소 목록에서 해당되는 주소를 선택한다.

7. 나머지 주소를 입력한 후 회원가입을 클릭한다.

8. 회원 가입을 제대로 마쳤으면 로그인창으로 이동하여 로그인을 시도한다.

로그인 성공!