[21.10.22] Interceptor 활용

yed·2021년 10월 22일
0

Interceptor 설정하기

HandlerInterceptorAdapter를 상속받는 클래스 생성

1. preHandle(request, response, handler)

  • override해서 메소드 작성
  • 요청(request)에 해당하는 컨트롤러 메소드가 동작하기 전에 요청을 가로채서 해야할 기능을 작성
  • 세션은 대부분 이전에 기능 작성함
  • handler는 들어가있는 객체
  • 서버가 요청 처리하기 이전
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
		throws Exception {
	logger.info("===== preHandle 호출");
	return super.preHandle(request, response, handler);
}

preHandle()의 return값 의미

  • true : 원래 실행하려고했던 컨트롤러 메소드를 실행한다
  • false : 컨트롤러 메소드를 실행하지 않는다

2. postHandle(request, response, handler, ModelAndView)

  • 컨트롤러 메소드가 수행된 이후에 DispatcherServlet이 view(JSP)를 처리하기 전 해야할 기능을 작성
  • view로 돌려줘야할 데이터를 ModelAndView에 저장
  • 클라이언트가 응답 받기 이전
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
		ModelAndView modelAndView) throws Exception {
	logger.info("===== postHandle 호출");
	super.postHandle(request, response, handler, modelAndView);
}

ModelAndView 객체

  • intercept된 경로에 있는 model과 view 정보를 가져온다

3. aftetCompletion(request, response, handler, ex)

  • DispatcherServlet에 의해 화면처리(view)가 끝난 후 해야할 기능들을 작성
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
		throws Exception {
	logger.info("===== afterCompletion 호출");
	super.afterCompletion(request, response, handler, ex);
}

servlet-context.xml에 bean과 url 매핑 설정

  • Interceptor 클래스의 인스턴스를 bean으로 관리
<beans:bean id="sample1" class="edu.spring.ex04.interceptor.SampleInterceptor1">
</beans:bean>
  • Interceptor가 가로챌 URL 매핑 설정
<interceptors>
	<interceptor>
		<mapping path="/" />
		<beans:ref bean="sample1" />
	</interceptor>
</interceptors>

ref의 bean을 설정한 bean의 path경로로 가서 가로챈다

데이터 송수신과정에서도 interceptor가 데이터를 가로챌 수 있다.

interceptor 사용 예제

@GetMapping("/test1")
public String test1() {
	logger.info("test1() 호출");
	return "test";
}
	
@GetMapping("/test2")
public String test2(Model model) {
	logger.info("test2() 호출");
	model.addAttribute("data", "test2");
	return "test";
}
  • 데이터가 없는 url과 있는 url이 존재할때 preHandle()과 postHandle()로 interceptor해보자
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
		throws Exception {
	logger.info("===== preHandle 호출");
	HandlerMethod handlerMethod=(HandlerMethod) handler;
	Method method=handlerMethod.getMethod();
		
	//url 경로에 있는 bean 객체
	logger.info("Bean : "+handlerMethod.getBean());
	//url 경로에 있는 메소드 이름
	logger.info("method : "+method.getName());
		
	return true;
}
  • 서버가 클라이언트의 신호를 받기전에 실행되는 메소드. 매핑한 url이 호출되면 서버보다 먼저 실행됨
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
		ModelAndView modelAndView) throws Exception {
	logger.info("===== postHandle 호출");
	String data=(String)modelAndView.getModel().get("data");
	logger.info("data : "+data);
		
	if(data==null) {
		HttpSession session=request.getSession();
		session.setAttribute("data", "DUMMY DATA");
	}
		
	super.postHandle(request, response, handler, modelAndView);
}
  • 서버가 데이터를 view로 보낼때 실행되는 메소드. 서버에서 데이터가 넘어오고 view에 도착하기 전에 interceptor해서 데이터에 간섭할 수 있음.

  • 만약 model에 데이터가 없으면 세션을 생성해서 데이터를 바꾸고 데이터가 있으면 기존 데이터 그대로 보내기

그림으로 그리자면 이런식으로 interceptor가 일어나는 것이다


Interceptor - 로그인 세션 체크

로그인 세션 생성 및 체크가 필요한 순간마다 interceptor를 사용하면 공통된 작업을 한번에 처리할 수 있음. 단점은 코드의 흐름파악이 어려울 수 있다

interceptor에서 로그인 세션을 체크하는데
세션이 있으면 컨트롤러 메소드 실행 후 진행(interceptor 활동 없음)
로그인 세션이 없으면 로그인 페이지로 이동시키고 이동하려던 url을 저장

