seong

(13)블로그 만들기 웹에서 Interceptor 구현 (WebMvcConfigurer 사용) 본문

Spring/블로그 만들기

(13)블로그 만들기 웹에서 Interceptor 구현 (WebMvcConfigurer 사용)

hyeonseong 2022. 9. 20. 22:14

Interceptor

컨트롤러로 들어오는 HttpRequest, HttpResponse를 가로채는 역할을 한다.

예를 들어 컨트롤러에 글을 삭제 하는 로직이 있다. 

글은 "해당글의 작성자"만이 삭제를 할 수 있다, 여기서 Interceptor 를 이용해 삭제를 하기 전 작성자가 아니라면 컨트롤러가 동작 하지 않게 한다. 

필터와 인터셉터는 비슷한 역할을 하지만 다르다!

Interceptor 호출 시점은 3가지가 있다.

1. preHandle : 컨트롤러가 호출 되기 전 

2. postHandle: 컨트롤러가 실행 된 후

3. afterComplete : 컨트롤러 -> View 모든 동작이 끝난 후

구현해보기

필요한 환경 설정 셋팅

보통 Interceptor 구현 하기 위해서 2가지가 필요하다. 

1. Interceptor 핸들러

2. 웹에서 Interceptor 경로를 설정해줄 WebMvcConfigurer이 필요하다.

주소에 특정 패턴 부여

핸들러 작성 전 인증이 필요한 컨트롤러 주소에 특정 패턴을 준다. 

패턴을 주는 이유는 인터셉터를 할 부분을 더 효율적으로 다루기 위해서 이다 .

View의 경로만 리턴 해줄 경우 아래 처럼 /s를 추가 

view 경로 확인

추가적으로 데이터를 리턴 해줄 때는 /api도 붙여 주었다.

/s : 인증이 필요한 컨트롤러

/api : 데이터를 리턴해주는 컨트롤러 

위의 코드에선 return에 데이터를 리턴하고, 인증이 필요하기 때문에 주소 앞에 /s/api를 넣어주었다.

/s/api는 작성자 본인이 필요에 따라 아무렇게 정해도 된다.

@ResponseBody가 적혀있다면 모두 /api가 적힌다.

 Interceptor 핸들러 작성

현재 Ajax를 통해 통신을 하고 있다.

Ajax는 CMRespDto라는 데이터를 전달하고있다. 

단지 주소(View의 주소)를 전달 하면 응답에 Redirect 해서 주면 되지만 JSON 데이터 타입은 인터셉터가 전달을 할 수 없기 때문에

직접 로직을 작성해 줄 필요가 있다.

package site.metacoding.red.handler;

import java.io.PrintWriter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.web.servlet.HandlerInterceptor;

import com.fasterxml.jackson.databind.ObjectMapper;

import site.metacoding.red.domain.users.Users;
import site.metacoding.red.web.dto.response.CMRespDto;

public class LoginIntercepter implements HandlerInterceptor{
	
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
//		System.out.println("================");
//		System.out.println(request.getRequestURI());
//		System.out.println("================");
		
		String uri = request.getRequestURI();
		
		HttpSession session = request.getSession();
		Users principal = (Users) session.getAttribute("principal");
		if(principal == null) {
			if(uri.contains("api")) {
//				System.out.println("===========");
//				System.out.println("API 가 주소에 있음");			
				
                //response.setHeader("Content-Type", "application/json; charset=utf-8");
				response.setContentType("application/json; charset=utf-8");
				PrintWriter out = response.getWriter();
				CMRespDto<?> cmRespDto = new CMRespDto<>(-1, "인증이 필요합니다", null);
				ObjectMapper om = new ObjectMapper();
				String json = om.writeValueAsString(cmRespDto);
				out.println(json);
			}else {
				System.out.println("===========");
				System.out.println("API 가 주소에 없음");
				response.sendRedirect("/loginForm");
			}
			return false;
		}
		return true;
	}
}

 

위 코드 동작

 

데이터의 타입은 JSON으로 했기 때문에 꼭 JSON으로 변환해서 전달 해 주어야 한다!

WebMvcConfigurer 작성 ( 경로를 담당 )

package site.metacoding.red.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import site.metacoding.red.handler.LoginIntercepter;
/*.excludePathPatterns("/s/boards/**") => /s/boards로 시작하는 모든것을 제외*/
import site.metacoding.red.handler.TestIntercepter;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
	
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		registry.addInterceptor(new LoginIntercepter())
		.addPathPatterns("/s/**");

	}
}

registry.addInterceptor는 만들 Interceptor객체를 연결 한다는 뜻이다.

.addPathPatterns("/s/boards/**");  => /s/boards로 시작하는 모든 경로를 포함.
.excludePathPatterns("/s/boards/**");  => /s/boards로 시작하는 모든 경로를 제외함.
 /s* => s뒤의 주소 한개 까지만 읽기 가능 /s/boards는 가능 /s/boards/1 은 불가능

 

Ajax,Form태그,Controller 등 경로가 있는 곳은 모두 체크해 바꿔준다!

아래 처럼 찾아서 모두 수정

Form
Ajax
controller

결과 확인 해보기 

1. 좋아요는 데이터를 응답 받는 코드이다.

그러므로 Intercetptor에서 응답 데이터를 만들어서 전달 해주고 확인

정상적으로 출력된다.

2. 글쓰기 폼 확인

로그인 하지 않고 writeForm으로 이동

 

세션값이 null이고, 주소값에 api가 있지 않기 때문에 /loginForm을 썻다. 제대로 전달이 되었다