[ JSP ] JQuery Cookie를 이용하여 아이디 저장, 로그인 유지(자동 로그인) 구현하기, interceptor를 이용한 로그인 유저 권한 설정

duck-ach·2022년 12월 6일
0

JSP

목록 보기
13/14

Cookie 란?

  1. 웹 서버가 웹 브라우저에게 보내어 저장했다가 서버의 부가적인 요청이 있을 때 다시 서버로 보내주는 문자열 정보
  2. 웹 페이지 방문 시 방문 기록 등 브라우저에서의 정보들이 저장된 텍스트 파일
  3. 쿠키는 서버를 대신하여 웹 브라우저에 저장하고 요청을 할 때 그 정보를 서버에 보내 사용자를 식별할 수 있게 한다.
  4. 세션관리, 개인화, 트래킹에 사용되며, 세션은 쿠키를 이용한다.
  5. 데이터 형태는 Key, Value 형태로 String 문이며, 4KB 이상 저장이 불가능하다.
  6. 브라우저마다 저장되는 쿠키가 다르다. (크롬, 익스플로러, 사파리, 파이어폭스 등등 각각 다르다)

쿠키 종류

  • 기술적 쿠키 : 사람인지 아니면 어플리케이션인지 구분 기능 수행
  • 분석 쿠키 : 어떤 종류 검색하는지, 많이 검색하는지, 시간, 언어 대상 등의 정보를 수집
  • 광고 쿠키 : 검색내용, 국가, 언어에 따라 광고를 게재

쿠키의 대표적인 쓰임새
1. ID 정보 저장(로그인 상태 유지)
2. 최근 검색한 정보 광고 추천
3. 쇼핑몰 장바구니 저장 기능
4. 3일간, 7일간 등 일정 기간 다시 보지 않기 체크(쿠키 날짜 기록 계산)

이번에 쓸 쿠키의 용도는 쿠키로 인하여 페이지 이동 시마다 로그인을 다시 하지 않고 사용자 정보를 유지할 수 있다.
쿠키가 없다면 해당 사용자 정보 파라미터를 계속 페이지마다 넘겨줘야 한다.


JQuery Cookie Import

cdnjs.com 으로가서 jquery cookie 를 검색해준다.

</>버튼을 눌러서 링크를 카피해준다.

그 후, 자동 로그인을 구현할 jsp의 jquery script링크 아래에 붙여넣기 해준다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<c:set var="contextPath" value="${pageContext.request.contextPath}" />
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="${contextPath}/resources/js/jquery-3.6.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js" integrity="sha512-3j3VU6WC5rPQB4Ld1jnLV7Kd5xr+cq9avvhwqzbH/taCRNURoeEpoPBK9pDyeukwSxwRPJ8fDgvYXd6SkaZ2TA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head>
<body>

	<div>
	
		<h1>로그인</h1>
		
		<form id="frm_login" action="${contextPath}/user/login" method="post">
			
			<input type="hidden" name="url" value="${url}">
			
			<div>
				<label for="id">아이디</label>
				<input type="text" name="id" id="id">
			</div>
			
			<div>
				<label for="pw">비밀번호</label>
				<input type="password" name="pw" id="pw">
			</div>
			
			<div>			
				<button>로그인</button>
			</div>
			
			<div>			
				<label for="rememberId">
					<input type="checkbox" id="rememberId">
					아이디 저장
				</label>
				<label for="keepLogin">
					<input type="checkbox" name="keepLogin" value="keep" id="keepLogin">
					로그인 유지
				</label>
			</div>
		
		</form>
			
		<div>
			<a href="${contextPath}/member/findId">아이디 찾기</a> | 
			<a href="${contextPath}/member/findPw">비밀번호 찾기</a>
		</div>
	
	</div>
	
</body>
</html>

꼭 jquery cdn또는 경로 아래에 jquery cookie cdn을 가지고와야 $가 인식되어 쿠키를 사용할 수 있다.

