공부방
Interceptor 본문
- HandlerInterceptor(인터페이스)를 구현한 것(또는 HandlerInterorAdapter(클래스)를 상속한 것)
- 요청(requests)을 처리하는 과정에서 요청을 가로채서 처리
- 접근 제어(Auth), 로그(Log)등 비즈니스 로직과 구분되는 반복적이고 부수적인 로직 처리
preHandle
postHandle
afterCompletion
위 세가지를 구현했을 때 출력되는 순서들을 보면 인터셉터는 순서가 중요하다.
servlet-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<context:component-scan base-package="com.ssafy.mvc.controller" />
<interceptors>
<interceptor>
<mapping path="/*"/>
<beans:bean class="com.ssafy.mvc.interceptor.AInterceptor"/>
</interceptor>
<interceptor>
<mapping path="/*"/>
<beans:bean class="com.ssafy.mvc.interceptor.BInterceptor"/>
</interceptor>
<interceptor>
<mapping path="/*"/>
<beans:bean class="com.ssafy.mvc.interceptor.CInterceptor"/>
</interceptor>
</interceptors>
</beans:beans>
===============================================================
HomeContreller.java
package com.ssafy.mvc.controller;
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import javax.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
/**
* Handles requests for the application home page.
*/
@Controller
public class HomeController {
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
logger.info("Welcome home! The client locale is {}.", locale);
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
String formattedDate = dateFormat.format(date);
model.addAttribute("serverTime", formattedDate );
return "home";
}
}
===============================================================
AInterceptor.java
package com.ssafy.mvc.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
//이거 인터셉터로 할랭
//1. 구현 : implements HandlerInterceptor 이게 더 나은 버전
//2. 상속 : extends HandlerInterceptorAdapter (지금은 괜춘 / 나중에는 없앨 수 도 있음)
public class AInterceptor implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("A : preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("A : postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("A : afterComplection");
}
}
===============================================================
BInterceptor
package com.ssafy.mvc.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
//이거 인터셉터로 할랭
//1. 구현 : implements HandlerInterceptor
//2. 상속 : extends HandlerInterceptorAdapter (지금은 괜춘 / 나중에는 없앨 수 도 있음)
public class BInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("B : preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("B : postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("B : afterComplection");
}
}
===============================================================
CInterceptor
package com.ssafy.mvc.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
//이거 인터셉터로 할랭
//1. 구현 : implements HandlerInterceptor
//2. 상속 : extends HandlerInterceptorAdapter (지금은 괜춘 / 나중에는 없앨 수 도 있음)
public class CInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("C : preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("C : postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("C : afterComplection");
}
}
===============================================================
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<title>Home</title>
</head>
<body>
<h1>Hello world!</h1>
<P>The time on the server is ${serverTime}.</P>
</body>
</html>
//
A : preHandle
B : preHandle
C : preHandle
INFO : com.ssafy.mvc.controller.HomeController - Welcome home! The client locale is ko_KR.
C : postHandle
B : postHandle
A : postHandle
C : afterComplection
B : afterComplection
A : afterComplection
언제 쓰일까?
- 인증 및 인가: 인터셉터를 사용하여 사용자의 인증 및 권한을 검사하고, 권한이 없는 사용자에게 액세스 거부 메시지를 반환할 수 있습니다.
- 로깅 및 감사: 인터셉터를 이용하여 모든 요청에 대한 로그를 작성하거나, 특정 액션에 대해 감사 기록을 남길 수 있습니다.
- 퍼포먼스 측정: 인터셉터를 이용하여 요청 처리 시간을 측정하고, 느린 API 호출에 대한 경고를 발생시킬 수 있습니다.
- 요청 및 응답의 가공: 인터셉터를 사용하여 요청 또는 응답 데이터를 수정하거나, 일부 공통 데이터를 추가할 수 있습니다. 예를 들어, 모든 응답에 공통 헤더를 추가하거나, 요청 데이터를 검증 및 정규화할 수 있습니다.
- 캐싱 및 압축: 인터셉터를 사용하여 캐싱 및 압축 로직을 추가하여, 성능을 개선하거나 네트워크 대역폭 사용을 줄일 수 있습니다.
간단한 로그인 구현
등록 페이지
나머지는 위 코드와 동일
HomeController.java
package com.ssafy.mvc.controller;
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import javax.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
/**
* Handles requests for the application home page.
*/
@Controller
public class HomeController {
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
logger.info("Welcome home! The client locale is {}.", locale);
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
String formattedDate = dateFormat.format(date);
model.addAttribute("serverTime", formattedDate );
return "home";
}
//regist라고 하는 요청이 들어오면 regist.jsp 로 보내면 좋겠어
//그런데 요청이 a태그를 이용해서 날아왔어...
@GetMapping("regist")
public String regist() {
//로그인 유무를 파악해서...
//로그인 했으면 계속 고
//로그인 안했으면 다시 메인으로 돌아가...
return "regist";
}
}
===================================================================
home.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<title>Home</title>
</head>
<body>
<h1>Hello world!</h1>
<P>The time on the server is ${serverTime}.</P>
<!-- regist.jsp로 보내는 버튼을 하나 만들고 싶다. -->
<a href="regist">regist.jsp 로 가즈아</a>
</body>
</html>
===================================================================
regist.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>등록페이지</title>
</head>
<body>
<h2>등록페이지</h2>
</body>
</html>
로그인 페이지
나머지 코드는 위와 동일
HomeController
package com.ssafy.mvc.controller;
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import javax.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
/**
* Handles requests for the application home page.
*/
@Controller
public class HomeController {
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
logger.info("Welcome home! The client locale is {}.", locale);
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
String formattedDate = dateFormat.format(date);
model.addAttribute("serverTime", formattedDate );
return "home";
}
//regist라고 하는 요청이 들어오면 regist.jsp 로 보내면 좋겠어
//그런데 요청이 a태그를 이용해서 날아왔어...
@GetMapping("regist")
public String regist() {
//로그인 유무를 파악해서...
//로그인 했으면 계속 고
//로그인 안했으면 다시 메인으로 돌아가...
return "regist";
}
//로그인 요청을 보내는 메서드
@GetMapping("login")
public String loginForm() {
return "login";
}
//로그인 시도가 들어오면 동작할 메서드
@PostMapping("login")
public String login(HttpSession session,String id, String pw) {
//id와 pw를 이용해서 실제 로그인을 해야겠지요.
//Service를 만들어서 Dao DB
if(id.equals("ssafy") && pw.equals("1234")) {
session.setAttribute("id", "ssafy");
return "redirect:/";
}
//아니라면 로그인페이지로 다시가라. 실패했으니까
return "redirect:/login";
}
}
=====================================================================
home.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<title>Home</title>
</head>
<body>
<c:choose>
<c:when test="${empty id }">
<a href="login">로그인 페이지</a>
</c:when>
<c:otherwise>
${id}님 반갑습니다.
</c:otherwise>
</c:choose>
<h1>Hello world!</h1>
<P>The time on the server is ${serverTime}.</P>
<!-- regist.jsp로 보내는 버튼을 하나 만들고 싶다. -->
<a href="regist">regist.jsp 로 가즈아</a>
</body>
</html>
=====================================================================
login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>로그인페이지</title>
</head>
<body>
<h2>로그인페이지입니다.</h2>
<form action="login" method="POST">
<input type="text" name="id"><br>
<input type="password" name="pw"><br>
<input type="submit" ><br>
</form>
</body>
</html>
로그아웃
나머지 코드는 위와 동일
HomeController.java
package com.ssafy.mvc.controller;
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import javax.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
/**
* Handles requests for the application home page.
*/
@Controller
public class HomeController {
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
logger.info("Welcome home! The client locale is {}.", locale);
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
String formattedDate = dateFormat.format(date);
model.addAttribute("serverTime", formattedDate );
return "home";
}
//regist라고 하는 요청이 들어오면 regist.jsp 로 보내면 좋겠어
//그런데 요청이 a태그를 이용해서 날아왔어...
@GetMapping("regist")
public String regist() {
//로그인 유무를 파악해서...
//로그인 했으면 계속 고
//로그인 안했으면 다시 메인으로 돌아가...
return "regist";
}
//로그인 요청을 보내는 메서드
@GetMapping("login")
public String loginForm() {
return "login";
}
//로그인 시도가 들어오면 동작할 메서드
@PostMapping("login")
public String login(HttpSession session,String id, String pw) {
//id와 pw를 이용해서 실제 로그인을 해야겠지요.
//Service를 만들어서 Dao DB
if(id.equals("ssafy") && pw.equals("1234")) {
session.setAttribute("id", "ssafy");
return "redirect:/";
}
//아니라면 로그인페이지로 다시가라. 실패했으니까
return "redirect:/login";
}
@GetMapping("logout")
public String logout(HttpSession session) {
session.removeAttribute("id");
return "redirect:/";
}
}
==================================================================
home.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<title>Home</title>
</head>
<body>
<c:choose>
<c:when test="${empty id }">
<a href="login">로그인 페이지</a>
</c:when>
<c:otherwise>
${id}님 반갑습니다. <a href="logout">로그아웃</a>
</c:otherwise>
</c:choose>
<h1>Hello world!</h1>
<P>The time on the server is ${serverTime}.</P>
<!-- regist.jsp로 보내는 버튼을 하나 만들고 싶다. -->
<a href="regist">regist.jsp 로 가즈아</a>
</body>
</html>
이제 로그인을 하기 전까지 다른 창을 눌러도 로그인 창으로 가게 만들 로그인 인터프리터 생성
다른 코드는 위와 동일
LoginInterceptor.java
package com.ssafy.mvc.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.web.servlet.HandlerInterceptor;
public class LoginInterceptor implements HandlerInterceptor {
//동작 시키기 이전에 검사를 할 것이기 때문에 preHandle을 사용
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//요기서 한번 검사를 해야겠다.
HttpSession session = request.getSession();
//로그인할때 이렇게 id를 직접 세션에 담아 두었다라고 가정
if(session.getAttribute("id") == null) {
response.sendRedirect("login");
return false;
}
return true; //옥헤이 통과
}
}
==================================================================
servlet-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<context:component-scan base-package="com.ssafy.mvc.controller" />
<!-- 일단 빈으로 등록하고 -->
<beans:bean class="com.ssafy.mvc.interceptor.LoginInterceptor" id="confirm"></beans:bean>
<interceptors>
<interceptor>
<mapping path="/*"/>
<exclude-mapping path="/login"/>
<exclude-mapping path="/"/>
<!-- exclude-mapping : 여기로 가는 건 막아라 -->
<beans:ref bean="confirm"/>
</interceptor>
</interceptors>
</beans:beans>
등록페이지를 누르면
로그인 페이지로 이동하게 된다.
로그인을 하고 등록페이지를 누르면
등록페이지로 탈 없이 들어가게된다.
그 이유는
logininterceptor에 return true; //옥헤이 통과 코드에서 만약 아이디가 있다면 true로 판단되기 때문에 login창으로 가지 않고 원래대로 등록페이지로 가게된다.
'스프링' 카테고리의 다른 글
MyBatis (0) | 2023.04.19 |
---|---|
File Upload&File Download (0) | 2023.04.18 |
Spring Web MVC (0) | 2023.04.13 |
Spring AOP (0) | 2023.04.12 |
스프링 기초 (0) | 2023.04.11 |