Everything has an expiration date
[inflearn] 20240120 [스프링-프레임워크] - 21강 필기 본문
[inflearn] 20240120 [스프링-프레임워크] - 21강 필기
Jelly-fish 2024. 1. 20. 22:4921강 - 리다이렉트, 인터셉트
컨트롤러에서 뷰를 분기하는 방법과 컨트롤러 실행 전 / 후에 특정 작업을 가능하게 하는 방법에 대해서 학습한다.
21-1 리다이렉트(redirect)
21-2 인터셉터 (interceptor)
21-1 리다이렉트(redirect)
- 리다이렉트(redirect) : 지금의 페이지에서 특정 페이지로 전환하는 기능.
① 회원 정보 수정 요청
modifyForm()
② 회원 인증 ( YES / NO )
▶ ⓐ 회원 인증 성공 (YES) : 회원정보 수정 페이지로 유도
return "member/modifyForm";
▶ ⓑ 회원 인증 실패 (NO) : 메인 페이지로 유도
return "redirect:/";
수정 페이지에 진입하기 위한 조건 (회원 인증) 을 만족하지 못하여
다시 메인 페이지로 페이지를 전환시킨다. → 이것이 곧, 리다이렉트(redirect)
① [`redierct`를 통한 분기 처리가 없을 경우]
MemberController.java
@RequestMapping(value = "/modifyform")
public String modifyForm(Model model, HttpServletRequest request)
{
HttpSession session = request.getSession();
// 세션(Session)에 저장된 회원의 객체를 가져온다.
Member member = (Member) session.getAttribute("member");
// 세션에 저장되어 있는 회원 객체(member)를
// Model 객체에 저장한다.
model.addAttribute("member", service.memberSearch(member));
return "/member/modifyForm";
}
[코드 해설]
로그인이 되어있지 않은 상태에서, 강제적인 방법으로 URL 창에 하드코딩을 하여 직접 `/modifyform` 을 요청해
이 페이지 경로로 진입을 했을 경우...
`member` 에 대한 세션을 얻어오려고 했을 때, 로그인을 하지 않았으므로 `member`에 대한 세션은 존재하지 않을 것이다.
따라서, member 에 대한 회원 정보를 얻어올 수 없으므로 `modifyForm` 페이지에 접근해도 `null` 값이 넘어가게 될 것이다.
이런 상황에서 로그인이 되어 있는지, 없는지에 따라 `redirect` 를 수정해서 분기 처리를 할 수 있다.
ⓐ 【 Model 객체를 사용했을 때 】
②-1 [`redirect` 를 통한 분기 처리 적용]
MemberController.java - `modifyForm()`
@RequestMapping(value = "/modifyform")
public String modifyForm(Model model, HttpServletRequest request)
{
HttpSession session = request.getSession();
// 세션(Session)에 저장된 회원의 객체를 가져온다.
Member member = (Member) session.getAttribute("member");
if (member == null) //-- 로그인을 하지 않았을 경우
{
// 로그인이 되어있지 않다면,
// 메인 페이지로 이동한다.
return "redirect:/";
}
else //-- 로그인을 했을 경우
{
// 로그인을 한 상태이므로, member 에 대한 세션이 제대로 넘어온다.
// 이 회원 정보(member)를 model 객체에 추가해 준 후
// 수정 폼 페이지로 이동한다.
model.addAttribute("member", service.memberSearch(member));
}
return "/member/modifyForm";
}
ⓑ 【 ModelAndView 객체를 사용했을 때 】
②-2 [`redirect` 를 통한 분기 처리 적용]
MemberController.java - `removeForm()`
@RequestMapping("/removeForm")
public ModelAndView removeForm(HttpServletRequest request)
{
ModelAndView mav = new ModelAndView();
HttpSession session = request.getSession();
Member member = (Member) session.getAttribute("member");
if (null == member) //-- 로그인을 하지 않았을 경우
{
// 메인 페이지로 이동
mav.setViewName("redirect:/"); //-- check~!!!
}
else //-- 로그인을 했을 경우
{
// 세션에 저장된 member 정보를 ModelAndView 객체에 저장.
mav.addObject("member", member);
// 회원 삭제 페이지로 이동.
mav.setViewName("/member/removeForm");
}
return mav;
}
[실행 결과]
※ 로그인을 하지 않고 강제로 `modifyForm` URL 로 접근했을시, 메인 페이지로 다시 이동하는 것을 확인.
21-2 인터셉터 (interceptor)
리다이렉트를 사용해야 하는 경우가 많은 경우 `HandlerInterceptor` 를 이용할 수 있다.
로그인이 된 상태여야만 이루어질 수 있는 서비스가 굉장히 많을 경우,
해당 Url을 요청할 때마다 `redirect` 분기를 처리한다면 굉장히 번거로울 것이다.
이를 해결하기 위해 나온 방법이 `intercept` 이다.
interceptor
- 컨트롤러가 시작되기 전이나, 컨트롤러가 작업을 다 끝낸 후에 그 요청을 가로채서 검증을 하는 것이다.
★ preHandle() | 컨트롤러가 작동하기 전 단계에 요청을 가로채서 작업한다. |
postHandle() | 컨트롤러가 작업한 후에 컨트롤러 업무 처리 결과를 가로채서 작업한다. |
afterCompletion() | 컨트롤러와 뷰가 모두 처리된 후에 작업을 한다. |
▶ `preHandle()` → `redirect` 대체 가능!
HandlerInterceptor 와 HandlerAdapter
`HandlerInterceptor`는 인터페이스이다. 이 안에 정의된 추상 메소드를 모두 재정의(`@Override`) 하기에는 불편함이 있으므로...
Spring 에서는 `HandlerInterceptor` 인터페이스를 구현한 클래스인 `HandlerInterceptorAdapter` 를 지원한다.
① HandlerInterceptorAdapter 를 구현한 클래스 생성
MemberLoginInterceptor.java - `preHandle()` 메소드 부분
public class MemberLoginInterceptor extends HandlerInterceptorAdapter
{ ★ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
// 컨트롤러가 작업하기 전에,
// 클라이언트의 요청(request)을 가져와서 작업한다.
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception
{
// 요청에 저장된 세션(Session)을 받아온다.
HttpSession session = request.getSession(false);
// 받아온 세션이 null 이 아닐 경우
// 로그인을 통해, 세션 안에 회원 정보를 담은 member 가
// 저장되어 있음을 의미한다.
if (session != null)
{
// 세션에 저장된 회원 정보를 받아와서 Object에 저장한다.
Object obj = session.getAttribute("member");
if (obj != null)
{
// obj가 null 이 아니면 세션에 저장된 member 객체가
// 제대로 전달됐음을 알 수 있으므로
// 컨트롤러가 작업할 수 있도록 한다.
return true;
}
}
// 세션을 통해 member 객체를 받아오지 못했을 경우
// 메인 페이지로 돌려 보낸다.
response.sendRedirect(request.getContextPath() + "/");
return false;
}
}
위와 같이, `HandlerInterceptorAdapter` 클래스를 상속한 클래스에서
컨트롤러가 작동하기 전에 사용자의 요청(request)을 가로채서 작업을 수행하는
`preHandle()` 메소드를 `@Override` 하여 세션에 저장되어 있는 `member` 객체를 확인한다면...
로그인이 필요한 페이지를 요청할 때마다 세션을 확인하여 `member` 객체의 존재 유무를 확인하므로
★ 모든 컨트롤러에서 `request` 분기 처리를 할 필요가 없어진다!
Interceptor 스프링 컨테이너 등록
이렇게 구성된 클래스는, 스프링 설정 파일(`dispatcher-servlet.xml`)에 등록을 해 주어야만
클라이언트가 해당 url 을 요청했을 때 `interceptor`를 동작시킬 수 있다.
ⓐ Interceptor 가 동작해야 할 접근 url 하나하나를 다 `mapping path`로 등록해 주는 방식.
servlet-context.xml
<interceptors>
<interceptor>
<!-- mapping path에 해당하는 url을 요청했을 때 -->
<!-- interceptor 동작하도록 구성. -->
<mapping path="/member/modifyForm"/>
<mapping path="/member/removeForm"/>
<!-- mapping path를 클라이언트가 요청했을 때 동작할 -->
<!-- HandlerInterceptorAdapter 를 상속한 클래스의 경로로 빈(bean)객체 생성 -->
<beans:bean class="com.bs.lec21.member.MemberLoginInterceptor"/>
</interceptor>
</interceptors>
ⓑ 특정 상위 경로 (`member`)에 해당하는 url을 요청할 경우 모두 Interceptor 가 동작하되,
`exclude-mapping path`에 해당하는 url 을 요청할 때는 Interceptor 가 동작하지 않도록 하는 방식.
servlet-context.xml
<interceptors>
<interceptor>
<!-- 클라이언트가 /member가 포함되는 모든 url을 요청할 경우 -->
<!-- Interceptor 가 동작한다. -->
<mapping path="/member/**"/>
<!-- ★ 단, exclude-mapping path에 해당하는 url을 요청했을 시에는 -->
<!-- Interceptor 가 동작하지 않도록 한다! -->
<exclude-mapping path="/member/joinForm"/>
<exclude-mapping path="/member/join"/>
<exclude-mapping path="/member/loginForm"/>
</interceptor>
</interceptors>
'[Inflearn] > 자바 스프링 프레임워크(renew ver.)' 카테고리의 다른 글
[inflearn] 20240121 [스프링-프레임워크] - 24강 필기 (0) | 2024.01.21 |
---|---|
[inflearn] 20240120 [스프링-프레임워크] - 23강 필기 (0) | 2024.01.21 |
[inflearn] 20240114 [스프링-프레임워크] - 20강 필기 (1) | 2024.01.14 |
[inflearn] 20240114 [스프링-프레임워크] - 19강 필기 (1) | 2024.01.14 |
[inflearn] 20240113 [스프링-프레임워크] - 18강 필기 (2) | 2024.01.14 |