쌍용교육(JAVA)/SpringBoot

쌍용교육 -JSP수업 91일차 ch15SpringPage(2)

구 승 2024. 6. 26. 13:25

validation.properties

#회원관리
Pattern.id=영문,숫자 4자~12자 입력
NotBlank.name=이름은 필수 항목
Pattern.passwd=영문,숫자 4자~12자 입력
Pattern.now_passwd=영문,숫자 4자~12자 입력
NotBlank.email=이메일은 필수 항목
Email.email=이메일 형식에 맞게 입력
NotBlank.phone=전화번호는 필수 항목
Size.zipcode=5자만 입력 가능
NotBlank.address1=주소는 필수 항목
NotBlank.address2=상세주소는 필수 항목
invalidPassword=비밀번호 불일치

common.css

56라인

.error-color{
	color:#ff0000;
}

mapper.xml

 <!-- 아이디 중복체크 및 로그인 처리-->
	 <select id="selectCheckMember" parameterType="string" resultType="memberVO" >
	 	SELECT 
	 		mem_num,
	 		id,
	 		auth,
	 		nick_name,
	 		au_id,
	 		passwd,
	 		email
	 	FROM spmember LEFT OUTER JOIN spmember_detail
	 	USING (mem_num)
	 	WHERE id=#{id}
	 </select>

 

member.controller => MemberAjaxController

package kr.spring.member.controller;

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import kr.spring.member.service.MemberService;
import kr.spring.member.vo.MemberVO;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller
public class MemberAjaxController {
	@Autowired
	private MemberService memberService;
	
	@GetMapping("/member/confirmId")
	@ResponseBody
	public Map<String,String> process(@RequestParam String id){
		
		log.debug("<<아이디 중복 체크>> : "+id);
		
		Map<String,String> mapAjax = new HashMap<String,String>();
		
		MemberVO member = memberService.selectCheckMember(id);
		
		if(member!=null) {
			//아이디 중복
			mapAjax.put("result","idDuplicated");
		}else {
			if(!Pattern.matches("^[A-Za-z0-9]{4,12}$", id)) {
				//패턴 불일치
				mapAjax.put("result","notMatchPattern");
			}else {
				//패턴이 일치하면서 아이디 미중복
				mapAjax.put("result","idNotFound");
			}
		}
		return mapAjax;
	}
}

static => js폴더

jquery-3.7.1.min (1).js
0.08MB

 

 

 

js=>member.register.js

$(function(){
	
   /*--------------------------
	*		회원가입
	*---------------------------*/
	
	//아이디 중복 여부 저장 변수 : 0은 아이디 중복 또는 중복 체크 미실행,
	//					  1은 아이디 미중복
	
	let checkId = 0;
	
	//아이디 중복 체크
	$('#confirmId').click(function(){
		if($('#id').val().trim()==''){
			$('#message_id').css('color','red').text('아이디를 입력하세요');
			$('#id').val('').focus();
			return;
		}
		
		$('#message_id').text(''); //메시지 초기화
		
		//서버와 통신
		$.ajax({
			url:'confirmId',
			type:'get',
			data:{id:$('#id').val()},
			dataType:'json',
			success:function(param){
				if(param.result == 'idNotFound'){
					checkId =1;
					$('#message_id').css('color','#000')
									.text('등록 가능 ID');
				}else if(param.result == 'idDuplicated'){
					checkId = 0;
					$('#message_id').css('color','red')
									.text('중복된 ID');
					$('#id').val('').focus();
				}else if(param.result == 'notMatchPattern'){
					checkId=0;
					$('message_id').css('color','red')
									.text('영문,숫자 4자~12자 입력');
					$('#id').val('').focus();
				}else{
					checkId = 0;
					alert('ID 중복 체크 오류');
				}
			},
			error:function(){
				checkId=0;
				alert('네트워크 오류 발생');
			}
			
		});
	});//end of click
	
	//아이디 중복 안내 메시지 초기화
	$('#member_register #id').keydown(function(){
		checkId=0;
		$('#message_id').text();
	});//end of keydown
	//submit 이벤트 발생시 아이디 중복 체크 여부 확인
	$('#member_register').submit(function(){
		if(checkId==0){
			$('#message_id').css('color','red')
							.text('아이디 중복 체크 필수');
			if($('#id').val().trim()==''){
				$('#id').val('').focus();
			}
			return false;
		}
	});//end of submit
});

