티스토리 뷰
KH 125일차 - Spring( 인터셉터 3 - 세션 트레킹 : 자동 로그인 ) (******)
monimoni 2022. 8. 25. 16:231. 자동로그인(Remember-Me)의 처리 결과
1 ) Login 수행시 ( LoginInterceptor )
- 자동로그인 쿠키 생성
- 쿠키의 유효기간(즉, 자동로그인 유효설정기간 의미) 설정
- 응답메시지의 `Set-Cookie` 헤더에 자동로그인 쿠키 설정
- tbl_user 테이블에 자동로그인 쿠키정보 기록
2 ) 웹브라우저를 죽이고 다시 수행시켜 접속하는 경우 ( AuthInterceptor )
- 자동로그인 쿠키를 이용하여, Session Scope 에 인증정보(UserVO) 복원
- 무사통과(로그인 창으로 이동시키지 않고, 요청 처리)
3 ) 명시적인 로그아웃 수행시 ( LogoutInterceptor )
- 자동로그인쿠키(remembermeCookie) 삭제
- tbl_user 테이블의 자동로그인쿠키컬럼(rememberme)과 rememberage 컬럼의 값을 모두 NULL로 제거
[ 1. 인터셉터 - 세션 트레킹 ] (*****)
[ + 이전 게시물과 이어집니다. ]
[ 1 - 1. Controller ]
[ + 코드 보기 ]
package org.zerock.myapp.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.zerock.myapp.common.SharedScopeKeys;
import org.zerock.myapp.domain.LoginDTO;
import org.zerock.myapp.domain.UserVO;
import org.zerock.myapp.exception.ControllerException;
import org.zerock.myapp.service.UserService;
import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;
@Log4j2
@NoArgsConstructor
@RequestMapping("/user/")
@Controller
public class LoginController {
@Autowired
private UserService service;
// =================================================
// + 1. 로그인 처리
// =================================================
@PostMapping("/loginPost")
// + @ModelAttribute 어노테이션을 통해 모델에 저장할 수 있다.
public String loginPost ( /* @ModelAttribute("loginDTO") */ LoginDTO dto, Model model, RedirectAttributes rttrs )
throws ControllerException {
log.trace("loginPost({}, {}) invoked.", dto, model);
// + loginPost(LoginDTO(userid=hohohoh, userpw=1234, rememberMe=true)) invoked.
// + view에서 post로 정보가 들어온다.
try {
UserVO vo = this.service.login(dto);
log.info("\t + vo : {}", vo);
if( vo != null ) { // 성공했을 때
model.addAttribute(SharedScopeKeys.LOGIN_KEY, vo);
return "user/loginPost";
// + redirect로 할 경우에는 Request Scope이 깨지기 때문에, model안의 vo가 나오지 못한다.
} else { // 실패했을 때
rttrs.addAttribute(SharedScopeKeys.RESULT, "Login Failed.");
return "redirect:/user/login";
} // if - else
} catch (Exception e) {
throw new ControllerException(e);
} // try - catch
} // loginPost
// =================================================
// + 2. 로그 아웃 처리
// =================================================
// + 로그 아웃 요청시에 수행되어야 할 일 : --> LogoutInterceptor가 수행
// + 1. Session Scope 자체를 파괴시켜야 한다. ( 즉, session.invalidate() 메소드 수행 )
// + 2. 현재 웹 브라우저에 할당된 이름( 세션 ID )도 삭제
// =================================================
@GetMapping("/logout")
public void logout( RedirectAttributes rttrs ) throws ControllerException {
log.trace("logout() invoked.");
// + 로그아웃은 LogoutInterceptor를 설정하기 위한 용도로만 사용될 뿐, 진짜 호출되지는 않는다.
} // logout
// =================================================
} // end class
[ 1 - 2. Interceptor ]
[ + 로그인 처리 인터셉터 ]
[ + 코드 보기 ]
package org.zerock.myapp.interceptor;
import java.util.Date;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.ui.ModelMap;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.zerock.myapp.common.SharedScopeKeys;
import org.zerock.myapp.domain.UserVO;
import org.zerock.myapp.service.UserService;
import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;
@Log4j2
@NoArgsConstructor
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Autowired
private UserService service;
// ===================================================================================================
// + 전제 :
// + 로그인에 성공하면 UserVO를 Session Scope에 올려 놓을 예정이다.
// ===================================================================================================
// + /user/loginPost로 접속 -> preHandle -> LoginController의 로그인 처리 -> postHandle
// + preHandle에서는 이전에 접속한
// ===================================================================================================
// ===================================================================================================
// + 1. preHandle : 로그인 처리
// ===================================================================================================
// + Incoming Request가 Controller's Handler Method로 위임되기 직전에 가로 채는 부분
// + Session Scope에 저장되어 있는 모든 정보를 파괴 수행
// + (*주의*) 명시적으로 로그아웃 요청을 보내지 않는 이상, 세션 자체를 파괴해서는 안된다.
// ===================================================================================================
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) throws Exception {
log.info("========================================================");
log.trace("1. preHandle(req, res, handler) invoked.");
log.info("========================================================");
// ===================================================================
// 1. Session Scope에 접근할 수 있는 HttpSession 객체 획득
// ===================================================================
HttpSession session = req.getSession();
// ===================================================================
// 2. Session Scope에 UserVO 객체가 공유 되어 있으면 삭제 처리
// ===================================================================
UserVO vo = (UserVO) session.getAttribute(SharedScopeKeys.USER_KEY);
// + 현재 Session Scope에 UserVO가 있는지, 로그인 되어있는 상태인지 확인
if ( vo != null ) {
session.removeAttribute(SharedScopeKeys.USER_KEY);
log.info("\t + Remove UserVO : {}", vo);
} else {
log.info("\t + No UserVO found in Session Scope");
} // if : null이 아니라면, UserVO가 Session Scope에 올려진 상태이기에 삭제해버린다.
return true;
} // preHandle
// ===================================================================================================
// + 2. postHandle : 로그인 성공 증빙 + 자동 로그인 처리
// ===================================================================================================
// + 만약 컨트롤러에서 예외가 발생하면, 아래의 callback 메소드는 실행되지 않는다.
@Override
public void postHandle(HttpServletRequest req, HttpServletResponse res, Object handler,
ModelAndView modelAndView) throws Exception {
log.info("========================================================");
log.trace("2. postHandle(req, res, handler, {}) invoked.", modelAndView);
log.info("========================================================");
// ===================================================================
// 1. 로그인 성공 증빙 데이터 바인딩
// ===================================================================
// + 매개변수인 modelAndView에 Model 상자 안에 UserVO 객체가 있는지 확인해 보고 ( 즉, 로그인 결과 )
// + 만약 성공했다면, 이 UserVO 객체를 Session Scope에 있는 로그인 성공증빙으로 올려 놓기로 한다.
// ===================================================================
// 1 ) modelAndView 객체 안에 UserVO가 있는지 확인
// ===================================================================
ModelMap modelMap = modelAndView.getModelMap();
UserVO vo = (UserVO) modelMap.getAttribute(SharedScopeKeys.LOGIN_KEY);
// ===================================================================
// 2 ) UserVO가 있다면( 로그인 성공 시 ) Session Scope에 UserVO를 올려 놓는다. ( 로그인 성공 증빙 )
// ===================================================================
if ( vo != null ) { // + 성공했을 때
// + 현재 Session Scope에 접근하기 위해 HttpSession 객체 생성
HttpSession session = req.getSession();
// + Session Scope에 공유 데이터로 로그인 성공 증빙 데이터를 바인딩
session.setAttribute(SharedScopeKeys.USER_KEY, vo);
// ===================================================================
// 2. 자동 로그인 처리
// ===================================================================
// ===================================================================
// 1 ) 자동 로그인(rememberMe) 옵션의 on / off 여부 확인
// ===================================================================
boolean isRememberMeOption = checkRememberMeOption(req);
log.info("\t + isRememberMeOption : {}", isRememberMeOption);
if ( isRememberMeOption ) { // + 자동 로그인 기능 적용 유무
// ===================================================================
// 2 ) 자동 로그인 쿠키 생성
// ===================================================================
// + Response Message의 Header에 쿠키를 저장해서 보낸다.
// + 이때 쿠키값으로는 현재 브라우저의 이름인 세션ID를 저장하자!
// + (*주의*) 세션 ID는 UUID이다.
String sessionId = session.getId();
Cookie rememberMeCookie = new Cookie(SharedScopeKeys.REMEMBER_ME_KEY, sessionId);
// + 쿠키는 전부 문자열이기에, 숫자로 보일지라도 문자열이다.
// + public Cookie(String name, String value)
// ===================================================================
// 3 ) 자동 로그인 쿠키 설정
// ===================================================================
final int maxAge = 1 * 60 * 60 * 24 * 7;
rememberMeCookie.setMaxAge( maxAge ); // 1주일
// + 쿠키의 유효기간( 자동 로그인 유효기간 ) 설정
// + .setMaxAge의 단위는 초이다.
rememberMeCookie.setPath("/");
// ===================================================================
// + 쿠키 확인
// ===================================================================
log.info("\t + rememberMeCookie - 1. name : {}", rememberMeCookie.getName());
log.info("\t + rememberMeCookie - 2. value : {} ", rememberMeCookie.getValue());
log.info("\t + rememberMeCookie - 3. path : {} ", rememberMeCookie.getPath());
log.info("\t + rememberMeCookie - 4. MaxAge : {} ", rememberMeCookie.getMaxAge());
// ===================================================================
// 4 ) 응답 메세지의 'set-cookie' 헤더에 자동설정
// ===================================================================
res.addCookie(rememberMeCookie);
// ===================================================================
// 5 ) tbl_user 테이블에 자동 로그인 쿠키 정보 기록
// ===================================================================
long currTime = System.currentTimeMillis(); // + 현재 시간
long expireTime = currTime + ( maxAge * 1000 ); // + 유효기간 종료 시간
Date date = new Date(expireTime); // + expireTime을 Date로 변환
boolean isSuccess = this.service.modifyUserWithRememberMe(vo.getUserid(), rememberMeCookie.getValue(), date );
log.info("\t + isUpdateSuccess : {}", isSuccess);
// + UserService.modifyUserWithRememberMe(String userid, String rememberMe, Date rememberAge);
} // inner if
} // if : 성공했다면
} // postHandle
// ===================================================================================================
// + 3. afterCompletion : 주로 자원 해제하는데 사용
// ===================================================================================================
// + afterCompletion은 view처리가 끝난 후 User에게 응답이 나가기 직전에 인터셉트하게 되는데,
// + 만약 처리할게 없다면, 삭제해도 된다.
// ===================================================================================================
@Override
public void afterCompletion(HttpServletRequest req, HttpServletResponse res, Object handler, Exception e)
throws Exception {
log.info("========================================================");
log.trace("3. afterCompletion(req, res, handler, handler, e) invoked.");
log.info("========================================================");
} // afterCompletion
// ===================================================================================================
// + 4. 자동 로그인 on / off 체크 여부 확인 메소드
// ===================================================================================================
private boolean checkRememberMeOption(HttpServletRequest req) {
log.trace("checkRememberMeOption(req) invoked.");
String rememberMe = req.getParameter("rememberMe");
log.info("\t + rememberMe : {}",rememberMe);
// + 전송 파라미터 중에서 rememberMe로 들어온 값을 변수 rememberMe에 저장
return rememberMe != null;
// + rememberMe가 null이 아니면 true를 반환하고,
// + rememberMe가 null이라면 false를 반환한다.
} // checkRememberMeOption
// ===================================================================================================
} // end class
[ + 로그 아웃 처리 인터셉터 ]
[ + 코드 보기 ]
package org.zerock.myapp.interceptor;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.util.WebUtils;
import org.zerock.myapp.common.SharedScopeKeys;
import org.zerock.myapp.domain.UserVO;
import org.zerock.myapp.service.UserService;
import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;
@Log4j2
@NoArgsConstructor
@Component
public class LogoutInterceptor implements HandlerInterceptor {
@Autowired
private UserService service;
// ===================================================================================================
// + 1. preHandle
// ===================================================================================================
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) throws Exception {
log.info("========================================================");
log.trace("1. preHandle(req, res, handler) invoked.");
log.info("========================================================");
// =======================================================================================
// 1. 현재 브라우저에 할당된 Session Scope를 모두 파괴하고, ( 즉, 로그인 성공증빙도 파괴 )
// 웹 브라우저에 할당된 이름( Session ID )도 무효화시킨다.
// =======================================================================================
HttpSession session = req.getSession();
String sessionId = session.getId();
log.info("\t + sessionID : {}", sessionId);
UserVO userVO = (UserVO) session.getAttribute(SharedScopeKeys.USER_KEY);
// + 로그아웃을 하기 위해서 로그아웃을 할 UserVO를 얻어낸다. ( 3단계에서 사용 )
session.invalidate();
log.info("\t + Current Session Scope Destroyed.");
// =======================================================================================
// 2. 로그인 성공시, 자동 로그인 옵션도 on시켜 놓은 웹 브라우저가 로그아웃을 명시적으로 수행하는 경우로
// 1단계도 수행되어야 하지만 자동로그인 쿠키도 삭제해줘야 한다. (***)
// =======================================================================================
Cookie rememberMeCookieToBeDestroyed = WebUtils.getCookie(req, SharedScopeKeys.REMEMBER_ME_KEY );
// + WebUtils.getCookie(HttpServletRequest request, String name)
// + Spring에서는 WebUtils.getCookie를 통해서 원해는 쿠키를 얻어낼 수 있다.
if ( rememberMeCookieToBeDestroyed != null ) {
rememberMeCookieToBeDestroyed.setMaxAge(0);
// + 쿠키는 유효기간을 0으로 설정함으로써 즉시 파괴할 수 있다.
rememberMeCookieToBeDestroyed.setPath("/");
res.addCookie(rememberMeCookieToBeDestroyed);
} // if
// =======================================================================================
// 3. 명시적으로 로그아웃 하는 것이므로, tbl_User 테이블에 있는 자동 로그인 쿠키 컬럼(rememerme)과
// expire 일시를 기록한 rememberage 칼럼의 값을 모두 Null로 제거해 줘야 한다.
// 그래서 명시적 로그아웃한 이후에는 더 이상 자동 로그인이 불가능하게 해야 한다. (*****)
// =======================================================================================
this.service.modifyUserWithRememberMe(userVO.getUserid(), null, null);
// + .modifyUserWithRememberMe(String userid, String rememberMe, Date rememberAge)
// =======================================================================================
// 4. 최종적으로 로그인 화면으로 리다이렉트 수행
// =======================================================================================
req.getSession().setAttribute(SharedScopeKeys.RESULT, "Signed Out Successfully");
// + rttrs.addAttribute(key, value)와 동일한 기능을 한다.
res.sendRedirect("/user/login");
// + 최종적으로 로그인 화면 창으로 리다이렉트 수행
// + Redirect할 경우에는 Session Scope이 파괴된다는 것을 잊지 말아야 한다.
// + 그렇기에, 로드인 페이지에서는 Signed Out Successfully 메시지를 얻어낼 수 없게 된다.
return false;
// + 로그아웃 요청을 컨트롤러의 핸들러로 요청을 보내지 않는다. (***)
// + 그러나, URI는 필요하기에 컨트롤러의 메소드를 삭제하면 인터셉터도 수행이 불가능하다.
// + 로그인 컨트롤러의 로그아웃 메소드는 단순히 형식으로만 존재하게 된다.
} // preHandle
} // end class
[ + 인증 / 인가 인터셉터 ]
[ + 코드 보기 ]
package org.zerock.myapp.interceptor;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.util.WebUtils;
import org.zerock.myapp.common.SharedScopeKeys;
import org.zerock.myapp.domain.UserVO;
import org.zerock.myapp.service.UserService;
import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;
@Log4j2
@NoArgsConstructor
@Component
public class AuthInterceptor implements HandlerInterceptor { // 인증, 인가 처리
@Autowired
private UserService service;
// ===================================================================================================
// + 1. preHandle
// ===================================================================================================
// + (1) 게시판에 관련된 모든 요청에 대해서 인증된 사용자(브라우저)인지를 가장 먼저 체크하고
// + 만약, 인증되지 않은 사용자(웹 브라우저)라면, 로그인을 하도록 로그인 창으로 리다이렉트해야 한다,
// + 위의 로직은 모든 인증 기능에서 가장 먼저 수행되어야 할 "공통 보안 로직"이다.
// ===================================================================================================
// + (2) 자동로그인 기능이 on되어있는 경우, 특수한 처리를 해야 된다.
// + ( 로그인 성공 인증 정보는 없는데, 자동 로그인 쿠키가 요청으로 날라오는 경우 )
// ===================================================================================================
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) throws Exception {
log.info("========================================================");
log.trace("1. preHandle(req, res, handler) invoked.");
log.info("========================================================");
// =======================================================================
// 1. 현재 요청 URI를 전송한 사용자(웹 브라우저)의 인증여부 확인
// =======================================================================
HttpSession session = req.getSession();
log.info("\t + 1. Session ID : {}", session.getId() );
UserVO vo = (UserVO) session.getAttribute(SharedScopeKeys.USER_KEY);
log.info("\t + 2. vo : {}", vo);
// + Session Scope에 있는 공유 데이터 중 로그인 성공 데이터를 찾는다.
if ( vo != null ) { // + 인증된 사용자(웹 브라우저)라면...
log.info("\t + 3. Already Authenticated : {}", vo);
return true;
// + 요청을 컨트롤러의 헨들러로 넘긴다.
} else { // + 인증되지 않은 사용자(웹 브라우저)라면...
// =======================================================================
// 2. 자동로그인 처리
// =======================================================================
// + 자동 로그인 처리에 필요한 처리는 2가지
// + (1) 현재 웹 브라우저에 할당된 Session Scope에 UserVO(인증정보)를 복구해줘야 한다. (***)
// + (2) (1) 조치를 해놓은 상태에서 무사통과시켜야 한다.
// =======================================================================
Cookie rememberMeCookie = WebUtils.getCookie(req, SharedScopeKeys.REMEMBER_ME_KEY);
// + WebUtils.getCookie(HttpServletRequest request, String name);
// + 자동 로그인 처리 쿠키가 존재하는지 확인한다.
// =======================================================================
// 1 ) + 자동 로그인 쿠키가 존재할 경우 (***)
// =======================================================================
if ( rememberMeCookie != null ) {
String cookieName = rememberMeCookie.getName();
String cookieValue = rememberMeCookie.getValue();
log.info("\t + 4. This User has rememberMeCookie.");
log.info( "\t + 5. rememberMeCookie found - name : {}, value : {}", cookieName, cookieValue );
UserVO userVO = this.service.findUserByRememberMe(cookieValue);
log.info("\t + 6. Found userVO : {}", userVO);
// + 이를 통해서 쿠키의 값을 통해서, userVO객체를 얻어낸다.
session.setAttribute(SharedScopeKeys.USER_KEY, userVO);
// + findUserByRememberMe를 통해 UserVO객체를 받아와 로그인 성공증빙과 같이 만든다.
return true;
// + 쿠키가 있을 경우 로그인 성공 인증정보가 없어도 무사히 통과할 수 있도록
// + 요청을 컨트롤러의 헨들러로 넘긴다.
} // if : 자동 로그인 처리 수행 -> 무사통과
// =======================================================================
// 2 ) + 자동 로그인 쿠키가 존재하지 않을 경우
// =======================================================================
log.info("\t + NO Authenticated User");
res.sendRedirect("/user/login");
// + 로그인 창으로 리다이렉트해버린다.
return false;
// + 요청을 컨트롤러의 헨들러로 넘기지 않는다.
// + 인증되지 않은 사용자의 경우에는 게시물로 접근이 불가능해야 한다.
} // if - else
} // preHandle
// ===================================================================================================
// + 2. postHandle
// ===================================================================================================
// + 만약 컨트롤러에서 예외가 발생하면, 아래의 callback 메소드는 실행되지 않는다.
@Override
public void postHandle(HttpServletRequest req, HttpServletResponse res, Object handler,
ModelAndView modelAndView) throws Exception {
log.info("========================================================");
log.trace("2. postHandle(req, res, handler, {}) invoked.", modelAndView);
log.info("========================================================");
} // postHandle
// ===================================================================================================
// + 3. afterCompletion
// ===================================================================================================
@Override
public void afterCompletion(HttpServletRequest req, HttpServletResponse res, Object handler, Exception e)
throws Exception {
log.info("========================================================");
log.trace("3. afterCompletion(req, res, handler, handler, e) invoked.");
log.info("========================================================");
} // afterCompletion
} // end class
[ 1 - 3. Mapper에 sql문 추가 ]
[ + 코드 보기 ]
<?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="org.zerock.myapp.persistence.UserDAO">
<select
id="selectUser"
resultType="org.zerock.myapp.domain.UserVO">
<![CDATA[
SELECT *
FROM tbl_user
WHERE userid = #{userid} AND userpw = #{userpw}
]]>
</select>
<!-- ========================================================================================= -->
<select
id="selectUserByRememberMe"
resultType="org.zerock.myapp.domain.UserVO">
SELECT userid, userpw, uname, upoint
FROM tbl_user
WHERE rememberme = #{rememberMe} AND rememberage >= current_date
<!-- rememberage는 유효기간으로, 현재날짜보다 유효기간이 커야지 유효하다. -->
</select>
<!-- ========================================================================================= -->
<update id="updateUserWithRememberMe">
UPDATE tbl_user
SET
rememberme = #{rememberMe, jdbcType=VARCHAR},
rememberage = #{rememberAge, jdbcType=DATE}
WHERE
userid = #{userid}
</update>
</mapper>
[ 1 - 4. DAO 추가 ]
[ + 코드 보기 ]
package org.zerock.myapp.persistence;
import java.util.Date;
import org.zerock.myapp.domain.LoginDTO;
import org.zerock.myapp.domain.UserVO;
import org.zerock.myapp.exception.DAOException;
public interface UserDAO {
// 1. 로그인 창에서 입력한 아이디와 암호에 매칭되는 사용자의 정보 획득
public abstract UserVO selectUser(LoginDTO dto) throws DAOException;
// 2. 자동 로그인 설정이 on된 상태로 로그인 성공시, 쿠키 정보를 기록
public abstract int updateUserWithRememberMe( String userid, String rememberMe, Date rememberAge ) throws DAOException;
// 3. 자동 로그인 쿠키값으로 사용자를 조회하여 인증정보를 생성
public abstract UserVO selectUserByRememberMe(String rememberMe) throws DAOException;
} // end interface
[ 1 - 5. DAO 구현 ]
[ + 코드 보기 ]
package org.zerock.myapp.persistence;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.zerock.myapp.domain.LoginDTO;
import org.zerock.myapp.domain.UserVO;
import org.zerock.myapp.exception.DAOException;
import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;
@Log4j2
@NoArgsConstructor
@Repository
public class UserDAOImpl implements UserDAO {
@Autowired
private SqlSessionFactory sqlSessionFactory;
@Override
public UserVO selectUser(LoginDTO dto) throws DAOException {
log.trace("selectUser({}) invoked.", dto);
SqlSession sqlSession = this.sqlSessionFactory.openSession();
try ( sqlSession ){
String namespace = "org.zerock.myapp.persistence.UserDAO";
String sqlId = "selectUser";
String sql = namespace + "." + sqlId;
return sqlSession.<UserVO>selectOne(sql, dto);
} catch(Exception e) {
throw new DAOException(e);
} // try - with - resources
} // selectUser
@Override
public int updateUserWithRememberMe(String userid, String rememberMe, Date rememberAge) throws DAOException {
log.trace("updateUserWithRememberMe({}, {}, {}) invoked.", userid, rememberMe, rememberAge );
SqlSession sqlSession = this.sqlSessionFactory.openSession();
try ( sqlSession ){
String namespace = "org.zerock.myapp.persistence.UserDAO";
String sqlId = "updateUserWithRememberMe";
String sql = namespace + "." + sqlId;
Map<String, Object> params = new HashMap<>();
params.put("userid", userid);
params.put("rememberMe", rememberMe);
params.put("rememberAge", rememberAge);
return sqlSession.update(sql, params);
} catch(Exception e) {
throw new DAOException(e);
} // try - with - resources
} // updateUserWithRememberMe
@Override
public UserVO selectUserByRememberMe(String rememberMe) throws DAOException {
log.trace("selectUserByRememberMe({}) invoked.", rememberMe);
SqlSession sqlSession = this.sqlSessionFactory.openSession();
try ( sqlSession ){
String namespace = "org.zerock.myapp.persistence.UserDAO";
String sqlId = "selectUserByRememberMe";
String sql = namespace + "." + sqlId;
return sqlSession.<UserVO>selectOne(sql, rememberMe);
} catch(Exception e) {
throw new DAOException(e);
} // try - with - resources
} // selectUserByRememberMe
} // end class
[ 1 - 6. Service 추가 ]
[ + 코드 보기 ]
package org.zerock.myapp.service;
import java.util.Date;
import org.zerock.myapp.domain.LoginDTO;
import org.zerock.myapp.domain.UserVO;
import org.zerock.myapp.exception.DAOException;
import org.zerock.myapp.exception.ServiceException;
public interface UserService {
// =====================================================================
// 1. 로그인 창에서 입력한 아이디와 암호에 매칭되는 회원이 있는지 확인
// =====================================================================
// ReturnType을 Boolean이 아닌 UserVO로 하는 이유는,
// 이 객체를 바로 로그인 성공 정보로 Session Scope에 바인딩시키기 위해서이다.
public abstract UserVO login(LoginDTO dto) throws ServiceException;
// =====================================================================
// 2. 자동 로그인 설정이 on된 상태로 로그인 성공시, 쿠키 정보를 기록
// =====================================================================
public abstract boolean modifyUserWithRememberMe( String userid, String rememberMe, Date rememberAge ) throws ServiceException;
// =====================================================================
// 3. 자동 로그인 쿠키값으로 사용자를 조회하여 인증정보를 생성
// =====================================================================
public abstract UserVO findUserByRememberMe(String rememberMe) throws ServiceException;
} // end interface
[ 1 - 7. Service 구현 ]
[ + 코드 보기 ]
package org.zerock.myapp.service;
import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.zerock.myapp.domain.LoginDTO;
import org.zerock.myapp.domain.UserVO;
import org.zerock.myapp.exception.DAOException;
import org.zerock.myapp.exception.ServiceException;
import org.zerock.myapp.persistence.UserDAO;
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j2;
@Log4j2
@AllArgsConstructor
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDAO userDAO;
// ===============================================================
// + 1. 로그인 처리
// ===============================================================
@Override
public UserVO login(LoginDTO dto) throws ServiceException {
log.trace("login({}) invoked.", dto);
try {
return this.userDAO.selectUser(dto);
} catch ( DAOException e ) {
throw new ServiceException(e);
} // try - catch
} // login
// ===============================================================
@Override
public boolean modifyUserWithRememberMe(String userid, String rememberMe, Date rememberAge) throws ServiceException {
log.trace("modifyUserWithRememberMe({}, {}, {}) invoked.", userid, rememberMe, rememberAge);
try {
return this.userDAO.updateUserWithRememberMe(userid, rememberMe, rememberAge) == 1;
} catch ( DAOException e ) {
throw new ServiceException(e);
} // try - catch
} // modifyUserWithRememberMe
// ===============================================================
@Override
public UserVO findUserByRememberMe(String rememberMe) throws ServiceException {
log.trace("findUserByRememberMe({}) invoked.", rememberMe);
try {
return this.userDAO.selectUserByRememberMe(rememberMe);
} catch ( DAOException e ) {
throw new ServiceException(e);
} // try - catch
} // findUserByRememberMe
// ===============================================================
} // end class
'KH 정보교육원 [ Java ]' 카테고리의 다른 글
KH 127일차 - Spring( AOP 2 / 트랜잭션[미완성] ) (******) (0) | 2022.08.29 |
---|---|
KH 126일차 - Spring ( AOP ) (***) (0) | 2022.08.26 |
KH 124일차 - Spring ( 인터셉터 - 세션 트레킹 : 로그인 / 로그아웃 / 인증 / 인가 / 자동 로그인 기능 ) (*********) (0) | 2022.08.24 |
KH 123일차 - Spring ( 인터셉터 ) (***) (0) | 2022.08.24 |
KH 122일차 - Spring ( Restful 방식 2 / 인터셉터 ) (****) (0) | 2022.08.22 |