Spring - MyPage(1) 내 정보 수정

맑은 눈의 코드 👀·2023년 8월 14일
0

06_framework

목록 보기
2/2
post-thumbnail

🚗 회원정보 수정

@SessionAttuributes() 의 역할
1) Model에 세팅된 값이 key와 {} 작성된 값이 일치하면 Session scope로 이동
2) Session으로 올려둔 값을 해당 클래스에서 얻어와 사용 가능하게 함
-> @SessionAtturibute(key)로 사용
예) @SessionAtturibute("loginMember") Member loginMember
// : Session에서 얻어온 ""loginMember"에 해당하는 객체를
// : 매개변수 Member loginMemeber에 저장

🚥 myPage-info.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>마이페이지</title>

    <link rel="stylesheet" href="/resources/css/myPage/myPage-style.css">

</head>
<body>
    <main>
        <jsp:include page="/WEB-INF/views/common/header.jsp" />

        <section class="myPage-content">

            <jsp:include page="/WEB-INF/views/myPage/sideMenu.jsp" />

            <section class="myPage-main">

                <h1 class="myPage-title">내 정보</h1>
                <span class="myPage-subject">원하는 회원 정보를 수정할 수 있습니다.</span>

                <%-- 현재페이지 : http://localhost/myPage/info 
                     제일 뒤에 info 지우고 
                     action에 작성된 경로 추가 
                
                --%>

                <form action="info" method="POST" name="myPageFrm">

                    <div class="myPage-row">
                        <label>닉네임</label>
                        <input type="text" name="memberNickname"  maxlength="10" 
                                value="${loginMember.memberNickname}">
                    </div>

                    <div class="myPage-row">
                        <label>전화번호</label>
                        <input type="text" name="memberTel"  maxlength="11" 
                                value="${loginMember.memberTel}">
                    </div>

                    <div class="myPage-row info-title">
                        <span>주소</span>
                    </div>
                    <%-- ${fn:split(loginMember.memberAddress, '^^^')[0]}
                    ${fn:split(loginMember.memberAddress, '^^^')[1]}
                    ${fn:split(loginMember.memberAddress, '^^^')[2]} --%>


                    <%--
                        ${fn:split(문자열, 구분자)}
                        문자열을 구분자로 나누어 배열 형태로 반환
                    --%>
                    <c:set var="addr" value="${fn:split(loginMember.memberAddress,'^^^')}"/>
                    <div class="myPage-row info-address">
                        <input type="text" name="memberAddress" placeholder="우편번호" value="${addr[0]}">
                        <button type="button">검색</button>
                    </div>

                    <div class="myPage-row info-address">
                        <input type="text" name="memberAddress"  placeholder="도로명/지번 주소" value="${addr[1]}">                
                    </div>

                    <div class="myPage-row info-address">
                        <input type="text" name="memberAddress"  placeholder="상세 주소" value="${addr[2]}">                
                    </div>

                    <button class="myPage-submit">수정하기</button>
                </form>

            </section>

        </section>

    </main>
    <jsp:include page="/WEB-INF/views/common/footer.jsp" />

    <!-- 다음 주소 api 추가 -->
    
</body>
</html>

🚥 myPage-style.css

/* 회원 페이지 전체를 감싸고 있는 요소 */
.myPage-content{
    display: flex;
    width: 1000px;
    min-height: 700px;
    margin: 50px auto;
    /* 
        width / height 관련 속성

        1) width / height
            - 지정된 크기로 고정

        2) min-width / min-height    
            - 내부 요소가 부모 크기보다 작아도 지정된 최소 크기를 유지
            - 단, 내부 요소가 부모크기를 초과화면 부모의 크기가 늘어남

        3) max-width / max-height    
            - 내부 요소가 부모 크기보다 커도 지정된 크기를 유지 
            - 단, 내부 요소가 부모 크기보다 작다면 부모의 크기가 줄어듬
    */

}

/* 사이드메뉴 */
.left-side{
    width: 25%;
    border-right: 2px solid #ddd;
}

.list-group{
    width: 100%;
    list-style: none;
    padding-right: 20px;
}

.list-group > li{
    height: 50px;
    font-size: 18px;
}

.list-group > li > a{
    color:black;
    text-decoration: none;

    display: flex;
    height: 100%;

    justify-content: center;
    align-items: center;

    border-bottom : 2px solid #ddd;
}

.list-group > li > a:hover{
    background-color: #ccc;
}

/* ********************************* */
/* 마이페이지 공통 */
.myPage-main{
    width: 75%;
    padding: 0 50px;
}