아이디 저장 Script 구현

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<c:set var="contextPath" value="${pageContext.request.contextPath}" />
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="${contextPath}/resources/js/jquery-3.6.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js" integrity="sha512-3j3VU6WC5rPQB4Ld1jnLV7Kd5xr+cq9avvhwqzbH/taCRNURoeEpoPBK9pDyeukwSxwRPJ8fDgvYXd6SkaZ2TA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
	$(function(){
		fn_login();
		fn_displayRememberId();
	});
	
	function fn_login() {
		$('#frm_login').submit(function(event){ // submit을 취소할 수 있게끔 event 객체를 잡아준다.
			
			// 아이디와 패스워드가 입력되지 않았을 경우
			if($('#id').val() == '' || $('#pw').val() == '') {
				alert('아이디와 패스워드를 모두 입력하세요');
				event.preventDefault();
				return; // 아래 if문을 막는다.
			}
		
			// 아이디 저장
			if($('#rememberId').is(':checked')) {		// Java에서 쿠키를 처리하려면 Service단에서 Cookie 클래스를 이용하여 request에 저장해주는 방식을 사용했다.
				$.cookie('rememberId', $('#id').val()); // 쿠키ID, 값 순으로 저장을 하면 편리
			} else {
				$.cookie('rememberId', '');
			}											
			
		});
	}
	
	function fn_displayRememberId() {
		// 아이디저장 쿠키 불러오기
		let rememberId = $.cookie('rememberId');
		if(rememberId == '') {
			$('#id').val('');
			$('#rememberId').prop('checked', false); // check 해제
		} else {
			$('#id').val(rememberId);
			$('#rememberId').prop('checked', true); // check 해제
		}
		
	}
</script>
</head>
<body>

	<div>
	
		<h1>로그인</h1>
		
		<form id="frm_login" action="${contextPath}/user/login" method="post">
			
			<input type="hidden" name="url" value="${url}">
			
			<div>
				<label for="id">아이디</label>
				<input type="text" name="id" id="id">
			</div>
			
			<div>
				<label for="pw">비밀번호</label>
				<input type="password" name="pw" id="pw">
			</div>
			
			<div>			
				<button>로그인</button>
			</div>
			
			<div>			
				<label for="rememberId">
					<input type="checkbox" id="rememberId">
					아이디 저장
				</label>
				<label for="keepLogin">
					<input type="checkbox" name="keepLogin" value="keep" id="keepLogin">
					로그인 유지
				</label>
			</div>
		
		</form>
			
		<div>
			<a href="${contextPath}/member/findId">아이디 찾기</a> | 
			<a href="${contextPath}/member/findPw">비밀번호 찾기</a>
		</div>
	
	</div>
	
</body>
</html>

javascript는 위에서부터 코드를 읽어 실행하기 때문에 익명함수 $(function(){}) 안에 넣어 실행을 시켜주거나 $(document).ready(function(){}) ready() 라는 jquery 함수를 이용하여 script가 위에있더라도 정상적으로 실행될 수 있도록 해야한다.

아이디 저장을 체크하고 로그인을 했다가 로그아웃을 하더라도 아이디가 저장되어 자동으로 입력 되어있는 것이 보인다.

로그인 유지

로그인 유지를 할 때에는 패스워드를 cookie에다가 저장하기에는 보안적으로 문제가 있기 때문에 session_id를 쿠키에 저장하고(예시: 쿠키명 keepLogin), session_id를 DB에도 저장해둔다(SESSION_ID 컬럼에 session_id저장, SESSION_LIMIT_DATE 칼럼에 세션만료일 저장).
그리고 사용할 경우 쿠키와 DB의 session_id를 비교하고 일치할 경우 해당 데이터를 꺼내오는 형식으로 꺼내오게된다.

