Luver Duck 2022. 9. 8. 00:38

회원 관련 기능 

- 회원 가입 : day29 - 0902

- 회원 목록 : day32 - 0907

- 회원 상세 정보 : day32 - 0907

 

준비

- MEMBER 테이블 생성

 - 회원 아이디 : member_id, 5 ~ 20자 영문 소문자, 숫자와 특수기호(_), (-)만 사용 가능
 - 회원 비밀번호 : member_pw, 8~16자 영문 대 소문자, 숫자, 특수문자(!, @, #, $)를 각각 1개 이상 사용
 - 닉네임 : member_nick, 한글로 시작하며 한글 or 숫자 가능, 총 10자 이내
 - 생년월일 : member_birth, YYYY-MM-DD, 날짜 형식
 - 전화번호 : member_tel, 대시 제외하고 010XXXXXXXX 형태
 - 이메일 : member_email, 100byte 이내, @ 반드시 포함
 - 주소
    - 우편 주소 : member_post, 5 ~ 6자리
    - 기본 주소 : member_base_address, 한글 50자
    - 상세 주소 : member_detail_address, 한글 50자
 - 포인트 : member_point, 0 이상 설정
 - 등급 : member_grade, 일반, VIP, 관리자 중 하나
 - 가입일시 : member_join, 날짜이며 현재 시간으로 자동 설정
 - 접속일시 : member_login, 로그인 할 때의 시간으로 자동 설정
 ** 회원 아이디가 기본키
 ** 전화번호, 이메일, 주소는 선택 입력 가능
 ** 접속일시는 가입시 설정하지 않음

 

-- 테이블 생성
create table member(
member_id varchar2(20) primary key
check(regexp_like(member_id, '^[a-z0-9-_]{5,20}$')),
member_pw varchar2(16) not null check(
					regexp_like(member_pw, '^[a-zA-Z0-9!@#$]{8,16}$')
					and
					regexp_like(member_pw, '[a-z]')
					and
					regexp_like(member_pw, '[A-Z]')
					and
					regexp_like(member_pw, '[0-9]')
					and
					regexp_like(member_pw, '[!@#$]')
					),
member_nick varchar2(30) not null unique check(regexp_like(member_nick, '^[가-힣][가-힣0-9]{0,9}$')),
member_birth date not null,
member_tel char(11) check(regexp_like(member_tel, '^010[0-9]{8}$')),
member_email varchar2(100) check(regexp_like(member_email, '@')),
member_post varchar2(6) check(regexp_like(member_post, '^[0-9]{5,6}$')),
member_base_address varchar2(150),
member_detail_address varchar2(150),
member_point number default 0 not null check(member_point >= 0),
member_grade varchar2(9) default '일반' not null check(member_grade in ('일반', 'VIP', '관리자')),
member_join date default sysdate not null,
member_login date
);

 

 

- Model이 될 클래스 정의 (DTO 또는 VO)

package com.kh.springhome.entity;

import java.sql.Date;
 
public class MemberDto {

	// 필드
	private String memberId;
	private String memberPw;
	private String memberNick;
	private Date memberBirth;
	private String memberTel;
	private String memberEmail;
	private String memberPost;
	private String memberBaseAddress;
	private String memberDetailAddress;
	private int memberPoint;
	private String memberGrade;
	private Date memberJoin;
	private Date memberLogin;
	
	// 생성자
	public MemberDto() {
		super();
	}
	
	// getter & setter
	public String getMemberId() {
		return memberId;
	}
	public void setMemberId(String memberId) {
		this.memberId = memberId;
	}
	public String getMemberPw() {
		return memberPw;
	}
	public void setMemberPw(String memberPw) {
		this.memberPw = memberPw;
	}
	public String getMemberNick() {
		return memberNick;
	}
	public void setMemberNick(String memberNick) {
		this.memberNick = memberNick;
	}
	public Date getMemberBirth() {
		return memberBirth;
	}
	public void setMemberBirth(Date memberBirth) {
		this.memberBirth = memberBirth;
	}
	public String getMemberTel() {
		return memberTel;
	}
	public void setMemberTel(String memberTel) {
		this.memberTel = memberTel;
	}
	public String getMemberEmail() {
		return memberEmail;
	}
	public void setMemberEmail(String memberEmail) {
		this.memberEmail = memberEmail;
	}
	public String getMemberPost() {
		return memberPost;
	}
	public void setMemberPost(String memberPost) {
		this.memberPost = memberPost;
	}
	public String getMemberBaseAddress() {
		return memberBaseAddress;
	}
	public void setMemberBaseAddress(String memberBaseAddress) {
		this.memberBaseAddress = memberBaseAddress;
	}
	public String getMemberDetailAddress() {
		return memberDetailAddress;
	}
	public void setMemberDetailAddress(String memberDetailAddress) {
		this.memberDetailAddress = memberDetailAddress;
	}
	public int getMemberPoint() {
		return memberPoint;
	}
	public void setMemberPoint(int memberPoint) {
		this.memberPoint = memberPoint;
	}
	public String getMemberGrade() {
		return memberGrade;
	}
	public void setMemberGrade(String memberGrade) {
		this.memberGrade = memberGrade;
	}
	public Date getMemberJoin() {
		return memberJoin;
	}
	public void setMemberJoin(Date memberJoin) {
		this.memberJoin = memberJoin;
	}
	public Date getMemberLogin() {
		return memberLogin;
	}
	public void setMemberLogin(Date memberLogin) {
		this.memberLogin = memberLogin;
	}

	// toString 오버라이딩 - memberPw(비밀번호)는 보안을 위해 제외할 것
	@Override
	public String toString() {
		return "MemberDto [memberId=" + memberId 
 					+ ", memberNick=" + memberNick
 					+ ", memberBirth=" + memberBirth 
 					+ ", memberTel=" + memberTel 
 					+ ", memberEmail=" + memberEmail
 					+ ", memberPost=" + memberPost 
 					+ ", memberBaseAddress=" + memberBaseAddress 
 					+ ", memberDetailAddress=" + memberDetailAddress 
 					+ ", memberPoint=" + memberPoint 
 					+ ", memberGrade=" + memberGrade
 					+ ", memberJoin=" + memberJoin 
 					+ ", memberLogin=" + memberLogin + "]";
	}
}

 

회원 정보 수정 (관리자 기능)

- 회원 정보를 수정하기 위해서는 기존 회원 정보를 알아야 하므로 가장 먼저 회원의 아이디로 단일 조회를 해야 한다

- 단일 조회의 결과인 DTO를 model에 첨부하며 View에서 <form>태그로 표시한다

- <form> 태그의 <input>에 새로운 값이 입력된 DTO를 ModelAttribute로 받아 회원 정보를 수정한다

- 수정할 수 없는 회원 정보가 있다

  1) 회원 아이디(memberId), 생년월일(memberBirth), 회원 가입일(memberJoin)은 수정할 수 없다

  2) 포인트(memberPoint), 회원 등급(memberGrade)는 관리자가 수정해야 할 항목이다

  3) 마지막 로그인(memberLogin)은 로그인할 때만 갱신되어야 한다

 

