이번에 많은 테스트를 하며 기록해 두면 좋을 것 같은 내용이다.
상황은 다음과 같다.
1. 파일 다운로드를 모두 void로 리턴한다.
- 스트림으로 이미 내보내서 커밋 됐는데 또 json으로 리턴하려고 하니 response has already been committed 에러가 나는 것으로 보임
2. 파일 다운로드 중간에 IOException 이 발생한 경우 json으로 응답하려고 함
크게 이 두가지다.
바로 코드로 들어가자
public void fileDownload(){
// ...
setDownloadResponseHeaders(...);
OutputStream outputStream = response.getOutputStream();
try (FileInputStream fileInputStream = new FileInputStream(downloadFile.toFile())) {
FileCopyUtils.copy(fileInputStream, outputStream);
} catch (IOException cae) {
cae.printStackTrace();
ErrorResponse.sendJsonResponse(response, ErrorCode.SERVER_ERR);
} finally {
outputStream.close();
}
}
- setDownloadResponseheaders()는 파일 다운로드를 위한 헤더 설정이다.
여기서 outputStream을 왜 try catch resource 구문을 활용하여 ( ) 안에 넣지않고 밖에 넣을 수 밖에 없었는지 실험을 많이 했다.
- ( ) 안에 outputStream이 있으면
1. copy부분에서 IOException이 발생한 경우 outputStream 자원이 먼저 반납된다.
2. 그런데 close 하기 전 commit을 하고 자원이 close 된다.
3. 그래서 ErrorResponse.sendJsonResponse() 메서드에서 응답을 생성 할 수 없다.
그래서 finally로 close 시켜줘야 commit을 내가 원하는 시점에 하고 close 할 수 있다.
아래는 json으로 응답하기 위한 메서드
public static void sendJsonResponse(HttpServletResponse response, ErrorCode errorCode) throws IOException {
response.reset();
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
try (OutputStream outputStream = response.getOutputStream()) {
ObjectMapper objectMapper = new ObjectMapper();
ResultVO resultVO = APIUtil.resResult(errorCode.getErrorCode(), errorCode.getErrorMsg(), null);
String json = objectMapper.writeValueAsString(resultVO);
outputStream.write(json.getBytes(StandardCharsets.UTF_8));
outputStream.flush();
}
}
여기서는 자원을 반납한다.
'자바' 카테고리의 다른 글
ClientAbortException 시 HttpServletResponse 에서 .getOutputStream() 관리 (0) | 2024.12.05 |
---|---|
mockMvc에서 HttpServletRequest 값 넣는 방법 (0) | 2024.12.03 |
[스프링] .properties 에 값이 없는 경우 @Value 기본 값 설정 (0) | 2024.02.19 |
[JDBC] DB PK변경 방법 (0) | 2024.02.07 |
스프링 테스트 코드 @RestControllerAdvice를 거치게 하는 방법 (0) | 2024.01.25 |