스프링 23강 - Member 게시판 CRUD 2, 1:N 관계 처리

voilà!·2022년 2월 7일
0

JSP 스프링

목록 보기
23/31

1명의 회원이 여러 개의 카드를 가질 수 있다
-> Member 와 Card 테이블은 1:N 관계

VO

MemberVO.java

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 + "]";
	}

	
}

CardVO.java

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 + "]";
	}
	
}

Controller

MemberController.java

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";
    }
    
}
    

Dao

MemberDao.java

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");
    }
    
}

Service

MemberService.java

package kr.or.ddit;

import java.util.List;
/*
* 스프링은 직접 클래스를 생성하는 것을 지양(안함)하고,
* 인터페이스를 통해 접근하는 것을 권장하는 프레임워크.
*/

public interface MemberService {
	//메소드 시그니처 처리
    //회원가입
    public int insert(MemberVO memberVO);
    
    //회원정보 목록
    List<MemberVO> select();
}

MemberServiceImpl.java

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();
    }
}

View

joinForm.jsp

<%@ 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>

list.jsp

<%@ 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}&nbsp;
            </c:forEach>
        </td>
    </tr>
</table>

</body>
</html>

xml

member_SQL.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="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>

mybatisAlias.xml

<?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>

0개의 댓글