<label for="keepLogin">
<input type="checkbox" name="keepLogin" id="keepLogin">
로그인 유지
</label>

session_id는 name값인 keepLogin이 된다.
Controller

@PostMapping("/user/login")
public void login(HttpServletRequest request, HttpServletResponse response) {
	userService.login(request, response);
}

Controller의 login요청에서는 request에 요청값을 담아 service의 login메소드를 호출하게 된다.

service interface

package com.gdu.app13.service;

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

public interface UserService {
	public void login(HttpServletRequest request, HttpServletResponse response);
	public void keepLogin(HttpServletRequest request, HttpServletResponse response);

service implements

package com.gdu.app13.service;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

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.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.gdu.app13.domain.RetireUserDTO;
import com.gdu.app13.domain.UserDTO;
import com.gdu.app13.mapper.UserMapper;

@PropertySource(value = {"classpath:email.properties"})
@Service
public class UserServiceImpl implements UserService {
	
	// field값
	@Autowired
	private UserMapper userMapper;	
	
	@Override
	public void login(HttpServletRequest request, HttpServletResponse response) {
		//자기 스스로 이동할 수 있는 코드 영역이 있기 때문에 반환타입을 void로 처리

		// 파라미터
		String url = request.getParameter("url");
		String id = request.getParameter("id");
		String pw = request.getParameter("pw");
		
		// pw는 DB에 저장된 데이터와 동일한 형태로 가공
		pw = securityUtil.sha256(pw);
		
		Map<String, Object> userMap = new HashMap<String, Object>();
		userMap.put("id", id);
		userMap.put("pw", pw);
	
		// id, pw가 일치하는 회원을 DB에서 조회하기
		UserDTO loginUser = userMapper.selectUserByMap(userMap);
		
		// id, pw가 일치하는 회원이 있다 : 로그인 기록 남기기 + session에 loginUser 저장하기
		if(loginUser != null) {
			
			// 로그인 유지 처리는 keepLogin 메소드가 따로 처리함
			keepLogin(request, response);
			
			// 로그인 처리를 위해서 session에 로그인 된 사용자 정보를 올려둠
			request.getSession().setAttribute("loginUser", loginUser);
			
			// 로그인 기록 남기기
			int updateResult = userMapper.updateAccessLog(id);
			if(updateResult == 0) {
				userMapper.insertAccessLog(id);
			}
			
			
			// 이동 (로그인페이지 이전 페이지로 되돌아가기)
			try {
				response.sendRedirect(url);
			} catch(IOException e) {
				e.printStackTrace();
			}
			
		}
		// id, pw가 일치하는 회원이 없다 : 로그인 페이지로 돌려 보내기
		else {
			// 응답
			try {
				
				response.setContentType("text/html; charset=UTF-8");
				PrintWriter out = response.getWriter();
				
				out.println("<script>");
				out.println("alert('일치하는 회원 정보가 없습니다.');");
				out.println("location.href='" + request.getContextPath() + "/user/login/form';");
				out.println("</script>");
				out.close();
				
			} catch(Exception e) {
				e.printStackTrace();
			}
		}
		
	}
	
