인터셉터(Interceptor)
인터셉터는 요청 처리 메소드가 호출되기 전 또는 후에 삽입되어 실행될 명령을 작성하여 제공하는 기능이다.
- 인터셉터를 사용하여 권한 관련 기능을 구현할 수 있다. - 요청 처리 메소드에서 권한 관련 명령..
- 인터셉터 관련 클래스를 작성하여 Srping Bean Configuration Fiel(servlet-context.xml)에 인터셉터가 동작될 수 있도록 설정해주면 된다.
인터셉터 vs 필터
필터는 WAS의 제어를 받으며 FrontController 전에 실행되는 반면, 인터셉터는 FrontController 다음에 실행되며 FrontController 의 영향을 받는다.
인터셉터는 FrontController(스프링 컨테이너)에 의해 관리 될 수 있도록 만들어진다.
Filter는 web.xml에 필터를 등록해주고 url 주소를 매핑해주었지만,
인터셉터는 FrontController가 가져다 쓰는 스프링 컨테이너에 인터셉터를 등록해 원하는 페이지를 요청할 때 인터셉터가 동잘될 수 있도록 만들어 주면 된다.
스프링 컨테이너는 servlet-context.xml에 요청 처리 메소드가 호출되기 전, 후에 인터셉터가 실행될 수 있도록 설정해주면 된다.
인터셉터는 일종의 ADP 기술을 이용하는 것이라고 볼 수 있으며, 일반적으로 권한처리 할 때 많이 사용된다.
예제)
패키지 생성