views/member => memberRegister.jsp 내용추가

<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.7.1.min.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/member.register.js"></script>

header.jsp 수정

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!-- 상단 시작 -->
<h2 class="align-center">SpringPage</h2>
<div class="align-right">
	<c:if test="${!empty user}">
	<a href="${pageContext.request.contextPath}/member/myPage">마이페이지</a>
	<a href="${pageContext.request.contextPath}/member/logout">로그아웃</a>
	</c:if>
	<c:if test="${empty user}">
	<a href="${pageContext.request.contextPath}/member/registerUser">회원가입</a>
	<a href="${pageContext.request.contextPath}/member/login">로그인</a>
	</c:if>	
	<a href="${pageContext.request.contextPath}/main/main">홈으로</a>
</div>
<!-- 상단 끝 -->

MemberController.java 내용추가

/*===============================
	 * 회원로그인
	 ===============================*/
	//로그인 폼호출
	@GetMapping("/member/login")
	public String formLogin() {
		return "memberLogin";

WEB-INF/tile-def =>Member.xml 내용추가

<definition name="memberLogin" extends="main">
		<put-attribute name="title" value="회원로그인"/>
		<put-attribute name="css" value="/WEB-INF/views/member/memberCSS.jsp"/>
		<put-attribute name="body" value="/WEB-INF/views/member/memberLogin.jsp"/>
	</definition>

WEB-INF/views/member=>memberLogin.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="form" uri="http://www.springframework.org/tags/form" %>
<!-- 회원로그인 시작 -->
<div class="page-main">
	<h2>회원로그인</h2>
	<form:form action="login" id="member_login"
	                            modelAttribute="memberVO">
	    <form:errors element="div" cssClass="error-color"/>
		<ul>
			<li class="floating-label">
				<form:input path="id" placeholder="아이디"
				                             autocomplete="off" cssClass="form-input"/>                            
				<form:label path="id">아이디</form:label>
				<form:errors path="id" cssClass="error-color"/>                             
			</li>
			<li class="floating-label">
				<form:password path="passwd" placeholder="비밀번호" cssClass="form-input"/>
				<form:label path="passwd">비밀번호</form:label>
				<form:errors path="passwd" cssClass="error-color"/>
			</li>
			<li>
				<label for="auto"><input type="checkbox" name="auto" id="auto">로그인상태유지</label>
			</li>
		</ul> 
		<div>
			<form:button class="login-btn">로그인</form:button>
		</div>                           
	</form:form>
	<p class="align-center">
		<input type="button" value="홈으로" class="default-btn"
			onclick="location.href='${pageContext.request.contextPath}/main/main'">
		<input type="button" value="비밀번호찾기" onclick="location.href='sendPassword'">	
	</p>
</div>
<!-- 회원가입 끝 -->

 

member.css수정

#member_login 이라고 쓴 곳이 수정한

/* 로그인
---------------------*/
#member_login{
	width:320px;
	margin:0 auto;
	padding:0;
	border:none;
}
#member_login ul{
	padding:0;
}
.floating-label{/*floating label 설정*/
	position:relative;
}
.floating-label > .form-input{
	width:300px;
	height:32px;
	padding:0.55rem 0.55rem;
}
.floating-label > label{
	position:absolute;
	top:0;
	left:0;
	padding:1.05rem 0.75rem;
	transition:all 0.25s;
}
.floating-label > .form-input::placeholder{
	color:transparent;
}
.floating-label > .form-input:focus, 
 .floating-label > .form-input:not(:placeholder-shown){
	padding-top:1.125rem;
	padding-bottom:0.125rem;      
}

