Notice
Recent Posts
Recent Comments
Link
«   2025/07   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Archives
Today
Total
관리 메뉴

Everything has an expiration date

[inflearn] 20240120 [스프링-프레임워크] - 21강 필기 본문

[Inflearn]/자바 스프링 프레임워크(renew ver.)

[inflearn] 20240120 [스프링-프레임워크] - 21강 필기

Jelly-fish 2024. 1. 20. 22:49

21강 - 리다이렉트, 인터셉트

컨트롤러에서 뷰를 분기하는 방법과 컨트롤러 실행 전 / 후에 특정 작업을 가능하게 하는 방법에 대해서 학습한다.

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;
}

[실행 결과]

출처 : Inflearn [스프링 프레임워크] - 21강

 

로그인을 하지 않고 강제로 `modifyForm` URL 로 접근했을시, 메인 페이지로 다시 이동하는 것을 확인.


21-2 인터셉터 (interceptor)

리다이렉트를 사용해야 하는 경우가 많은 경우 `HandlerInterceptor` 를 이용할 수 있다.

출처 : Inflearn [스프링 프레임워크] - 21강

 

로그인이 된 상태여야만 이루어질 수 있는 서비스가 굉장히 많을 경우,

해당 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>