	@Override
	public void keepLogin(HttpServletRequest request, HttpServletResponse response) {
		/*
			로그인 유지를 체크한 경우
			
			1. session_id를 쿠키에 저장해둔다.
				(쿠키명 : keepLogin)
			2. session_id를 DB에 저장해 둔다.
				(SESSION_ID 칼럼에 session_id를 저장하고, 
				 SESSION_LIMIT_DATE 칼럼에 로그인유지가 언제까지 유효한지(세션 만료일)를 (나는 15일 후 날짜)저장
			
			로그인 유지를 체크하지 않은 경우
			1. 쿠키 또는 DB중 하나만 삭제하면 된다. (둘다 매칭해서 같은 경우 저장된것을 꺼내오는 시스템이라서)
			   편의상 쿠키명 keepLogin을 제거한느 것으로 처리한다. 
			
		*/
		String id = request.getParameter("id");
		String keepLogin = request.getParameter("keepLogin");
		
		if(keepLogin != null) { // 로그인 유지를 체크한 경우 : keep
			
			// session_id
			String sessionId = request.getSession().getId();
			
			// 1. session_id를 쿠키에 저장하기
			Cookie cookie = new Cookie("keepLogin", sessionId); // session_id 값
			cookie.setMaxAge(60 * 60 * 24 * 15); // 60초(1분), 60분(1시간), 24시간(1일), 15일 // 총 15일
			cookie.setPath(request.getContextPath()); // localhost:9090/app13이라는 contextPath를 사용하는 모든 페이지에서 쿠키를 사용할수있다.
			response.addCookie(cookie); // 쿠키를 클라이언트에게 보내는 것은 응답이므로 response에 담는다.
			
			// 2. session_id를 DB에 저장하기
			UserDTO user = UserDTO.builder()
					.id(id)
					.sessionId(sessionId)		// timeStamp 1/1000 이므로, timeStamp에 15일을 더한 값
					.sessionLimitDate(new Date(System.currentTimeMillis() + (60 * 60 * 24 * 15) * 1000)) 
					.build();
			
			userMapper.updateSessionInfo(user);
			
		} else { // 로그인 유지를 체크하지 않은 경우 : Null
			
			// keepLogin 쿠키 제거하기
			Cookie cookie = new Cookie("keepLogin", ""); // keepLogin이라는 값을 빈 문자열로 만듦
			cookie.setMaxAge(0); // 쿠키 유지 시간이 0이면 삭제를 의미함
			cookie.setPath(request.getContextPath());
			response.addCookie(cookie); // 응답에 쿠키 정보를 담음
			
		}
		
	}
	
	@Override
	public void logout(HttpServletRequest request, HttpServletResponse response) {
		// 로그아웃 하려면 세션 초기화. (자동로그인을 풀려면 쿠키 한쪽 제거해줘야함)
		
		// 로그아웃 처리
		HttpSession session = request.getSession(); // 세션
		if(session.getAttribute("loginUser") != null) {
			session.invalidate(); // 세션 초기화			
		}
		// 위 코드를 request.getSession().invalidate()로 줄일 수 있음
		
		// 로그인 유지 풀기
		// cookie의 이름 중 "keepLogin"이 있다면 // 원래 점검코드가 있었는데 있으나 없으나 덮어쓰기함
		Cookie cookie = new Cookie("keepLogin", ""); // keepLogin이라는 값을 빈 문자열로 만듦
		cookie.setMaxAge(0); // 쿠키 유지 시간이 0이면 삭제를 의미함
		cookie.setPath(request.getContextPath());
		response.addCookie(cookie); // 응답에 쿠키정보를 담음
		
		
		
	}
	
	@Override
	public UserDTO getUserBySessionId(Map<String, Object> map) {
		return userMapper.selectUserByMap(map);
	}
	
}

로그인 처리는


처음에는 저장된 cookie가 없다.


로그인을 수행하면 keepLogin 이라는 세션아이디를 확인할 수 있다.

이제 로그아웃을 하지않는 이상 15일동안 인터넷 브라우저가 꺼지더라도 컴퓨터가 꺼지더라도 로그인이 유지된다.

번외) Interceptor를 이용한 로그인/비로그인 권한 처리

Interceptor는 Contoller의 모든 요청 이전에 알아서 일을 처리해주는 친구다.
나는 이 친구로 로그인이 완료된 사용자가 주소창으로 로그인페이지로 이동하거나, 회원가입을 하는 약관페이지를 이동하거나, 가입페이지 이동 등의 요청을 하면 이를 막아주는 역할을 하게 할것이다.


HandlerInterceptor interface를 구현하는 Java class를 하나 만들어준다.