.floating-label > .form-input:focus + label, 
 .floating-label > .form-input:not(:placeholder-shown) + label{
	opacity:0.65;
	transform:scale(0.85) translateY(-0.5rem) translateX(-0.5rem);      
}
#member_login .login-btn{
	width:320px;
	
}
#member_login label[for="auto"]{
	width:200px;
	padding:0 0 5px 0;
}

validation.propertie 내용수정

invalidIdOrPassword=아이디 또는 비밀번호 불일치

MemberController 추가

/*===============================
	 * 회원로그인
	 ===============================*/
	//로그인 폼호출
	@GetMapping("/member/login")
	public String formLogin() {
		return "memberLogin";
	}
	//로그인 폼에서 전송된 데이터 처리
	@PostMapping("/member/login")
	public String submitLogin(@Valid MemberVO memberVO, BindingResult result, HttpSession session, HttpServletResponse response) {
		
		log.debug("<<회원로그인>> : "+memberVO);
		
		//유효성 체크 결과 오류가 있으면 폼 호출
		//id와 passwd 필드만 체크
		if(result.hasFieldErrors("id")|| result.hasFieldErrors("passwd")) {
			return formLogin();
		}
		
		//로그인 체크(id,비밀번호 일치 여부 체크)
		MemberVO member = null;
		try {
			member = memberService.selectCheckMember(memberVO.getId());
			
			boolean check = false;
			if(member !=null) {
				//비밀번호 일치 여부 체크
				check = member.ischeckedPassword(memberVO.getPasswd());
			}
			if(check) {//인증 성공
				// ==== 자동로그인 체크 시작 ====//
	
				// ==== 자동로그인 체크 끝 ====//
				
				//인증 성공, 로그인 처리
				session.setAttribute("user",member);
				
				log.debug("<<인증 성공>>");
				log.debug("<<id>> : "+member.getId());
				log.debug("<<auth>> : "+member.getAuth());
				log.debug("<<au_id>> : "+member.getAu_id());
				
				if(member.getAuth() ==9) { //관리자
					return "redirect:/main/admin";
				}else {
					return "redirect:/main/main";
				}
			}
			//인증 실패
			throw new AuthCheckException();
		}catch(AuthCheckException e) {
			//인증 실패로 로그인 폼 호출
			if(member!=null && member.getAuth()==1) {//정지회원 메시지 표시
				result.reject("noAuthority");
			}else {
				result.reject("invalidIdOrPassword");
			}
			log.debug("<<인증실패>>");
			
			return formLogin();
		}
		
	}
	/*===============================
	 * 로그아웃
	 ===============================*/
	@GetMapping("/member/logout")
	public String processLogout(HttpSession session) { //로그아웃은 세션에있는 속성들을 다 지워야되기 떄문에 session이 필요
		//로그아웃
		session.invalidate();
		
		// ==== 자동로그인 시작 ====//
		// ==== 자동로그인 끝 ====//
		
		return "redirect:/main/main";
	}

 

kr.spring.util => AuthCheckException 

위에 컨트롤러 파일에서 try catch에서 Exception을 쓰기위해 따로 파일을 만들어줌

package kr.spring.util;

public class AuthCheckException extends Exception {

}

아이디를 잘못입력했을경우
로그인에 성공했을경

validation.properties 내용추가

noAuthority=정지회원입니다.

MemberMapper

@Select("SELECT * FROM spmember JOIN spmember_detail USING(mem_num) WHERE mem_num=#{mem_num}")
	public MemberVO selectMember(Long mem_num);

 

MemberserviceImpl

@Override
	public MemberVO selectMember(Long mem_num) {
		
		return memberMapper.selectMember(mem_num);
	}

 

다시 Controller 수정

