09009
[Spring] 예제 2 - (중요) 카테고리 속성을 적용한 회원가입 구현 수정 본문
화면에 체크박스 기능 추가 - 라디오 버튼
✍registerPage.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>회원 가입</h1>
<form action="./registerProcess" method="post">
ID: <input type="text" name="user_id"><br>
PW: <input type="password" name="user_pw"><br>
nickname: <input type="text" name="nickname"><br>
gender:
<input type="radio" name="gender" value="M">남
<input type="radio" name="gender" value="F">여 <br>
취미:
<input type="checkbox">농구
<input type="checkbox">축구
<input type="checkbox">야구
<input type="checkbox">농구<br>
email: <input type="text" name="email"><br>
생년월일: <input type="date" name="birth"><br>
전화번호: <input type="text" name="phone"><br>
<button>회원가입</button>
</form>
<a href="./loginPage">로그인 페이지로 이동</a>
</body>
</html>
회원가입할 때 새로운 속성이 추가되었는데 member 테이블을 수정해야할까?
그것보다는 회원의 취미 정보를 담을 테이블을 따로 추가하는 것이 더 바람직하다.
member 테이블 수정? (x)
테이블 추가 (o)
- 다중 속성 insert하는 경우
- 제 1 정규화: 도메인이 원자값이어야 한다.
위의 사례는 취미를 등록할 수 있는 개수가 제한된다. (컬럼의 개수가 제한됨)
다중속성의 경우, 원칙적으로 한 테이블에 컬럼을 여러 개 생성하는 것이 아니라 테이블 자체를 만드는 것이 더 바람직하다.
→ 테이블을 따로 설계하고 생성해야 한다.
다중속성은 1대 다 형태로 테이블을 설계
ex) 1번 회원이 야구, 축구를 선택
위 방식으로 테이블을 설계한 후 회원가입 작업을 수행하면 두 테이블에 데이터가 insert 될 것이다.
더 좋은 방법은
테이블을 하나 더 생성하는 것이다. (카테고리 테이블)
새로운 카테고리가 추가하고 싶을 때 코드 수정을 용이하게 하기 위함이다.
테이블 설계
취미 테이블(fp_hobby)을 따로 생성하고 회원과 취미의 정보를 연결해주는 테이블(fp_member_hobby)을 생성한다.
테이블 생성
(fp_hobby_category → fp_hobby)
-- 취미 카테고리 T
DROP TABLE fp_hobby_category;
CREATE TABLE fp_hobby_category(
id NUMBER PRIMARY KEY,
name VARCHAR2(40)
);
DROP SEQUENCE fp_hobby_category_seq;
CREATE SEQUENCE fp_hobby_category_seq;
-- 회원 - 취미 연결 T
DROP TABLE fp_member_hobby;
CREATE TABLE fp_member_hobby(
id NUMBER PRIMARY KEY,
member_id NUMBER,
hobby_id NUMBER
);
DROP SEQUENCE fp_member_hobby_seq;
CREATE SEQUENCE fp_member_hobby_seq;
취미 테이블 데이터 입력 (관리자 페이지까지 만들면 입력 안해도됨)
-- 카테고리 초기화
INSERT INTO fp_hobby_category VALUES(fp_hobby_category_seq.nextval, '야구');
INSERT INTO fp_hobby_category VALUES(fp_hobby_category_seq.nextval, '축구');
INSERT INTO fp_hobby_category VALUES(fp_hobby_category_seq.nextval, '농구');
INSERT INTO fp_hobby_category VALUES(fp_hobby_category_seq.nextval, '당구');
테이블 생성을 완료하였으면 DTO부터 생성한다.
✍HobbyCategoryDto (fp_hobby 테이블에 관한 DTO)
package com.ja.finalproject.dto;
public class HobbyCategoryDto {
private int id;
private String name;
public HobbyCategoryDto() {
super();
}
public HobbyCategoryDto(int id, String name) {
super();
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
✍ MemberHobbyDto (fp_member_hobby 테이블에 관한 DTO)
package com.ja.finalproject.dto;
public class MemberHobbyDto {
private int id;
private int member_id;
private int hobby_id;
public MemberHobbyDto() {
super();
}
public MemberHobbyDto(int id, int member_id, int hobby_id) {
super();
this.id = id;
this.member_id = member_id;
this.hobby_id = hobby_id;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getMember_id() {
return member_id;
}
public void setMember_id(int member_id) {
this.member_id = member_id;
}
public int getHobby_id() {
return hobby_id;
}
public void setHobby_id(int hobby_id) {
this.hobby_id = hobby_id;
}
}
회원가입 페이지에서 취미 체크박스 항목이 있는 화면이 출력될 수 있도록
쿼리를 제작하고 mapper를 수정해주어야 한다.
ex) 회원가입 페이지에서 취미 항목을 선택할 수 있는 화면이 보여야 한다. - 반환형은 List로 적용
그리고 DB에서 취미 테이블에 카테고리를 추가될 때마다
화면에서도 항목이 추가된 것이 적용될 수 있도록 설계할 것이다. - c:foreach문 적용
✍ MemberSqlMapper
// 취미 관련
public List<HobbyCategoryDto> selectHobbyList();
✍MemberSqlMapper.xml
회원가입 화면에 있는 취미 체크박스 항목에 취미 카테고리 여러 개가 출력될 수 있도록 쿼리를 작성한다.
<!-- 취미 관련 -->
<select id="selectHobbyList" resultType="com.ja.finalproject.dto.HobbyCategoryDto">
SELECT * FROM fp_hobby_category ORDER BY id ASC
</select>
DB 테스트
✍ MemberServiceImpl
public List<HobbyCategoryDto> getHobbyList() {
return memberSqlMapper.selectHobbyList();
}
✍ MemberController
기존 메서드 수정
@RequestMapping("registerPage")
public String registerPage(Model model) {
// List<HobbyCategoryDto> list = memberService.getHobbyList();
// model.addAttribute("hobbyList", list);
model.addAttribute("hobbyList", memberService.getHobbyList());
return "member/registerPage";
}
jstl 코드 추가
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
✍ registerPage.jsp 수정
아래 코드 추가
취미:
<c:forEach items="${hobbyList}" var="hobby">
<input type="checkbox"> ${hobby.name}
</c:forEach>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>회원 가입</h1>
<form action="./registerProcess" method="post">
ID: <input type="text" name="user_id"><br>
PW: <input type="password" name="user_pw"><br>
nickname: <input type="text" name="nickname"><br>
gender:
<input type="radio" name="gender" value="M">남
<input type="radio" name="gender" value="F">여 <br>
취미:
<c:forEach items="${hobbyList}" var="hobby">
<input type="checkbox"> ${hobby.name}
</c:forEach>
<br>
email: <input type="text" name="email"><br>
생년월일: <input type="date" name="birth"><br>
전화번호: <input type="text" name="phone"><br>
<button>회원가입</button>
</form>
<a href="./loginPage">로그인 페이지로 이동</a>
</body>
</html>
COMMIT 후 실행
클라이언트에서 작성한 파라미터를 어떻게 서버에 전송해야 할까?
일단 dto로 파라미터를 받지 않고 name 속성을 추가하여 이용한다.
✍ registerPage.jsp
수정
취미:
<c:forEach items="${hobbyList}" var="hobby">
<input type="checkbox" name="hobby_id" value="${hobby.id}"> ${hobby.name}
</c:forEach>
checkbox의 특징
페이지 소스를 확인하면 name 속성의 이름이 같은 것이 여러 개 존재한다는 것을 확인할 수 있다.
get 방식으로 변경하고 웹을 실행시키고 아래 쿼리스트링을 확인해보면 아래와 같이 나온다.
위와 같이 파라미터가 전송된다.
체크박스에서 항목을 체크한 것만큼 데이터가 전송되는 것이다.
체크박스에서 항목을 여러 개 체크할 수 있기 때문에 hobby_id를 String이 아닌 list로 받아야 한다.
체크박스의 경우, 같은 name으로 여러 개의 값이 전송될 수 있으므로
받는 쪽에서도 여러 개의 값을 받아야 한다 → 반환형을 list 계열로 선언한다.
테스트 코드
INSERT INTO fp_member_hobby VALUES(
fp_member_hobby_seq.nextval,
1,
3
);
✍MemberSqlMapper
// 취미 등록
// 파라미터 두개 -> dto로 묶는다
public void insertMemberHobby(MemberHobbyDto memberHobbyDto);
✍ MemberSqlMapper.xml
<insert id="insertMemberHobby">
INSERT INTO fp_member_hobby VALUES(
fp_member_hobby_seq.nextval,
#{member_id},
#{hobby_id}
)
</insert>
hobby도 insert 해야 한다.
(중요)
로그인한 상태가 아니지만 회원가입 페이지에서 데이터를 insert하려할 때, 회원번호가 필요한 문제가 발생한다.
글쓰기하였을 때는 세션에 회원번호가 저장되어 있는데 회원가입의 경우는 그렇지 않다.
dual
dual: 아무 의미없는 테이블
SELECT fp_member_seq.nextval FROM dual;
위의 쿼리를 실행할 때마다 번호가 올라감
✍ MemberSqlMapper
// primary key를 생성하는 쿼리 -> insert할때마다 넣는 것이 좋음
// 두 개의 테이블에 동시에 INSERT할때 필요
public int createPk();
✍MemberSqlMapper.xml
<select id="createPk" resultType="int">
SELECT fp_member_seq.nextval FROM dual
</select>
그리고 insert 쿼리 시퀀스 부분을 아래와 같이 변경한다.
<insert id="insert">
INSERT INTO fp_member VALUES(
#{id},
#{user_id},
#{user_pw},
#{nickname},
#{gender},
#{email},
#{birth},
#{phone},
SYSDATE
)
</insert>
✍ MemberServiceImpl
메서드 수정
public void register(MemberDto memberDto, int[] hobby_id) {
System.out.println("여기서 알고리즘 수행");
int memberPk = memberSqlMapper.createPk(); // primary key 생성, nextval이 실행된다.
// ! 중요 !
memberDto.setId(memberPk); // 파라미터로 안받기 때문에 SET으로 해주어야함.
memberSqlMapper.insert(memberDto);
if(hobby_id != null) {
for(int hobbyId : hobby_id) {
MemberHobbyDto memberHobbyDto = new MemberHobbyDto();
memberHobbyDto.setHobby_id(hobbyId);
memberHobbyDto.setMember_id(memberPk);
memberSqlMapper.insertMemberHobby(memberHobbyDto);
}
}
}
✍ MemberController
수정
@RequestMapping("registerProcess")
public String registerProcess(MemberDto params, int[] hobby_id) {
System.out.println("registerProcess called");
System.out.println(params.getId());
System.out.println(params.getUser_id());
System.out.println(params.getNickname());
memberService.register(params, hobby_id);
return "member/registerComplete";
}
'Back-End > Spring' 카테고리의 다른 글
[Spring] 예제 2 - html escape (0) | 2023.05.22 |
---|---|
[Spring] 예제 2 - 페이징 처리 (0) | 2023.05.22 |
[Spring] 예제 2 (예제 1에서 기능 추가) (0) | 2023.05.22 |
[Spring] 예제 1 연습 - 게시글 수정 및 삭제 (0) | 2023.05.21 |
[Spring] 예제 1 연습 - 게시글 상세보기 (0) | 2023.05.21 |