1명의 회원이 여러 개의 카드를 가질 수 있다
-> Member 와 Card 테이블은 1:N 관계
package kr.or.ddit;
import java.util.Date;
import java.util.List;
import org.springframework.format.annotation.DateTimeFormat;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
//자바빈 클래스
//lombok사용해서 아래처럼 편하게 만들 수 있지만 POJO(초기의 순수한 자바)에 위배됨
//@Setter
//@Getter
//@ToString
public class MemberVO {
private String memberid;
private String password;
private String name;
private String email;
private String introduction; //자기소개
//pattern : date 넣을 때 요 형식으로 써주세요~
//@DateTimeFormat(pattern="yyyy-MM-dd")꼭 써줘야 date형식으로 들어간다
@DateTimeFormat(pattern="yyyy-MM-dd")
private Date regdate;
private String[] hobbyArray; //취미 방법 2
private List<String> hobbyList; //취미 방법 1
private String gender; //성별
//MemberVO : CardVO = 1 : n 의 관계
//한명의 회원이 여러 카드를 가질 수 있다.
private List<CardVO> cardList;
//기본 생성자
public MemberVO() {
super();
// TODO Auto-generated constructor stub
}
//파라미터 던져주면 멤버변수에 자동으로 세팅된다
public MemberVO(String memberid, String password, String name, String email, Date regdate) {
super();
this.memberid = memberid;
this.password = password;
this.name = name;
this.email = email;
this.regdate = regdate;
}
public String getMemberid() {
return memberid;
}
public void setMemberid(String memberid) {
this.memberid = memberid;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Date getRegdate() {
return regdate;
}
public void setRegdate(Date regdate) {
this.regdate = regdate;
}
public String getIntroduction() {
return introduction;
}
public void setIntroduction(String introduction) {
this.introduction = introduction;
}
public List<String> getHobbyList() {
return hobbyList;
}
public void setHobbyList(List<String> hobbyList) {
this.hobbyList = hobbyList;
}
public String[] getHobbyArray() {
return hobbyArray;
}
public void setHobbyArray(String[] hobbyArray) {
this.hobbyArray = hobbyArray;
}
//비밀번호 변경 기능 구현 시 사용
public boolean matchPassword(String pwd) {
return password.contentEquals(pwd);
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public List<CardVO> getCardList() {
return cardList;
}
public void setCardList(List<CardVO> cardList) {
this.cardList = cardList;
}
@Override
public String toString() {
return "MemberVO [memberid=" + memberid + ", password=" + password + ", name=" + name + ", email=" + email
+ ", introduction=" + introduction + ", regdate=" + regdate + ", hobbyArray=" + hobbyArray
+ ", hobbyList=" + hobbyList + ", gender=" + gender + ", cardList=" + cardList + "]";
}
}
package kr.or.ddit;
import java.util.Date;
import org.springframework.format.annotation.DateTimeFormat;
//자바빈 클래스
public class CardVO {
private String memberid;
private String no;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date vaildMonth;
public String getMemberid() {
return memberid;
}
public void setMemberid(String memberid) {
this.memberid = memberid;
}
public String getNo() {
return no;
}
public void setNo(String no) {
this.no = no;
}
public Date getVaildMonth() {
return vaildMonth;
}
public void setVaildMonth(Date vaildMonth) {
this.vaildMonth = vaildMonth;
}
@Override
public String toString() {
return "CardVO [memberid=" + memberid + ", no=" + no + ", vaildMonth=" + vaildMonth + "]";
}
}
package kr.or.ddit;
import java.util.HashMap;
//spring 프레임워크가 자바 빈(=객체)으로 등록해서 관리할 수 있도록 어노테이션 달기
//클래스 단으로 빼면 메소드 위 @RequestMapping("/member/insert") -> @RequestMapping("/insert")로 사용 가능
@RequestMapping(value="/member")
@Controller
public class MemberController {
//로거 만들기
private static final Logger logger = LoggerFactory.getLogger(MemberController.class);
//DI(Dependency Injection : 의존성 주입)하면 컨트롤러에서 MemberService를 사용할 수 있다
@Autowired
MemberService memberService;
//컨트롤러의 insert메서드의 매개변수로 자바빈즈 객체가 전달이 되면 기본적으로 다시 화면(view(jsp))으로 전달함
//컨트롤러와 뷰 사이에 자바빈즈 객체를 서로 공유한다.
//방법
//1) 폼 객체의 속성명을 직접 지정
//2) 폼 객체의 속성명은 직접 저장하지 않으면 **폼 객체의 클래스명의 맨 처음 문자를 소문자로 변환하여 처리
// ex) MemberVO -> memberVO, 아래 매개변수명을 memberVO라고 적지 않아도 앞 클래스명을 변환하여 전달
//3) ModelAttribute 애너테이션으로 폼 객체의 속성명을 dotori라고 지정했다면...
// 스프링 폼의 modelAttribute 속성의 값도 똑같이 dotori라고 작성해줘야 함
@RequestMapping("/insert")
public String insert(Model model, @ModelAttribute("memberVO") MemberVO memberVO) {
//폼 객체의 속성명과 폼 태그의 modelAttribute 속성값이 같아야 함
//model.addAttribute("memberVO", new MemberVO()); 이렇게 적어주거나 파라미터에 넣기
//폼 객체의 프로퍼티 값을 지정 -> 모델을 통해서 뷰(jsp)로 전달이 됨
// --> <form:input의 path="memberid" /> 때문 (단, path값은 VO객체의 멤버변수명과 일치해야 함)
memberVO.setMemberid("a001");
memberVO.setName("도토리");
//<form:password -> 값을 설정해서 뷰(jsp)에 전달하더라도 패스워드 필드에 반영되지 않음
memberVO.setPassword("java");
memberVO.setEmail("test@test.com");
String introduction = "안녕하세요.\n반갑습니다.";
memberVO.setIntroduction(introduction);
//취미 세팅
Map<String, String> hobbyMap = new HashMap<String,String>();
hobbyMap.put("01", "배구");
hobbyMap.put("02", "EDM Music");
hobbyMap.put("03", "해리포터 시리즈");
model.addAttribute("hobbyMap",hobbyMap);
//성별 세팅
Map<String, String> genderMap = new HashMap<String, String>();
genderMap.put("Male","남성");
genderMap.put("Female","여성");
genderMap.put("other","기타");
//session.setAttribute("gender","genderMap"); 처럼
model.addAttribute("genderMap",genderMap);
//model에는 memberVO객체와 hobbyMap, genderMap이 들어가 있음
return "member/joinForm";
//model은 jsp를, ModelAndView는 ModelAndView 객체를 리턴
}
//요청과 메소드를 매핑(연결)하는 어노테이션
@RequestMapping(value="/insert", method=RequestMethod.POST)
//기본이 GET이기 때문에, GET방식이라면 method=RequestMethod.GET 생략 가능
//기존에는 ModelAndView로 model의 영역과 view의 영역을 같이 사용했음
//public ModelAndView insertPost(@RequestParam Map<String, Object> map) {
// ModelAndView mav = new ModelAndView(map);
// mav.setViewName("member/result");
// return mav;
//이제는 model과 view를 분리한다!
public String insertPost(@ModelAttribute MemberVO memberVO) { //@ModelAttribute를 사용해서 jsp안에 있는 VO로 받을 수 있다.
//sysout 안쓰고 logger로 찍기
logger.info(memberVO.getMemberid());
logger.info(memberVO.getName());
logger.info(memberVO.getPassword());
logger.info(memberVO.getEmail());
logger.info(memberVO.getIntroduction());
List<String> hobbyList = memberVO.getHobbyList();
for(String hobby : hobbyList){
logger.info(hobby);
}
String[] hobbyArray = memberVO.getHobbyArray();
for(String str : hobbyArray) {
logger.info(str);
}
//성별
logger.info(memberVO.getGender());
//뷰의 경로(mav.setViewName("member/result"))
//forwarding 방식
return "member/result";
}
// public ModelAndView list(ModelAndView mav) { 로 하거나 아래처럼
// String은 뷰의 경로, list(Model model)는 모델 데이터
// 속성이 하나이면 @RequestMapping(value="/member/list", method = RequestMethod.GET)으로 안쓰고 아래처럼 생략가능
@RequestMapping("/list")
public String list(Model model){
List<MemberVO> memberVO = this.memberService.select();
// 1) 데이터를 담아서
model.addAttribute("list", memberVO);
// 2) 뷰로 보낸다
// 뷰의 경로, forwarding 방식(데이터를 끌어감)
return "member/list";
}
}
package kr.or.ddit;
import java.util.List;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
// spring 프레임워크가 자바 빈(=객체)으로 등록해서 관리할 수 있도록 어노테이션 달기
@Repository
public class MemberDao {
//sqlSessionTemplate 타입 객체를 MemberDao 객체에 주입(사용가능하게) 함
@Autowired
SqlSessionTemplate sqlSessionTemplate; // root-context 객체에 있는 id와 같아야 함
//회원가입
public int insert(MemberVO memberVO) {
//namespace.id
//result가 0이면 입력실패, 1이면 입력 성공
int result = this.sqlSessionTemplate.insert("member.insert", memberVO);
return result;
}
//회원 정보 목록
public List<MemberVO> select(){
//namespace.id
return this.sqlSessionTemplate.selectList("member.select");
}
}
package kr.or.ddit;
import java.util.List;
/*
* 스프링은 직접 클래스를 생성하는 것을 지양(안함)하고,
* 인터페이스를 통해 접근하는 것을 권장하는 프레임워크.
*/
public interface MemberService {
//메소드 시그니처 처리
//회원가입
public int insert(MemberVO memberVO);
//회원정보 목록
List<MemberVO> select();
}
package kr.or.ddit;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
//spring 프레임 워크가 자바 빈(=객체)으로 등록해서 관리할 수 있도록 어노테이션 달기
@Service
public class MemberServiceImpl implements MemberService {
//DI(의존성 주입)
//데이터베이스에 접근을 위해 MemberDao 인스턴스를 주입받음
@Autowired
MemberDao memberDao;
//회원가입
@Override
public int insert(MemberVO memberVO) {
return memberDao.insert(memberVO);
}
//회원정보 목록
@Override
public List<MemberVO> select(){
return memberDao.select();
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html>
<html>
<head>
<title>회원가입</title>
</head>
<body>
<!--
스프링 폼 태그 라이브러리 <form:>
- 스프링 폼은 HTML 폼을 표시하기 위한 태그 라이브러리
- 스프링 폼을 이용하면 HTML 폼과 자바 객체를 쉽게 바인딩할 수 있음
컨트롤러에서 사용하는 modelAttribute가 정의되어 있어야 아래 modelAttribute가 정의되어 있어야 아래 modelAtrribute="memberVO" 처럼 사용할 수 있음
여기서 path : 폼 팡목에 바인딩되는 폼 객체(Controller에 있음)의 프로퍼티를 지정
-->
<form:form modelAttribute="memberVO" method="post" action="/member/insert">
<p>
아이디 : <form:input path="memberid" />
<font color="red">
<form:errors path="memberid" />
</font>
</p>
<p>
이름 : <form:input path="name" />
<font color="red">
<form:errors path="name" />
</font>
</p>
<p>
비밀번호 : <form:password path="password" />
<font color="red">
<form:errors path="password" />
</font>
</p>
<p>
이메일 : <form:input path="email" />
<font color="red">
<form:errors path="email" />
</font>
</p>
<p>
자기소개 :
<form:textarea path="introduction" rows="6" cols="30" />
</p>
<p>
취미 :
<form:checkboxes path="hobbyList" items="${hobbyMap}" />
<!--
items는 눈에 보여질 대상.
컨트롤러에서 model.addAttribute("hobbyMap", hobbyMap);로 보낸 것을 el태그로 받음
-->
</p>
<p>
취미(hobbyArray) :
<form:checkbox path="hobbyArray" value="안철수" label="안철수" /><br>
<form:checkbox path="hobbyArray" value="이재명" label="이재명" /><br>
<form:checkbox path="hobbyArray" value="윤석열" label="윤석열" /><br>
<form:checkbox path="hobbyArray" value="심상정" label="심상정" /><br>
</p>
<p>
성별 :
<%--
방법 두가지
1)
<form:radiobuttons path="gender" items="${genderMap}" /> 처럼 사용하거나
2)
--%>
<form:radiobutton path="gender" value="Male" label="Male" />
<form:radiobutton path="gender" value="Female" label="Female" />
<form:radiobutton path="gender" value="Other" label="Other" />
</p>
<form:button name="register">등록</form:button>
</form:form>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<title>회원목록</title>
</head>
<body>
<!--
varStatus
*1) count : 1부터 순서적으로 1씩 증가
*2) index : 0부터 순서적으로 1씩 증가
3) current : 현재의 아이템
4) first : 처음 반복되는 것인지 반환
5) last : 마지막 반복인지 반환
6) begin : 시작값
7) end : 끝값
8) step :증가값
-->
<table border="1">
<tr>
<th>번호</th>
<th>이름</th>
<th>이메일</th>
<th>가입일</th>
<th>보유 카드번호</th>
</tr>
<c:forEach var="memberVO" items="${list}" varStatus="stat"> <!-- items는 컨트롤러 model.addAttribute("list", memberVO)의 키값 -->
<tr>
<td>${stat.count}</td>
<td>${memberVO.name}</td>
<td>${memberVO.email}</td>
<td>${memberVO.regdate}</td>
<td>
<c:forEach var="cardVO" items="${memberVO.cardList}">
${cardVO.no}
</c:forEach>
</td>
</tr>
</table>
</body>
</html>
<?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="member">
<!--
기본키는 id, 아닌 컬럼은 result에
property : vo의 멤버변수명
column : select문의 컬럼명
<assciation>은 1:1, <collection>은 1:N
-->
<!-- 아래에서 만든 resultMap의 상세 속성 적기-->
<resultMap type="memberVO" id="memberMap">
<id property="memberid" column="MEMBERID" />
<result property="password" column="PASSWORD"/>
<result property="name" column="NAME"/>
<result property="email" column="EMAIL"/>
<result property="regdate" column="REGDATE"/>
<result property="introduction" column="INTRODUCTION"/>
<collection property="cardList" resultMap="cardMap">
</collection>
</resultMap>
<!-- 위 <collection>에서 선언한 resultMap의 상세 속성을 다시 적는다-->
<!-- type="cardVO"은 mybatisAlias.xml에 추가한 이름과 같게 사용 -->
<resultMap type="cardVO" id="cardMap">
<result property="memberid" column="MEMBERID" />
<result property="no" column="NO" />
<result property="vaildMonth" column="VALID_MONTH" />
</resultMap>
<!-- 회원가입 -->
<insert id="insert" parameterType="memberVO"> <!-- typeAlias에서 정한 거! -->
INSERT INTO MEMBER(MEMBERID,PASSWORD,NAME,EMAIL,REGDATE)
VALUES(#{memberid},#{password},#{name},#{email},SYSDATE)
</insert>
<!-- 회원정보 목록 -->
<select id="select" resultMap="memberMap">
SELECT M.MEMBERID, M.PASSWORD, M.NAME, M.EMAIL, M.REGDATE, M.INTRODUCTION
, C.NO, C.VALID_MONTH, C.MEMBERID
FROM MEMBER M, CARD C
WHERE M.MEMBERID = C.MEMBERID
ORDER BY C.NO DESC
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--
[마이바티스]
스프링에서 "_"를 사용한 컬럼명을 사용 시 테이블 컬럼명에 "_"가 있을 경우 카멜케이스로 읽어줌
member 테이블 컬럼명이 mem_id일 경우 memId로 사용가능하도록 도와줌
cart 테이블에 cart_prod -> cartProd
-->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true" />
</settings>
<!-- 자주 사용하는 타입의 별칭 -->
<typeAliases>
<typeAlias type="kr.or.ddit.BookVO" alias="bookVO"/>
<typeAlias type="kr.or.ddit.MemberVO" alias="memberVO"/>
<typeAlias type="kr.or.ddit.CardVO" alias="cardVO"/>
</typeAliases>
</configuration>