/* 마이페이지 제목 */
.myPage-title{
    margin-bottom: 10px;
    font-size: 30px;
}

/* 마이페이지 부제 */
.myPage-subject{
    display: block;
    margin-bottom: 30px;

    font-size: 14px;
    letter-spacing: -1px;
}

/* 마이페이지 행 단위 스타일 지정 */
.myPage-row{
    width: 500px;
    height: 50px;
    margin-top: 20px;

    display: flex;
    align-items: center;
    border-bottom : 2px solid #ddd;
}

.myPage-row > * {
    font-size: 18px;
    font-weight: bold;
}

/* 행 제목 */
.myPage-row > label{
    width: 30%;
    color: #455ba8;
}

.myPage-row > span{
    width: 70%;
    color: #455ba8;
}

/* 행 내부 input 태그 */
.myPage-row > input{
    width: 100%;
    height: 100%;
    border: none;
    outline: none;
    font-weight: normal;
}

/* 제출 버튼 */
.myPage-submit{
    width: 100%;
    padding: 10px;
    margin: 50px 0;
    
    border: none;
    font-size: 20px;
    font-weight: bold;

    background-color: #455ba8;
    color: white;
    cursor: pointer;
}

/* form태그 */
form[name='myPageFrm']{
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
}

/* 내부 input 요소 focus 시 */
.myPage-row:focus-within{ 
    border-bottom-color: #455ba8;
}


/* ******************************************* */
/* 내 정보 페이지 전용 스타일 */

.info-title{
    border: none;
}

.info-address{
    margin: 0;
}

.info-address > button{
    width: 30%;
    height: 70%;

    font-size: 14px;
    font-weight: normal;

    background-color: white;
    border : 1px solid gray;
    cursor: pointer;
}

/* *********비밀번호 변경 화면*********** */
.myPage-row > input[type='password']{
    width: 70%;
} 

/* **********회원 탈퇴 약관********** */
.secession-terms{
    width: 500px;
    height: 300px;
    border: 1px solid black;
    
    overflow: auto;
    /* 내용이 요소를 벗어나는 경우 방향에 맞춰서 자동으로 스크롤 추가 */

    font-family: sans-serif; /* 돋움체 */
    font-size: 14px;
}

/* ************* 프로필 화면 ************* */
.profile-image-area{
    width: 150px;
    height: 150px;
    border: 3px solid #ccc;
    border-radius: 50%;

    position: relative;

    overflow: hidden;
    display: flex;
    justify-content: center;
    align-content: center;
}

#profileImage{
    height: 100%;
}

/* 삭제버튼 */
form[name='myPage-frm']{position: relative;}

#deleteImage{
    position: absolute;
    top: 0px;
    right: 240px;
    cursor: pointer;
}

/* 이미지 버튼 영역 */
.profile-btn-area{
    width: 230px;
    margin: 20px 0;

    display: flex;
    justify-content: center;
    align-items: center;
}

.profile-btn-area > *{
    width: 110px;
    height: 33px;
    padding: 5px 10px;

    border: 1px solid black;
    background-color: white;
    font-size: 14px;
    cursor: pointer;
    text-align: center;
}

#imageInput{ display: none;}

.profile-btn-area > button{
    background-color: #455ba8;
    color : white;
    margin-left: 2px;
}

🚥MyPageController 클래스

// 회원정보 수정 
	@PostMapping("/info")
	public String info(Member updateMember, String[] memberAddress
						, @SessionAttribute("loginMember") Member loginMember
						, RedirectAttributes ra) {
		
		
		//------------------매개변수 설명---------------------
		// Member updateMember : 수정할 닉네임, 전화 변호담긴 커멘드 객체
		// String[] memberAddress : neme= "memberAddress"인 input 3개의 값(주소)
		
		// @SessionAtturibute("loginMember") Member loginMember
		//  : Session에서 얻어온 ""loginMember"에 해당하는 객체를 
		//	: 매개변수 Member loginMemeber에 저장
		
		// RedirectAttributes ra : 리다이렉트 시 재요청 
		//------------------------------------------------
		
		//주소하나로 합치기
		String addr = String.join("^^^", memberAddress);
		updateMember.setMemberAddress(addr);
		
		//로그인한 회원의 번호를 updateMember에 추가
		updateMember.setMemberNo( loginMember.getMemberNo() );
		
		// DB에 회원 정보 수정 Update 서비스 호출 
		int result = service.updateInfo(updateMember);
		
		String message = null;
		if(result > 0 ) {
			message= "회원 정보가 수정되었습니다.";
			
			//Session에 로그인된  회원 정보도 수정(동기화)
			loginMember.setMemberNickname(updateMember.getMemberNickname());
			loginMember.setMemberTel(updateMember.getMemberTel());
			loginMember.setMemberAddress(updateMember.getMemberAddress());
			 
			
		}else {
			message= "회원 정보 수정 실패.";
		}
		
		ra.addFlashAttribute("message", message);
		return "redirect:info"; //상대경로 (/myPage/myPage-info)
	}

