728x90
Class를 생성하여 Filter 인터페이스를 상속을 받습니다
Filter 인터페이스 내용
import java.io.IOException;
public interface Filter {
// Filter 생성 시 호출되는 메소드
default void init(FilterConfig filterConfig) throws ServletException {
}
void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;
// Filter 삭제 시 호출되는 메소드
default void destroy() {
}
}
doFilter 메서드:
- doFilter(ServletRequest request, ServletResponse response) 메서드를 호출하여 체인의 다음 필터로 요청과 응답을 전달합니다.
- 이 메서드가 호출되지 않으면 요청이 다음 필터 또는 서블릿으로 전달되지 않고 현재 필터에서 처리됩니다.
- 각 필터는 필요에 따라 doFilter 메서드 호출 전에 요청을 처리하거나, 호출 후에 응답을 처리할 수 있습니다.
doFilter()메소드를 활용하여 LoggerFilter 만들기
import jakarta.servlet.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Slf4j
@Component // 빈으로 등록
public class LoggerFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 서비스 로직 시작 전
filterChain.doFilter(servletRequest, servletResponse);
// 서비스 로직 종료 후
}
}
ServletRequest: 요청의 정보를 가진 객체
- 클라이언트가 서버에 보낸 요청에 대한 모든 정보를 포함합니다.
- 요청 파라미터, 속성, 세션 정보, 요청 본문 등의 데이터를 접근할 수 있는 메서드를 제공합니다.
ServletResponse: 응답의 정보를 가진 객체
- 서버가 클라이언트에게 보낼 응답에 대한 모든 정보를 포함합니다.
- 응답 본문 작성, 상태 코드 설정, 콘텐츠 타입 지정 등의 작업을 수행할 수 있는 메서드를 제공합니다.
FilterChain: 필터 체인을 통해 요청과 응답을 전달하는 객체
- 필터 체인은 요청이 들어올 때 여러 필터를 차례대로 적용할 수 있게 해줍니다.
- 각 필터는 요청을 처리하고, 체인의 다음 필터로 요청을 전달하거나, 필요에 따라 응답을 생성할 수도 있습니다.
- 필터 체인을 통해 요청이 최종적으로 서블릿에 도달하거나, 응답이 클라이언트에게 반환되기 전에 여러 단계의 처리를 거칠 수 있습니다.
실습
도서관 사서가 책을 저장하는 프로그램 만들기
@Getter @Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ToString
@JsonNaming(value = PropertyNamingStrategies.SnakeCaseStrategy.class)
public class BookRequest {
private String bookName; // 책 이름
private String category; // 카테고리
private String author; // 저자
private LocalDate publicationDate; // 발행 날짜
}
@Slf4j
@RestController
@RequestMapping("/api/book")
public class BookApiController {
@PostMapping("")
public BookRequest saveBook(
@RequestBody
BookRequest bookRequest
) {
log.info("저장하는 책 정보 : {}", bookRequest.toString());
return bookRequest;
}
}
@Slf4j
@Component
public class LoggerFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
var req = new ContentCachingRequestWrapper((HttpServletRequest) servletRequest);
var res = new ContentCachingResponseWrapper((HttpServletResponse) servletResponse);
filterChain.doFilter(req, res);
var reqJson = new String(req.getContentAsByteArray());
log.info("request : {}", reqJson);
var resJson = new String(res.getContentAsByteArray());
log.info("response : {}", resJson);
res.copyBodyToResponse();
}
}
Logger Filter 클래스 코드 설명
var req = new ContentCachingRequestWrapper((HttpServletRequest) servletRequest);
var res = new ContentCachingResponseWrapper((HttpServletResponse) servletResponse);
- (HttpServletRequest)로 형변환
- ServletRequest는 HTTP 프로토콜뿐 아니라 다양한 프로토콜을 처리할 수 있는 인터페이스입니다.
- HTTP로 처리하기 위해 ServletRequest를 상속받는 HttpServletRequest로 형변환해줍니다.
- ContentCachingRequestWrapper로 객체 생성하기
- HttpServletRequest 인터페이스를 구현한 클래스인 HttpServletRequestWrapper라는 클래스로 요청한 데이터를 확인할 수 있습니다.
- 하지만 HttpServletRequestWrapper로 데이터를 보기 위해서는 데이터를 추출하는 BufferedReader로 반환하는 getReader() 메소드 밖에 없습니다.
- HttpServletRequestWrapper를 상속받은 ContentCachingRequestWrapper에 있는 메소드로 추출한 데이터를 다시 객체에 넣을 수 있습니다.
- new String(getContentAsByteArray())
- 객체에 있는 데이터를 byte array로 추출합니다.
- String 클래스는 인자로 받을 수 있는 값 중 byte[]를 인자로 받을 수 있습니다.
- byte[]를 String으로 바꾸어 내용을 확인합니다.
- res.copyBodyToResponse()
- 해당 메소드는 추출한 데이터를 다시 복원시키는 메소드입니다.
- 해당 메소드를 사용하지 않으면 응답하는 데이터가 존재하지 않습니다.
- 해당 메소드를 사용하기 위해 ContentCachingResponseWrapper 클래스를 사용합니다.
결과 화면
클라이언트가 서버에 보내는 데이터
{
"name": "Spring boot 열공하자", // bookName과 일치하지 않음
"category": "IT",
"author": "철수",
"publicationDate": "2024-07-17" // snake_case 형식과 일치하지 않음
}
서버가 받는 데이터
저장하는 책 정보 : BookRequest(bookName=null, category=IT, author=철수, publicationDate=null)
서버의 LoggerFilter에서 확인한 클라이언트가 보낸 데이터
request : {
"name": "Spring boot 열공하자",
"category": "IT",
"author": "철수",
"publicationDate": "2024/07/17"
}
서버가 클라이언트에게 보낸 데이터
response : {"book_name":null,"category":"IT","author":"철수","publication_date":null}
클라이언트가 받은 response
{
"book_name": null,
"category": "IT",
"author": "철수",
"publication_date": null
}
728x90
'Spring Boot' 카테고리의 다른 글
[Spring Boot] 여러가지 사용하는 Class (0) | 2024.07.24 |
---|---|
[Spring Boot] Web Authentication(웹 인증) (0) | 2024.07.23 |
[Spring Boot] IoC/DI (0) | 2024.07.10 |
[Spring Boot] 유효성 검사와 예외 처리를 통한 API 구현 (0) | 2024.07.05 |
[Spring Boot] Validation 유효성 검사 클라이언트 오류 보내기 (0) | 2024.07.04 |