MemberDao

- 회원 정보 수정의 결과로 수정 여부(boolean)을 반환한다

public interface MemberDao {
 
	// 추상 메소드 - 회원 정보 수정(관리자 기능)
	boolean update(MemberDto memberDto);
}

 

MemberDaoImpl

@Repository
public class MemberDaoImpl implements MemberDao {

	// 의존성 주입
	@Autowired
	private JdbcTemplate jdbcTemplate;
	
	// 추상 메소드 오버라이딩 - 회원 정보 수정
	@Override
	public boolean update(MemberDto memberDto) {
		String sql = "update member set member_pw = ?, "
						+ "member_nick = ?, "
						+ "member_tel = ?, "
						+ "member_email = ?, "
						+ "member_post = ?, "
						+ "member_base_address = ?, "
						+ "member_detail_address = ?, "
						+ "member_point = ?, "
						+ "member_grade = ? "
					+ "where member_id = ?";
		Object[] param = new Object[] {
						memberDto.getMemberPw(), 
						memberDto.getMemberNick(), 
						memberDto.getMemberTel(), 
						memberDto.getMemberEmail(), 
						memberDto.getMemberPost(), 
						memberDto.getMemberBaseAddress(), 
						memberDto.getMemberDetailAddress(), 
						memberDto.getMemberPoint(), 
						memberDto.getMemberGrade(), 
						memberDto.getMemberId()
						};
		return jdbcTemplate.update(sql, param) > 0;
	}
}

 

MemberController

@Controller
@RequestMapping("/member")
public class MemberController {

	// 의존성 주입
	@Autowired
	private MemberDao memberDao;
	
	// 4. 회원 정보 수정
	// 4-1. 회원 정보 수정 Mapping
	@GetMapping("/edit")
	public String edit(Model model, @RequestParam String memberId) {
		// model에 단일 조회 selectOne(String memberId)의 결과를 첨부
		model.addAttribute("memberDto", memberDao.selectOne(memberId));
		// 회원 정보 수정 페이지(edit.jsp)로 연결
		// return "/WEB-INF/views/member/edit.jsp";
		return "member/edit";
	}
	