ctrl + space bar를 입력하면 여러가지 구현체와 메소드들을 확인할 수 있다.
preHandle : Controller의 모든 요청 이전에 Interceptor가 개입
postHandle : Controller의 모든 요청 이후에 Interceptor가 개입

package com.gdu.app13.interceptor;

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

import org.springframework.web.servlet.HandlerInterceptor;

public class KeepLoginInterceptor implements HandlerInterceptor {

	// 모든 요청 이전에 KeppLoginInterceptor가 개입
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		// TODO Auto-generated method stub
		return HandlerInterceptor.super.preHandle(request, response, handler);
	}
	
}

이렇게 자동으로 Override 된다. 필요없는 코드들은 지워주고, 내가 넣고싶은 기능을 코드로 짜서 넣으면 된다.
Interceptor

package com.gdu.app13.interceptor;

import java.io.PrintWriter;

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

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

@Component
public class PreventLoginInterceptor implements HandlerInterceptor {

	// 로그인이 완료된 사용자가
	// 로그인 페이지 이동, 약관페이지, 가입페이지 이동 등의 요청을 하면 이를 막는 인터셉터
	
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		
		if(request.getSession().getAttribute("loginUser") != null) { // login이 되어있지 않으면?
			
			response.setContentType("text/html; charset=UTF-8");
			PrintWriter out = response.getWriter();
			
			out.println("<script>");
			out.println("alert('해당 기능은 사용할 수 없습니다..');");
			out.println("location.href='" + request.getContextPath() + "';");
			out.println("</script>");
			out.close();
			
			return false; // 컨트롤러의 요청이 처리되지 않는다.
			
		} else {			
			return true; // 컨트롤러의 요청이 처리된다.
		}
		
	}
	
}

servlet-context.xml

<interceptors>
	<interceptor>
		<mapping path="/user/login/form"/>
    	<mapping path="/user/join/write"/>
    	<mapping path="/user/agree"/>
    	<beans:bean class="com.gdu.app13.interceptor.PreventLoginInterceptor" />
	</interceptor>
</interceptors>

servlet-context.xml에 bean으로 등록해야 이 interceptor가 작동할 수 있다.

사용자가 로그인을 하면 저장되는 Session 정보를 이용하여 로그인의 유무를 파악하고, 로그인을 했을 경우 로그인을 다시할 수 있는 페이지를 이동하지 못하도록 구현했다.

이제 컨트롤러의 메소드 중 interceptor를 지정할 요소 앞에 requiredLogin_이라는 키워드를 지정해주면 해당 Mapping은 interceptor를 거치고 난 후 컨트롤러로 들어가게 된다.
Controller

package com.gdu.app13.controller;

import java.util.HashMap;
import java.util.Map;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
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.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.gdu.app13.service.UserService;

@Controller
public class UserController {
	
	@Autowired
	private UserService userService; 
	
	// 컨트롤러의 모든 요청 이전에 일어나는 intercepter가 일어난다.
	// intercepter는 가로채기를 하는 애다. 어떤 처리를 하기전에 자기가 개입해서 일처리를 하고 들어옴
	// 모든 intercepter의 위치는 여기(field와 Mapping 사이)
	// true와 false를 반환함. (true : intercepter가 개입하고 일을 처리, false : 작업을 취소하고 이건안되겠다 하면서 막아버림)
	// 만들어만 두면 스스로 개입한다.
	
	@GetMapping("/")
	public String index() {
		return "index";
	}
	
	@GetMapping("/user/agree")
	public String agree() {
		return "user/agree";
	}
	
	@GetMapping("/user/join/write")
	public String joinWrite(@RequestParam(required=false) String location
						, @RequestParam(required=false) String promotion
						, Model model) {
		model.addAttribute("location", location);	// jsp에서는 request에 담아 값을 넘겨줬지만
		model.addAttribute("promotion", promotion); // spring에서 forward 할때 model로 넘겨줌
		return "user/join";
	}
	