/*===============================
	 * 마이페이지
	 ===============================*/
	@GetMapping("/member/myPage")
	public String process(HttpSession session, Model model) {
		MemberVO user = (MemberVO)session.getAttribute("user");
		//회원정보
		MemberVO member = memberService.selectMember(user.getMem_num());
		log.debug("<<MY페이지>> :"+member);
		
		model.addAttribute("member",member);
		return "myPage";
	}

 

layout_mypage.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles" %>    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title><tiles:getAsString name="title"/></title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/common.css" type="text/css">
<tiles:insertAttribute name="css" ignore="true"/>
</head>
<body>
<div id="main">
		<div id="main_header">
			<tiles:insertAttribute name="header"/>
		</div>
		
		<div class="side-height">
			<div id="page_nav">
				<tiles:insertAttribute name="nav"/>
			</div>
			<div id="page_body">
				<tiles:insertAttribute name="body"/>
			</div>
		</div>	
		<div id="main_footer" class="page-clear">
			<tiles:insertAttribute name="footer"/>
		</div>
	
</div>
</body>
</html>

nav_mypage.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!-- mypage 메뉴 시작 -->
<div class="side-bar">
	<ul>
		<li>
			<img src="${pageContext.request.contextPath}/member/photoView" width="200" height="200" class="my-photo">
			<div class="camera" id="photo_btn">
				<img src="${pageContext.request.contextPath}/images/camera.png" width="35">
			</div>
		</li>
		<li>
			<div id="photo_choice" style="display:none;">
				<input type="file" id="upload" accept="image/gif,imgae/png,image/jpeg"><br>
				<input type="button" value="전송" id="photo_submit">
				<input type="button" value="취소" id="photo_reset">
			</div>
		</li>
		<li>
			<input type="button" class="menu-btn" value="비밀번호변경" onclick="changePassword">
		</li>
		<li>
			<input type="button" class="menu-btn" value="회원탈퇴" onclick="delete">
		</li>
	</ul>
		
</div>
<!-- MyPage 메뉴 끝 -->

member =>memberView.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>    
<!-- 회원정보 시작 -->
<div class="page-main">
	<h2>회원상세정보 <input type="button" value="회원정보수정" onclick="location.href='update'"></h2>
	<ul>
		<li>이름: ${member.name}</li>
		<c:if test="${!empty member.nick_name}">
		<li>별명 :${member.nick_name}</li>
		</c:if>
		<li>전화번호 :${member.phone}</li>
		<li>이메일 :${member.email}</li>
		<li>우편번호 :${member.zipcode}</li>
		<li>주소 :${member.address1} ${member.address2}</li>
		<li>가입일 :${member.reg_date}</li>
		<c:if test="${!empty member.modify_date}">
		<li>정보수정일 :${member.modify_date} </li>
		</c:if>
	</ul>
</div>
<!-- 회원정보 끝 -->

tiles-def => member.xml 내용추가

<!-- MyPage -->
	<definition name="myPage" template="/WEB-INF/views/template/layout_mypage.jsp">
		<put-attribute name="title" value="Mypage"/>
		<put-attribute name="header" value="/WEB-INF/views/template/header.jsp"/>
		<put-attribute name="nav" value="/WEB-INF/views/template/nav_mypage.jsp"/>
		<put-attribute name="body" value="/WEB-INF/views/member/memberView.jsp"/>
		<put-attribute name="footer" value="/WEB-INF/views/template/footer.jsp"/>
	</definition>

static/css=>member.css 내용수정

/* MY페이지
---------------------*/
.camera{
	width:50px;
	height:50px;
	border-radius:100%;
	background-color:#d3bb72;
	position:relative;
	top:-60px;
	left:140px;
	border:2px solid #fff;
	cursor:pointer;
	padding:13px 0 0 10px;
}

static=> images => 카메라 이미지

static/css/common.css 내용추가