	// 4-2. 회원 정보 수정 Mapping에 DTO 전달 및 DB 처리 
	@PostMapping("/edit")
	public String edit(@ModelAttribute MemberDto memberDto, RedirectAttributes attr) {
		// DB에서 수정(UPDATE) 결과(boolean, 실행 결과가 0보다 큰지)에 따라 서로 다른 Mapping으로 이동
		if(memberDao.update(memberDto)) {	// true라면 해당 아이디(memberId) 회원의 단일 조회 Mapping으로 이동
			// RedirectAttributes : redirect할 때 해당 경로 뒤에 붙을 변수명과 그 값을 추가
			attr.addAttribute("memberId", memberDto.getMemberId());
			return "redirect:detail";
		}
		else {	// false라면 회원 정보 수정 실패(edit_fail) Mapping으로 강제 이동(redirect)
			return "redirect:edit_fail";
		}
	}
	
	// 4-3. 회원 정보 수정 실패 Mapping
	@GetMapping("/edit_fail")
	public String editFail() {
		// 수정 실패 페이지(editFail.jsp)으로 이동
		return "member/editFail";
	}
}

 

edit.jsp

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

<html>
<head>
<meta charset="UTF-8">
<title>회원 정보 수정</title>
</head>
<body>

<div align = "center">

<h1>회원 정보 수정</h1>

<form action = "edit" method = "post">
	<input type = "hidden" name = "memberId" value = "${memberDto.getMemberId()}">
	비밀번호 : <input type = "password" name = "memberPw" value = "${memberDto.getMemberPw()}"><br><br>
	닉네임 : <input type = "text" name = "memberNick" value = "${memberDto.getMemberNick()}"><br><br>
	전화번호 : <input type = "text" name = "memberTel" value = "${memberDto.getMemberTel()}"><br><br>
	이메일 : <input type = "text" name = "memberEmail" value = "${memberDto.getMemberEmail()}"><br><br>
	우편번호 : <input type = "text" name = "memberPost" value = "${memberDto.getMemberPost()}"><br><br>
	기본주소 : <input type = "text" name = "memberBaseAddress" value = "${memberDto.getMemberBaseAddress()}"><br><br>
	상세주소 : <input type = "text" name = "memberDetailAddress" value = "${memberDto.getMemberDetailAddress()}"><br><br>
	포인트 : <input type = "text" name = "memberPoint" value = "${memberDto.getMemberPoint()}"><br><br>
	<button type = "submit">변경</button>
</form>

</div>

</body>
</html>

 

- model에는 단일 조회의 결과인 MemberDto 형태의 memberDto가 첨부되어 있다

- <input>의 value의 값으로 memberDto 각 필드의 getter값으로 하면 Veiw에서 그 값이 미리 입력되어 화면이 출력된다

- jsp에서 입력한 <form> 데이터를 "/edit" Mapping에 "POST" 방식으로 전송한다

  <form>의 action 속성은 <form> 데이터를 보낼 Mapping을 의미한다

  <form>의 method 속성은 <form> 데이터를 보낼 때 그 방식(POST/GET)을 의미한다

 

회원 탈퇴 (관리자 기능)

- 회원 탈퇴는 해당 회원의 아이디를 입력받아 회원 테이블에서 삭제(DELETE)를 수행하도록 한다

- 회원 탈퇴 후 따로 회원 탈퇴 결과 페이지를 만들지 않을 것이라면 jsp는 필요없다

 

memberDao

public interface MemberDao {
 
	// 추상 메소드 - 회원 탈퇴(관리자 기능)
	boolean delete(String memberId);
}

 

memberDaoImpl

@Repository
public class MemberDaoImpl implements MemberDao {

	// 의존성 주입
	@Autowired
	private JdbcTemplate jdbcTemplate;
	
	// 추상 메소드 오버라이딩 - 회원 탈퇴(관리자 기능)
	@Override
	public boolean delete(String memberId) {
		String sql = "delete member where member_id = ?";
		return jdbcTemplate.update(sql, memberId) > 0;
	}
}

 

memberController

@Controller
@RequestMapping("/member")
public class MemberController {

	// 의존성 주입
	@Autowired
	private MemberDao memberDao;

	// 5. 회원 탈퇴
	// 회원 탈퇴 Mapping
	@GetMapping("/delete")
	public String delete(@RequestParam String memberId) {
		// DB에서 삭제(DELETE) 결과(boolean, 실행 결과가 0보다 큰지)에 따라 서로 다른 Mapping으로 이동
		if(memberDao.delete(memberId)) {	// true라면 회원 목록 Mapping으로 강제 이동(redirect)
			return "redirect:list";
		}
		else {	// false라면 회원 수정 실패 Mapping으로 이동
			return "member/editFail";
		}
	}
}