로그인이 되어있는지 아닌지 확인하는건 controller가 실행되기 전에만 체크하면되기 때문에 preHandle()만 사용한다.

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
		throws Exception {
	logger.info("===== preHandle 호출");
	HttpSession session=request.getSession();
	String userid=(String)session.getAttribute("userid");
		
	if(userid!=null) {
		logger.info("로그인 상태 -> controller method 실행");
		return true;
	} else {
		logger.info("로그아웃 상태 -> controller method 실행 안됨");
			
		//전체 요청 주소에서 쿼리 스트링을 제외한 부분
		String uri=request.getRequestURI();
		logger.info("요청 uri : "+uri);
		String contextRoot=request.getContextPath();
		logger.info("contextRoot : "+contextRoot);
		uri=uri.replace(contextRoot, "");
		
		//전체 요청 주소에서 쿼리 스트링만 추출
		String queryString=request.getQueryString();
		logger.info("쿼리 스트링 : "+queryString);
		
		String targetURL="";
		if(queryString==null) {
			targetURL=uri;
		}else {
			targetURL=uri+"?"+queryString;
		}
		request.getSession().setAttribute("targetURL", targetURL);
		
        	response.sendRedirect("/ex04/member/login");
		return false;			
	}
}

request가 없는 controller에서 request가 필요한 일을 하고자하면 그냥 매개변수로 request를 받아오면 됨

	@PostMapping("/login")
	public String loginPost(String userid, String password, HttpServletRequest request) throws Exception{
		logger.info("loginPost() 호출");
		if(userid.equals("test") && password.equals("1234")) {
			logger.info("로그인 성공");
			HttpSession session=request.getSession();
			session.setAttribute("userid", userid);
			
			//세션에서 targetURL 가져오기
			String targetURL=(String)session.getAttribute("targetURL");
			logger.info("목표 url : "+targetURL);
			if(targetURL!=null) {
				session.removeAttribute("targetURL");
				return "redirect:"+targetURL;
			}else {
				return "redirect:/board/list";				
			}
			
		}else {
			logger.info("로그인 실패");
			return "redirect:/member/login";
		}
	}

imgScalr - 이미지 썸네일

pom.xml 라이브러리 추가

  • imgScalr - 이미지 썸네일을 위한 라이브러리
<dependency>
	<groupId>org.imgscalr</groupId>
	<artifactId>imgscalr-lib</artifactId>
	<version>4.2</version>
</dependency>
  • Multipart File upload 라이브러리
<dependency>
	<groupId>commons-fileupload</groupId>
	<artifactId>commons-fileupload</artifactId>
	<version>1.3.3</version>
</dependency>

servlet-context.xml 경로 추가

  • 문자열 리소스를 bean으로 추가
<beans:bean id="uploadPath" class="java.lang.String">
	<beans:constructor-arg value="C:\\Study\\FileUploadTest">
	</beans:constructor-arg>
</beans:bean>

java에서 그냥 String uploadPath=new String("경로"); 로 가능하긴함.
다만 인스턴스를 계속 만들기도하고 목적에 따라 구분짓기위해서 bean으로 추가함

  • 파일업로드 최대 용량 설정 : 1024 x 1024 x 10B = 10MB
<beans:bean id="multipartResolver" 
	class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
	<beans:property name="maxUploadSize" value="10485760"></beans:property>
</beans:bean>

단일 파일 업로드

<view.jsp>

  • enctype : 데이터 인코딩 방식 명시
<form action="upload" method="post" enctype="multipart/form-data">
	<input type="file" name="file"><br>
	<input type="submit" value="업로드">
</form>

<controller.java>

  • servlet-context.xml 파일에 설정된 문자열 리소스를 주입
@Resource(name ="uploadPath")
private String uploadPath;
  • form에서 파일을 업로드받음
@PostMapping("/upload")
public void uploadPost(MultipartFile file, Model model) {
	logger.info("uploadPost() 호출");
	logger.info("파일 이름 : "+file.getOriginalFilename());
	logger.info("파일 크기 : "+file.getSize());
		
	String savedFile=saveUploadFile(file);
	logger.info("저장된 파일 이름 : "+savedFile);		
}
  • UUID : 업로드하는 파일 이름이 중복되지 않게해줌
private String saveUploadFile(MultipartFile file) {	
	UUID uuid=UUID.randomUUID();
	String savedName=uuid+"_"+file.getOriginalFilename();
	File target=new File(uploadPath, savedName);
		
	try {
		FileCopyUtils.copy(file.getBytes(), target);
		logger.info("파일 저장 성공");
		return savedName;
	} catch (IOException e) {
		logger.error("파일 저장 실패");
		return null;			
	}
}

다중 파일 업로드

<view.jsp>

<form action="upload2" method="post" enctype="multipart/form-data">
	<input type="file" name="files" multiple><br>
	<input type="submit" value="업로드">
</form>

<Controller.java>

@PostMapping("/upload2")
public String uploadPost2(MultipartFile[] files, Model model) {
	String result="";
	for (MultipartFile f : files) {
		result += saveUploadFile(f)+" ";
	}
	logger.info("result = "+result);
	return "upload";
}
profile
6개월 국비과정 기록하기

0개의 댓글