/* Admin, MY페이지 공통
---------------------*/
.side-bar{
	margin:10px 10px 10px 0;
	padding:10px;
	/*사이드바의 높이가 컨텐트의 높이와 동일하게 자동 조절*/
	margin-bottom:-9999px;
	padding-bottom:9999px;
	background-color:#cecccc;
}
.side-bar ul{
	margin:0;
	padding:0;
	
}
.side-bar ul li{
	padding:5px 10px 5px 10px;
}
.side-bar ul li ing{
	margin-left:3px;
}
.side-height{
	/*사이드바의 높이가 컨텐트 높이와 동일하게 자동 조절하기 위해 흘러넘친 배경색은 숨김*/
	overflow:hidden;
	margin-bottom:10px;
}
#page_nav{
	float:left;
	width:25%;
	min-height:530px;
}
#page_body{
	width:75%;
	float:left;
}
.page-clear{
	clear:both;
}
/* 공통 프로필
---------------------*/
.my-photo{
	object-fit:cover;
	/*정사각형이 아니라 직사각형일 경우 원 안에 보여지게 할 중심 이미지의 위치를 지정*/
	object-position:top;
	border-radius:50%;
}

 

코드를 수정하고 reload가 된 뒤 페이지를 새로고침하면 로그아웃이 되어서

로그인 때만 볼 수 있는 마이페이지 화면을 볼 수 없기 때문에 화면에 에러가난다.

또는 로그아웃 상태에서 링크창으로 mypage를 검색해서 들어가면 에러가 난다.

 

그러기 때문에 인터셉터(요청을 낚아챈다)를 만들어야된다.

kr.spring.interceptor => loginCheckInterceptor

package kr.spring.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.web.servlet.HandlerInterceptor;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class loginCheckInterceptor implements HandlerInterceptor{
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		
		log.debug("<<LoginCheckInterceptor 진입>>");
		
		HttpSession session = request.getSession();
		
		//로그인 여부 검사
		if(session.getAttribute("user")==null) {
			log.debug("<<LoginCheckInterceptor 로그아웃 상태>>");
			//로그인이 되지 않은 상태
			response.sendRedirect(request.getContextPath()+"/member/login");
			
			return false; // 요청한 페이지(URL)를 호출하길 원하지 않을 경우 false
		}
		log.debug("<<LoginCheckInterceptor 로그인 상태>>");
		return true; //true는 요청한 페이지(URL)가 호출될 때
	}
}

kr.spring.config=>AppConfig 내용추가 (변수추가)

private loginCheckInterceptor loginCheck;
	
	
	@Bean
	public loginCheckInterceptor interceptor2() {
		loginCheck = new loginCheckInterceptor();
		return loginCheck;
	}
	
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		//LoginCheckInterceptor 설정
		registry.addInterceptor(loginCheck).addPathPatterns("/member/myPage")
											.addPathPatterns("/member/update");
		
	}

화면 실행 하고 로그인하면

디버그는 잘 작동하였다.

코드를 살짝수정 후 페이지 새로고침을 누르니 로그아웃이 된 것도 볼 수 있다.

화면역시 로그아웃 상태에서 마이페이지로 가려고하면 로그인창으로 이동된다.

 

MemberMapper.java내용추가

@Update("UPDATE spmember SET nick_name=#{nick_name} WHERE mem_num=#{mem_num}")
	public void updateMember(MemberVO member);

MemberMapper.xml내용추가

<!-- 회원정보 수정 -->
	 <update id="updateMember_detail" parameterType="memberVO"> <!-- void기 떄문에 resultType 없음 -->
	 UPDATE spmember_detail
	 SET
	 	name=#{name},
	 	phone=#{phone},
	 	email=#{email},
	 	zipcode=#{zipcode},
	 	address1=#{address1},
	 	address2=#{address2},
	 	modify_date=SYSDATE
	 WHERE mem_num=#{mem_num}
	 </update>

MemberServiceImpl

@Override
	public void updateMember(MemberVO member) {
		memberMapper.updateMember(member);
		memberMapper.updateMember_detail(member);
		
	}