	@ResponseBody // ajax 처리를 위해 @ResponseBody
	@GetMapping(value="/user/checkReduceId", produces=MediaType.APPLICATION_JSON_VALUE)
	public Map<String, Object> checkReduceId(String id) {
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("id", id);
		return userService.isReduceId(map);
	}

	@ResponseBody // ajax 처리를 위해 @ResponseBody
	@GetMapping(value="/user/checkReduceEmail", produces=MediaType.APPLICATION_JSON_VALUE)
	public Map<String, Object> checkReduceEmail(String email) {
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("email", email);
		return userService.isReduceEmail(map);
	}
	
	@ResponseBody // ajax 처리를 위해 @ResponseBody
	@GetMapping(value="/user/sendAuthCode", produces=MediaType.APPLICATION_JSON_VALUE)
	public Map<String, Object> sendAuthCode(String email) {
		return userService.sendAuthCode(email);
	}
	
	@PostMapping("/user/join")
	public void join(HttpServletRequest request, HttpServletResponse response) {
		userService.join(request, response);
	}
	
	@GetMapping("user/retire")
	public void retire(HttpServletRequest request, HttpServletResponse response) {
		userService.retire(request, response);
	}
	
	// login페이지 이동
	@GetMapping("/user/login/form") // <a> 태그를 이용하여 값을 전달하면 GET 방식이다.
	public String loginForm(HttpServletRequest request, Model model) {
		// 요청 헤더 referer : 이전 페이지의 주소가 저장
		model.addAttribute("url", request.getHeader("referer")); // 로그인 후 되돌아 갈 주소 url (header값중에 referer)
		
		// 네이버 로그인
		model.addAttribute("apiURL", userService.getNaverLoginApiURL(request));
		
		return "user/login";
	}
	
	@PostMapping("/user/login")
	public void login(HttpServletRequest request, HttpServletResponse response) {
		userService.login(request, response);
	}
	
	@GetMapping("/user/naver/login")
	public void naverLogin(HttpServletRequest request) {
		userService.getNaverLoginTokenNProfile(request);
	}
	
	
	@GetMapping("/user/logout")
	public String logout(HttpServletRequest request, HttpServletResponse response) {// 세션 초기화 (자동로그인을 풀려면 쿠키 한쪽 제거해줘야함)
		userService.logout(request, response);
		return "redirect:/";
	}
	
	@GetMapping("/user/check/form")
	public String requiredLogin_checkForm() {
		return "user/check";
	}
	
	@ResponseBody
	@PostMapping(value="/user/check/pw", produces="application/json") // true false 들어갈예정이라 charset은 굳이 해주지 않아도 된다.
	public Map<String, Object> requiredLogin_checkPw(HttpServletRequest request) { // service에서 Map을 반환하므로 Map, request를 필요로 하므로 request를 인자값으로 넘겨준다.
		return userService.confirmPassword(request);
	}
	
	@GetMapping("/user/mypage") // location으로 이동하는것이기 때문에 GetMapping
	public String requiredLogin_mypage() {
		return "user/mypage";
	}
	
	@PostMapping("/user/modify/pw")
	public void requiredLogin_modifyPw(HttpServletRequest request, HttpServletResponse response) {
		userService.modifyPassword(request, response);
	}
	
	@GetMapping("/user/sleep/display") // sendRedirect라서 주소창이동. GETMAPPING
	public String sleepDisplay() {
		return "user/sleep";
	}
	
	@PostMapping("/user/restore")
	public void restore(HttpServletRequest request, HttpServletResponse response) {
		userService.restoreUser(request, response);
	}
}


로그인이 된 상태에서


이렇게 alert창을 띄운 후, contextPath의 주소인 index 페이지로 돌아가도록 설정했다.

profile
자몽 허니 블랙티와 아메리카노 사이 그 어딘가

0개의 댓글