Filter

Minseo Kang·2023년 2월 21일
0

Spring Boot

목록 보기
20/27
post-thumbnail

01. Filter 개념


개념

  • Web Application에서 관리되는 영역
  • Spring Boot Framework에서 Client로부터 오는 요청/응답에 대해 최초/최종 단계의 위치에 존재
  • 이를 통해 요청/응답의 정보를 변경할 수 있음
  • Spring에 의해 데이터가 변환되기 전의 순수한 Client의 요쳥/응답 값 확인 가능

특징

  • 유일하게 ServletRequest, ServletResponse 객체를 변환할 수 있음

사용

  • request/response의 Logging
  • 인증과 관련된 Logic 처리
  • 이를 선/후 처리하여 Service business logic과 분리




02. 프로젝트 구조



Lombok 사용을 위해 build.gradle의 dependencies에 다음 코드 추가

compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'



03. User 클래스 작성


  • lombok 사용
package com.example.filter.dto;

import lombok.*;

@Data // Getter, Setter 등
@NoArgsConstructor // 기본 생성자
@AllArgsConstructor // 전체 생성자
public class User {
    private String name;
    private int age;
}



03. ApiController 클래스 작성


  • @Slf4j : log 찍기 위함
package com.example.filter.controller;

import com.example.filter.dto.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
@RequestMapping("/api/user")
public class ApiController {

    @PostMapping("")
    public User user(@RequestBody User user) {
        log.info("User : {}", user);
        return user;
    }

}



04. ApiUserController 클래스 작성


  • @Slf4j : log 찍기 위함
package com.example.filter.controller;

import com.example.filter.dto.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
@RequestMapping("api/temp")
public class ApiUserController {

    @PostMapping("")
    public User user(@RequestBody User user) {
        log.info("Temp : {}", user);
        return user;
    }

}



05. GlobalFilter 클래스 작성


  • Filter 클래스를 implements 받아 doFilter 메소드 overriding
  • @Slf4j : log 찍기 위함
  • @WebFilter : 특정 url에 Filter 걸기
  • 전처리에서의 HttpServletRequest/HttpServletResponse 형변환 : Filter 단에서 response/request 변형 가능
  • chain.doFilter(req, res) : 기준으로 전처리/후처리 이루어짐
  • ContentCachingRequestWrapper 클래스의 copyBodyToResponse 메소드 : Client가 제대로 된 응답을 받을 수 있도록 꺼낸 내용을 Body에 Copy
package com.example.filter.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Slf4j
@WebFilter(urlPatterns = "/api/user/*") // 특정 url에 Filter 걸기
public class GlobalFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        // 전처리 구간
        // 형 변환
        ContentCachingRequestWrapper httpServletRequest = new ContentCachingRequestWrapper((HttpServletRequest)request);
        ContentCachingResponseWrapper httpServletResponse = new ContentCachingResponseWrapper((HttpServletResponse)response);

        // 실행
        chain.doFilter(httpServletRequest, httpServletResponse);

        // 어떤 주소로 가져왔는지
        String url = httpServletRequest.getRequestURI();

        // 후처리 구간
        // 응답 받기
        String reqContent = new String(httpServletRequest.getContentAsByteArray());
        String resContent = new String(httpServletResponse.getContentAsByteArray());
        int httpStatus = httpServletResponse.getStatus();

        // 위에서 내용을 빼가기 때문에 이 메소드 호출하여 Client가 제대로 된 응답을 받을 수 있도록 함
        httpServletResponse.copyBodyToResponse();

        log.info("request url : {}, requestBody : {}", url, reqContent);
        log.info("response status : {}, responseBody : {}", httpStatus, resContent);
    }

}



06. FilterApplication 클래스(Main) 작성


  • @ServletComponentScan : 특정 url에 Filter 걸기
package com.example.filter;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

@SpringBootApplication
@ServletComponentScan 특정 url에 Filter 걸기
public class FilterApplication {

	public static void main(String[] args) {
		SpringApplication.run(FilterApplication.class, args);
	}

}



07. 실행 결과 및 정리


http://localhost:8080/api/user 실행 결과

  • Filter에서 지정한 log가 찍혀야 함


http://localhost:8080/api/tmep 실행 결과

  • Filter에서 지정한 log가 찍히면 안됨


lombok 관련 정리

@DataGetter, Setter, toString, equals, hashCode 등
@NoArgsConstructor기본 생성자
@AllArgsConstructor전체 생성자

Filter 관련 정리

@Slf4jlog.info로 로그 찍기
implements FilterdoFilter 메소드 오버라이딩
chain.doFilter(req, res)Filter가 실행되는 부분
전처리 구간의 형변환Filter 단이라 가능
ContentCachingRequestWrapper 클래스의 copyBodyToResponse 메소드Client가 제대로 된 응답을 받을 수 있도록 꺼낸 내용을 Body에 Copy
@ServletComponentScanMain - 특정 url에 Filter 걸기
@WebFilter(urlPatterns = "")Filter - 특정 url에 Filter 걸기
핵심은 doFilter 이후의 후처리log 찍기 + copyBody

0개의 댓글