스프링 입문

[스프링 입문] 6.3 Filter - Intercepter 활용 (1)

코딩펭귄 2024. 1. 10. 02:45

Filter

- Web Application에서 관리되는 영역

- 가장 앞단에서 client의 요청이 들어오자마자 해당 request body / response body를 기록하는, 보안의 용도로 사용

- Spring Boot Framewor에서 Client로부터 오는 요청/응답에 대해 최조/최종 단계 위치에 존재함 -> 이를통해 요청/응답의 정보를 변경하거나, Spring에의해 데이터가 변환되기전의 순수한 Client의 요청/응답값을 확인할 수 있음

- 유일하게 ServeletRequest, ServeletResponse의 객체를 변환할 수 있음

- 주로 Spring Framework에서 request / response의 Logging용도로 활용하거나, 인증과 관련된 Logic들을 해당Filter에서 처리함

- 이를 선/후처리 함으로써 Service business logic과 분리시킴

이미지출처: 패스트캠퍼스 한번에끝내는 자바/스프링

      - 라이프사이클 : Filter에서부터 시작되는것을 확인할 수 있음

 

 

이번 프로젝트부터는 LomBok도 사용한다

 

만약 프로젝트 생성시 롬복선택하는거 까먹었다면 그래들파일에서 아래 해당 부분 설정 해줘야됨

 

 

 

controller 패키지 : client가 request하는 post를 받아줄수있도록 하기위함

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 {

    //body를 하나 받음
    @PostMapping("")
    public User user(@RequestBody User user){
        log.info("User : {}, {}", user, user);
        return user;
    }
}
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 {

    //body를 하나 받음
    @PostMapping("")
    public User user(@RequestBody User user){
        log.info("Temp : {}, {}", user, user);
        return user;
    }
}

 

dto패키지 - user

package com.example.filter.dto;

import lombok.*;

//@Getter // 아래 변수의 겟,셋메서드 생성해줌
//@Setter // 아래 변수의 겟,셋메서드 생성해줌
@Data // getter, setter, toString, 등등 전부 생성해줌
@NoArgsConstructor //기본생성자
@AllArgsConstructor
public class User {
    private String name;
    private int age;
}

 

filter 패키지 - GlobalFilter

package com.example.filter.filter;

import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;

import java.io.BufferedReader;
import java.io.IOException;

@Slf4j // 로그를 남기기 위함
@WebFilter(urlPatterns = "/api/user/*")
public class GlobalFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        //전처리
        // ContentCaching~~Wrapper = 몇번이고 계속 읽을 수 있도록 만들어줌
        ContentCachingRequestWrapper httpServletRequest = new ContentCachingRequestWrapper((HttpServletRequest)request); //HttpServletRequest로 형변환 시켜서 request매개변수로 넘겨줌
        ContentCachingResponseWrapper httpServletResponse = new ContentCachingResponseWrapper((HttpServletResponse)response);

        // doFilter() 를 통해 실제 내부 스프링 안으로 들어가야 그 메소드가 실행됨
        // -> request에 대한 내용이 byte array에 담김 -> 읽을 수 있음
        chain.doFilter(httpServletRequest, httpServletResponse);

        String url = httpServletRequest.getRequestURI();

        //후처리
        //req
        String reqContent = new String(httpServletRequest.getContentAsByteArray());
        log.info("respuest url : {}, resquest body : {}", url, reqContent);

        String resContent = new String(httpServletResponse.getContentAsByteArray());
        int httpStatus = httpServletResponse.getStatus();

        //내가 읽었던 만큼 다시한번 복사해주는 메소드
        // 이렇게 해야 실제 응답이 클라이언트로 전송될수있음
        httpServletResponse.copyBodyToResponse(); //다시한번 body내용을 채워넣음

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

 

main

package com.example.filter;

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

@SpringBootApplication
@ServletComponentScan
public class FilterApplication {

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

}