1. HandlerInterceptor
HandlerInterceptor는 특정 URI 호출을 가로채는 역할을 한다. 이를 이용하여 기존 컨트롤러의 로직 수정 없이도 사전이나 사후 제어가 가능하다
1) HandlerInterceptor 메소드
- preHandle(request, response, handler)
: 지정된 컨트롤러의 동작 이전에 수행할 동작 (사전제어)
- postHandle(request, response, handler, modelAndView)
: 지정된 컨트롤러의 동작 이후에 처리할 동작 (사후제어)
spring MVC의 Dispatcher Servlet이 화면을 처리하기 전에 동작
- afterCompletion(request, response, handler, exception)
: Dispatcher Servlet의 화면 처리가 완료된 이후 처리할 동작
2) HandlerInterceptor vs Filter
두 기능 모드 특정 URI에 접근할 때 제어하는 용도로 사용된다. 두 기능의 가장 큰 차이는 Context(실행 영역)에 있다.
Filter는 웹 어플리케이션 내에서 동작하기 때문에 Spring Context에 접근하기 어렵다
반면 Interceptor의 경우 Spring 영역 내에서 동작하기 때문에, Spring Context에 접근하기 쉽다
2. HandlerInterceptor 사용 설정
HandlerInterceptorAdaptor를 상속한 Interceptor 클래스를 작성한다
package org.sample.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
public class SampleInterceptor extends HandlerInterceptorAdaptor {
@Override
public boolean preHandler( 어떤건 preHandle 도있음
HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
System.out.println("pre handle........");
return true;
}
@Override
public void postHandler(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("post handle.......");
}
}
1) servlet-context.xml (SpringFramework)
servlet-context.xml
<beans:bean id="sampleInterceptor"
class="org.sample.interceptor.SampleInterceptor"/>
<interceptors>
<interceptor>
<mapping path="/doA"/>
<mapping path="/doB"/>
<beans:ref bean="sampleInterceptor"/>
</interceptor>
</interceptors>
전자정부프레임워크는
아래와같이 쓰면됨(LoginInterceptro는 사용자가 지정한이름)
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean id="loginInterceptor" class="egovframework.com.main.web.interceptor.LoginInterceptor" >
</bean>
</mvc:interceptor>
</mvc:interceptors>
/doA URI 실행 결과
pre handle........
doA...............
post handle.......
1) Configure Class (SpringBoot)
SampleWebMvcConfig.java
package org.sample;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.sample.interceptor.SampleInterceptor;
@Configuration
public class SampleWebMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
List<String> URL_PATTERNS = Arrays.asList("/doA", "doB");
registry.addInterceptor(new SampleInterceptor())
.addPathPatterns(URL_PATTERNS)
.excludePathPatterns("/login")
.excludePathPatterns("/admin/**/");
}
}
addInterceptors 메서드를 구현할 때 위와 같이 구현을 하며, 인터세버 구현 시 메서드 체이닝이 되어있어 연속적으로 다른 추가 패턴도 등록할 수 있다.
addPathPatterns는 적용할 url 패턴을 설정한다. *, ** 등을 사용한 URI Pattern String을 전송하거나, URI Pattern 배열을 전송할 수 있다.
excludePathPatterns의 경우 인터셉터를 제외할 url 패턴을 등록하는 메서드로써 해당 url로 접근 시 인터셉터를 적용하지 않게 된다.
3. 로그인 처리
1) LoginInterceptor
로그인한 사용자에 대해서 postHandle()을 통해 HttpSession에 보관하는 처리
LoginInterceptor.java
public class LoginInterceptor extends HandlerInterceptorAdapter {
private static final String LOGIN = "login";
private static final Logger logger = LoggerFactory.getLogger(LoginInterceptor.class);
@Override
public void postHadler (HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
HttpSession session = request.getSession();
ModelMap modelMap = modelAndView.getModelMap();
Object userVO = modelMap.get("userVO");
if(userVO != null) {
// 로그인 성공시 Session에 저장후, 초기 화면 이동
logger.info("new login success");
session.setAttribute(LOGIN, userVO);
response.sendRedirect("/");
}
}
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
HttpSession session = request.getSession();
if(session.getAttribute(LOGIN) != null) {
// 기존 HttpSession에 남아있는 정보가 있는 경우 이를 삭제
logger.info("clear login data before");
session.removeAttribute(LOGIN);
}
return true;
}
}
servlet-context.xml
<beans:bean id="loginInterceptor"
class="org.sample.interceptor.LoginInterceptor"/>
<interceptors>
<interceptor>
<mapping path="/user/login"/>
<beans:ref bean="loginInterceptor"/>
</interceptor>
</interceptors>
2) AuthInterceptor
특정 경로에 사용자가 접근하는 경우 현재 사용자가 로그인한 상태인지를 체크하는 처리
AuthInterceptor.java
public class AuthInterceptor extends HandlerInterceptorAdapter {
private static final Logger logger = LoggerFactory.getLogger(AuthInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
HttpSession session = request.getSession();
if(session.getAttribute("login") != null) {
logger.info("current user is not logined");
// 로그인하지 않은 사용자일 경우 로그인 페이지로 이동
response.sendRedirect("/user/login");
return false;
}
// 로그인한 사용자일 경우 Controller 호출
return true;
}
}
servlet-context.xml
<beans:bean id="loginInterceptor"
class="org.sample.interceptor.LoginInterceptor"/>
<beans:bean id="authInterceptor"
class="org.sample.interceptor.AuthInterceptor"/>
<interceptors>
<interceptor>
<mapping path="/user/login"/>
<beans:ref bean="loginInterceptor"/>
</interceptor>
<interceptor>
<!-- login 인증이 필요한 URI 들 -->
<mapping path="/sboard/register"/>
<mapping path="/sboard/modify"/>
<mapping path="/sboard/remove"/>
<beans:ref bean="authInterceptor"/>
</interceptor>
</interceptors>
3) 자동 페이지 이동
로그인이 요구되어 로그인 페이지로 접근한 사용자가 로그인한 이후에 원래 경로로 이동시켜주는 동작
AuthInterceptor.java
// 로그인 페이지 이동 전, 현재 페이지를 Session에 저장
private void saveDest(HttpServletRequest req) {
String uri = req.getRequestURI();
Stirng query = req.getQueryString();
// 기존 URI에 parameter가 있을 경우, 이를 포함
if(query == null || query.equals("null")) {
query = "";
} else {
query = "?" + query;
}
if(req.getMethod().equals("GET")) {
logger.info("dest: " + (uri + query));
req.getSession().setAttribute("dest", uri + query);
}
}
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
HttpSession session = request.getSession();
if(session.getAttribute("login") == null) {
logger.info("current user is not logined");
saveDest(request);
// 로그인하지 않은 사용자일 경우 로그인 페이지로 이동
response.sendRedirect("/user/login");
return false;
}
// 로그인한 사용자일 경우 Controller 호출
return true;
}
LoginInterceptor.java
@Override
public void postHadler (HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
HttpSession session = request.getSession();
ModelMap modelMap = modelAndView.getModelMap();
Object userVO = modelMap.get("userVO");
if(userVO != null) {
// 로그인 성공시 Session에 저장후, 초기 화면 이동
logger.info("new login success");
session.setAttribute(LOGIN, userVO);
// 이전 destination 불러오기
// response.sendRedirect("/");
Object dest = session.getAttribute("dest");
response.sendRedirect(dest != null ? (String)dest : "/");
}
'웹 개발 > 🍃 SpringBoot' 카테고리의 다른 글
스프링부트 동작방식 (0) | 2024.10.23 |
---|---|
REST API (0) | 2024.10.23 |
Lombok VO 변수명 설정시 유의사항 (0) | 2024.03.08 |
[springboot] 윈도우 환경에서 jar 배포하는법 (0) | 2023.09.10 |
[Spring] @Resource 와 @Autowired 차이 (0) | 2023.06.16 |