day33 - 0908
회원 관련 기능
- 회원 가입 : 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";
}
}
}