Intercepter 클래스
- Intercepter 클래스는 요청 처리 메소드가 호출되기 전 또는 후에 삽입되어 실행될 기능을 제공하는 클래스이다.
- Intercepter 클래스는 반드시 HandlerInterceptor 인터페이스를 상속받아 작성해주면 된다. 이 때, 필요한 메소드만 오버라이드 선언 해주면 된다.
- -> HandlerInterceptor 인터페이스 내에 선언된 메소드들은 추상 메소드가 아니라 default 메소드이기 때문에 필요한 것만 오버라이드 할 수 있다.
- Srping Bean Configuration Fiel(servlet-context.xml)에 Srping Bean으로 등록하고 요청 처리 메소드 호출 전 또는 후에 실행되도록 설정해주어야 한다.
관리자 관련 권한 처리를 위한 인터셉터 클래스 작성
요청 처리 메소드가 호출되기 전에 비로그인 사용자이거나 관리자가 아닌 사용자가 페이지를 요청한 경우 인위적으로 예외를 발생시켜 보자. - 에러 페이지로 응답 처리할 것임
preHandle 메소드
- 요청 처리 메소드가 호출되기 전에 실행될 명령을 작성하기 위한 메소드이다.
- false를 반환하면 요청 처리 메소드를 호출하지 않는다는 뜻이고 true를 반환하면 요청 처리 메소드를 호출한다는 뜻이다. (기본값은 true)
AdminAuthInterceptor
public class AdminAuthInterceptor implements HandlerInterceptor {
//요청 처리 메소드가 호출되기 전에 실행될 명령을 작성하기 위한 메소드
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
HttpSession session=request.getSession();
Userinfo loginUserinfo=(Userinfo)session.getAttribute("loginUserinfo");
//비로그인 사용자이거나 관리자가 아닌 사용자인 경우
if(loginUserinfo == null || loginUserinfo.getStatus() != 9) {
//1)
//response.sendError(HttpServletResponse.SC_FORBIDDEN);//403 에러코드 전달
//return false;//요청 처리 메소드 미호출
//2)
//request.getRequestDispatcher("usrinfo/user_error.jsp").forward(request, response);
//return false;//요청 처리 메소드 미호출
//3) ExceptionHandler 사용
throw new BadRequestException("비정상적인 요청입니다.");
}
return true;//요청 처리 메소드 호출
}
}
postHandle 메소드
- 요청 처리 메소드가 호출되어 반환된 뷰 이름으로 ViewResolver가 뷰(View)를 생성하기 전에 실행될 명령을 작성하기 위한 메소드이다.
- ModelAndView 객체를 제공받아 VeiwName 또는 Model 객체의 속성값을 저장(변경)하기 위해 사용한다.
//요청 처리 메소드가 호출되어 뷰(View)가 생성되기 전에 실행될 명령을 작성하기 위한 메소드
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// TODO Auto-generated method stub
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
afterCompletion 메소드
- 요청 처리 메소드가 호출되어 반환된 뷰이름으로 ViewResolver가 뷰(View)를 생성한 후에 실행될 명령을 작성하는 메소드이다.
- 뷰(View)를 변경하기 위해 사용한다.
//요청 처리 메소드가 호출되어 뷰가 생성된 후에 실행될 명령을 작성하는 메소드
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// TODO Auto-generated method stub
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
로그인 사용자 관련 권한 처리를 위한 인터셉터 클래스 작성
요청 처리 메소드가 호출되기 전에 비로그인 사용자가 페이지를 요청한 경우 인위적으로 예외를 발생시킬 것이다. - 에러 페이지로 응답 처리할 것임
public class LoginAuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
HttpSession session=request.getSession();
Userinfo loginUserinfo=(Userinfo)session.getAttribute("loginUserinfo");
//비로그인 사용자인 경우
if(loginUserinfo == null || loginUserinfo.getStatus() != 9) {
throw new BadRequestException("비정상적인 요청입니다.");
}
return true;//요청 처리 메소드 호출
}
}
** 실제 프로젝트에서는 리다이렉트 이동을 시키되 쿼리 스트링, 세션 등을 이용해 return url을 사용해보기..(로그인 페이지로 이동 등)
UserinfoController에서 기존 메소드를 수정해주자
//회원정보를 입력받기 위한 뷰이름을 반환하는 요청 처리 메소드
// => 비로그인 사용자 또는 관리자가 아닌 사용자가 페이지를 요청할 경우 인위적 예외 발생
인터셉터 사용 전
@RequestMapping(value = "/write", method = RequestMethod.GET)
public String write(HttpSession session) throws BadRequestException {
Userinfo loginUserinfo=(Userinfo)session.getAttribute("loginUserinfo");
if(loginUserinfo == null || loginUserinfo.getStatus() != 9) {
//throw new Exception("비정상적인 요청입니다.");
throw new BadRequestException("비정상적인 요청입니다.");
}
return "userinfo/user_write";
}
인터셉터 사용 후
@RequestMapping(value = "/write", method = RequestMethod.GET)
public String write(HttpSession session) throws BadRequestException {
return "userinfo/user_write";
}
//USEINFO 테이블에 저장된 모든 회원정보를 검색하여 속성값으로 저장하여 회원목록을 출력하는
//뷰이름을 반환하는 요청 처리 메소드
// => 비로그인 사용자가 페이지를 요청할 경우 인위적 예외 발생
인터셉터 사용 전
@RequestMapping("/list")
public String list(Model model, HttpSession session) throws BadRequestException {
Userinfo loginUserinfo=(Userinfo)session.getAttribute("loginUserinfo");
if(loginUserinfo == null) {
throw new BadRequestException("비정상적인 요청입니다.");
}
model.addAttribute("userinfoList", userinfoService.getUserinfoList());
return "userinfo/user_list";
}
인터셉터 사용 후
=> 인터셉터를 사용하여 권한 관련 처리 기능 구현 - 요청 처리 메소드에서 권한 관련 명령 미작성
@RequestMapping("/list")
public String list(Model model, HttpSession session) throws BadRequestException {
model.addAttribute("userinfoList", userinfoService.getUserinfoList());
return "userinfo/user_list";
}
//아이디를 전달받아 USEINFO 테이블에 저장된 회원정보를 검색하여 속성값으로 저장하여
//회원정보를 출력하는 뷰이름을 반환하는 요청 처리 메소드
// => 비로그인 사용자가 페이지를 요청할 경우 인위적 예외 발생
인터셉터 사용 전
@RequestMapping("/view")
public String view(@RequestParam String userid, Model model, HttpSession session) throws BadRequestException, UserinfoNotFoundException {
Userinfo loginUserinfo=(Userinfo)session.getAttribute("loginUserinfo");
if(loginUserinfo == null) {
throw new BadRequestException("비정상적인 요청입니다.");
}
model.addAttribute("userinfo", userinfoService.getUserinfo(userid));
return "userinfo/user_view";
}
인터셉터 사용 후
@RequestMapping("/view")
public String view(@RequestParam String userid, Model model) throws UserinfoNotFoundException {
model.addAttribute("userinfo", userinfoService.getUserinfo(userid));
return "userinfo/user_view";
}
//아이디를 전달받아 USEINFO 테이블에 저장된 회원정보를 검색하여 속성값으로 저장하여
//회원정보를 변경하는 뷰이름을 반환하는 요청 처리 메소드
// => 비로그인 사용자 또는 관리자가 아닌 사용자가 페이지를 요청할 경우 인위적 예외 발생
인터셉터 사용 전
@RequestMapping(value = "/modify", method = RequestMethod.GET)
public String modify(@RequestParam String userid, Model model, HttpSession session) throws BadRequestException, UserinfoNotFoundException {
Userinfo loginUserinfo=(Userinfo)session.getAttribute("loginUserinfo");
if(loginUserinfo == null || loginUserinfo.getStatus() != 9) {
throw new BadRequestException("비정상적인 요청입니다.");
}
model.addAttribute("userinfo", userinfoService.getUserinfo(userid));
return "userinfo/user_modify";
}
인터셉터 사용 후
@RequestMapping(value = "/modify", method = RequestMethod.GET)
public String modify(@RequestParam String userid, Model model) throws UserinfoNotFoundException {
model.addAttribute("userinfo", userinfoService.getUserinfo(userid));
return "userinfo/user_modify";
}
//아이디를 전달받아 USEINFO 테이블에 저장된 회원정보를 삭제하고 회원목록 출력페이지를
//요청할 수 있는 URL 주소를 클라이언트에게 전달하여 응답 처리하는 요청 처리 메소드
// => 비로그인 사용자 또는 관리자가 아닌 사용자가 페이지를 요청할 경우 인위적 예외 발생
인터셉터 사용 전
@RequestMapping("/remove")
public String remove(@RequestParam String userid, HttpSession session) throws BadRequestException, UserinfoNotFoundException {
Userinfo loginUserinfo=(Userinfo)session.getAttribute("loginUserinfo");
if(loginUserinfo == null || loginUserinfo.getStatus() != 9) {
throw new BadRequestException("비정상적인 요청입니다.");
}
userinfoService.removeUserinfo(userid);
if(loginUserinfo.getUserid().equals(userid)) {
return "redirect:/userinfo/logout";
}
return "redirect:/userinfo/list";
}
인터셉터 사용 후
@RequestMapping("/remove")
public String remove(@RequestParam String userid, HttpSession session) throws UserinfoNotFoundException {
Userinfo loginUserinfo=(Userinfo)session.getAttribute("loginUserinfo");
userinfoService.removeUserinfo(userid);
if(loginUserinfo.getUserid().equals(userid)) {
return "redirect:/userinfo/logout";
}
return "redirect:/userinfo/list";
}
중복된 코드를 없앨 수 있다는 장점이 있다.
작성한 두개의 인터셉터 클래스가 동작할 수 있도록 만들어 보자
sevlet-context.xml
Intercepteor 클래스를 스프링 빈으로 등록
<beans:bean class="xyz.itwill10.util.AdminAuthInterceptor" id="adminAuthInterceptor"></beans:bean>
<beans:bean class="xyz.itwill10.util.LoginAuthInterceptor" id="loginAuthInterceptor"></beans:bean>
interceptors : interceptor 엘리먼트로 등록하기 위한 엘리먼트
- interceptor : 인터셉터 기능을 제공받기 위한 규칙을 설정하는 엘리먼트
- mapping : 인터셉터가 실행될 요청 처리 메소드의 페이지 요청 URL 주소를 설정하는 엘리먼트
- path 속성에 요청 처리 메소드가 호출될 요청 URL 주소를 속성값으로 설정한다.
- ref : 인터셉터 기능을 제공할 객체(Spring Bean)을 설정하기 위한 엘리먼트
- bean 속성에 Interceptor 클래스의 Spring Bean 식별자(beanName)를 속성값으로 설정한다.
<!-- interceptors : interceptor 엘리먼트로 등록하기 위한 엘리먼트 -->
<interceptors>
<interceptor>
<!-- 인터셉터가 실행될 요청 처리 메소드의 페이지 요청 URL 주소를 설정 -->
<mapping path="/userinfo/write"/>
<mapping path="/userinfo/modify"/>
<mapping path="/userinfo/remove"/>
<!-- Interceptor 클래스의 Spring Bean 식별자(beanName)를 속성값으로 설정 -->
<beans:ref bean="adminAuthInterceptor"/>
</interceptor>
<interceptor>
<mapping path="/userinfo/list"/>
<mapping path="/userinfo/view"/>
<beans:ref bean="loginAuthInterceptor"/>
</interceptor>
</interceptors>
mapping 엘리먼트의 path 속성값으로 [*] 패턴문자를 사용하여 요청 URL 주소를 설정하는 것도 가능하다.
- [/*] : 폴더의 모든 페이지를 요청한 경우
- [/**] : 최상위 폴더 및 하위 폴더의 모든 페이지를 요청한 경우
<!-- 폴더의 모든 페이지를 요청한 경우-->
<mapping path="/*"/>
<!-- 최상위 폴더 및 하위 폴더의 모든 페이지를 요청한 경우 -->
<mapping path="/**"/>
만약 권한이 없는 사용자가 list를 요청했을 경우 user_error.jsp 로 이동한다

페이지가 많을 경우 [*]을 사용하는 것을 권장한다.
exclude-mapping : 인터셉터가 실행되지 않는 페이지의 요청 URL 주소를 설정하는 엘리먼트
<interceptor>
<mapping path="/userinfo/*"/>
<!-- 인터셉터가 실행되지 않는 페이지의 요청 URL 주소를 설정 -->
<exclude-mapping path="/userinfo/login"/>
<beans:ref bean="loginAuthInterceptor"/>
</interceptor>
'학원 > 복기' 카테고리의 다른 글
[Spring] 자료실 만들기 (0) | 2023.08.15 |
---|---|
[Srping] commons fileupload 라이브러리 이용한 파일 처리 (0) | 2023.08.15 |
[Spring] 예외 클래스 / ExceptionHandler / jbcrypt 라이브러리 (0) | 2023.08.11 |
[Spring] TilesView 클래스 (0) | 2023.08.11 |
[Spring] TranscationManager (0) | 2023.08.10 |