부스트 코스(웹) PROJ6-1

Posted by 이창권 on September 19, 2019

지난 개발까지에서는 한줄평 조회가 있었다면 이번에는 한줄평 등록입니다!

이번 백엔드 프로젝트에서는 파일 업로드와 로그 인터셉트로 크게 두가지 기능을 구현해야 합니다.

파일 업로드

기존에 이미지를 보여줄 때는 컨트롤러를 거치지 않고 webapp폴더 경로 아래의 static한 파일들을 보여주었습니다.
하지만 이는 보안 상의 이유로 좋지 않습니다.
게다가 사용자가 한줄평에 이미지를 넣어 등록하는 경우, 모두가 접근 가능한 webapp폴더에 저장하는 것이 아닌 다른 저장소에 저장한 다음 컨트롤러를 통해서 접근하게 하여야 합니다.

파일 업로드의 경우에 사용자가 올린 파일을 저장하기 위해 해당 파일명을 유일하게 해야하기 때문에, UUID클래스를 사용하여 파일명을 작성하였습니다.
파일은 주로 크기가 크기 때문에 버퍼를 이용하여 저장하여야하는데, 이를 위해 InputStream과 OutputStream을 이용하여 로컬에 파일을 저장하였습니다.

파일 다운로드를 위한 컨트롤러는 간단하기 때문에 예시를 보도록 하겠습니다.

multipart 요청이 들어올 시에 는 따로 resolver를 설정해 주어야 처리가 가능합니다.
따라서 WebMvcContextConfiguration파일에 밑과 같이 bean을 추가하여 줍니다.

@Bean
public MultipartResolver multipartResolver() {
    org.springframework.web.multipart.commons.CommonsMultipartResolver multipartResolver = new org.springframework.web.multipart.commons.CommonsMultipartResolver();
    multipartResolver.setMaxUploadSize(10485760); // 1024 * 1024 * 10
    return multipartResolver;
}

그리고 필요한 컨트롤러를 작성하여 줍니다.

@GetMapping("/comment-image/{id}")
public void getCommentImage(@PathVariable(name = "id") int commentImageId, HttpServletRequest request, HttpServletResponse response) {
    response.setHeader("Content-Transfer-Encoding", "binary");
    response.setHeader("Content-Type", 파일 확장자);
    response.setHeader("Pragma", "no-cache;");
    response.setHeader("Expires", "-1;");

    try {
        FileInputStream fis = new FileInputStream(저장소 경로+파일 이름
        OutputStream out = response.getOutputStream();

        writeWithStream(fis, out);
    } catch (Exception ex) {
        throw new RuntimeException("file Save Error");
    }
}

로그 인터셉터

인터셉터는 Dispatcher servlet에서 Handler(Controller)로 요청을 보낼 때, Handler에서 Dispathcer servlet으로 응답을 보낼 때 동작합니다.

운영 중인 웹 애플리케이션이 문제가 발생했을 경우, 문제의 원인을 파악하려면 문제가 발생했을 때 당시의 정보가 필요합니다.
이런 정보를 얻기 위해서 Exception이 발생했거나, 중요 기능이 실행되는 부분에서는 적절한 로그를 남겨야 합니다.

인터셉터를 이용하여 로그를 남길 수 있습니다.

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new LogInterceptor());
}

위와 같이 인터셉터를 WebMvcContextConfiguration에 추가하여 준 후

public class LogInterceptor extends HandlerInterceptorAdapter {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        서블릿 작동 종료  로그 남기기
        logger.debug("컨트롤러 : {} 액션: {} ", controllerName, actionName);
	}
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
		서블릿 작동  request 로그 남기기
        logger.debug("요청 URL:{}, 시간:{}, 클라이언트ip:{} ",request.getRequestURL(),
    }
}

위와 같은 형식으로 모든 처리를 인터셉트해 로그를 남길 수 있습니다.