🚥MyPageService 인터페이스

package edu.kh.project.myPage.model.service;

import edu.kh.project.member.model.dto.Member;

public interface MyPageService {
	/** 내정보 수정 메소드 
	 * @param updateMember
	 * @return result
	 */
	int updateInfo(Member updateMember);
}

🚥MyPageSericeImpl 클래스

트렌젝션 처리
스프링에서는 트랜잭션을 처리할 방법을 지원해줌.(코드기반, 선언적)
1) <tx:advice> -> AOP를 이용한 방식(XML에 작성)
2) @Transactional 어노테이션을 이용한 방식(클래스 또는 인터페이스에 작성)
- 인터페이스를 구현한 클래스로 선언된 빈은 인터페이스 메소드에 한해서 트랜잭션이 적용됨
* 트랜잭션 처리를 위해서는 트랜잭션 매니저가 bean으로 등록되어 있어야 함.
-> root-context.xml 작성
정상 여부는 RuntimeException이 발생했는지 기준으로 결정되며,
RuntimeException 외 다른 Exception(대표적으로 SQLException 등)에도 트랜잭션 롤백처리를 적용하고 싶으면
@Transactional의 rollbackFor 속성을 활용하면 된다

package edu.kh.project.myPage.model.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import edu.kh.project.member.model.dto.Member;
import edu.kh.project.myPage.model.dao.MyPageDAO;

@Service //비지니스 로직을 처리하는 클래스 + Bean으로 등록 (IOC)
public class MyPageServiceImpl implements MyPageService{

	@Autowired
	private MyPageDAO dao;
	
	// 스프링에서는 트랜잭션을 처리할 방법을 지원해줌.(코드기반, 선언적)
   // 1) <tx:advice> -> AOP를 이용한 방식(XML에 작성)
   
   // 2) @Transactional 어노테이션을 이용한 방식(클래스 또는 인터페이스에 작성)
   // - 인터페이스를 구현한 클래스로 선언된 빈은 인터페이스 메소드에 한해서 트랜잭션이 적용됨
   // * 트랜잭션 처리를 위해서는 트랜잭션 매니저가 bean으로 등록되어 있어야 함. 
   //   -> root-context.xml 작성
   
   // 정상 여부는 RuntimeException이 발생했는지 기준으로 결정되며, 
   // RuntimeException 외 다른 Exception(대표적으로 SQLException 등)에도 트랜잭션 롤백처리를 적용하고 싶으면 
   // @Transactional의 rollbackFor 속성을 활용하면 된다
	
	//회원 정보 수정 서비스 
	@Transactional(rollbackFor = {Exception.class})
	@Override
	public int updateInfo(Member updateMember) {

		int result = dao.updateInfo(updateMember); 
		return result;
	}
}

🚥MyPageDAO 클래스

package edu.kh.project.myPage.model.dao;

import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import edu.kh.project.member.model.dto.Member;

@Repository // 저장소(DB)와 관련된 클래스 + Bean등록(IOC, 스프링이 객체를 관리)
public class MyPageDAO {
	
	// 등록된 Bean 중에서 타입이 SqkSessionTemplate을 찾아서 Bean를 주입(DI)
	// -> root-context.xml에 <Bean> 작성됨
	@Autowired
	private SqlSessionTemplate sqlSession;

	public int updateInfo(Member updateMember) {

		//return sqlSession.update("namespace.id", 전달할 );
		return sqlSession.update("myPageMapper.updateInfo", updateMember);
	}
}

🚥myPage-mapper.xml

<!-- 회원 정보 수정 -->
	<update id="updateInfo" parameterType="Member">
	UPDATE MEMBER SET MEMBER_NICKNAME = #{memberNickname}
					, MEMBER_TEL = #{memberTel}
					, MEMBER_ADDR = #{memberAddress}
	WHERE MEMBER_NO = ${memberNo}		
	</update>
profile
나를 죽이지 못하는 오류는 내 코드를 더 강하게 만들지ㅋ

0개의 댓글