장점
slf4j Reference
http://www.slf4j.org/manual.html
slf4j (Simple Logging Facade For Java)
@Slf4j 어노테이션을 이용하면 클래스 별로 로깅 할 수 있음 (log("methodName"))
AOP를 이용하여 관점 지향적으로 logging을 남길 수 있음
log4j : 가장 오래된 Apache Java 기반 로깅 프레임 워크, 콘솔 및 파일 출력의 형태 가능
레벨 level
logback Reference
https://logback.qos.ch/
logback
* log4j2 Reference**
log4j2
Servlet layer - Filter - Interceptor - AOP - Controller
controller 도달 전, 요청 HttpRequest과 응답 HttpResponse을 가로채는 역할
세션 관리,인증 등의 역할을 수행
인증/인가(권한) 등과 같은 공통 작업 (ex: 관리자, 일반 사용자)
Controller로 넘겨주는 정보의 가공
API 호출에 대한 로깅 또는 감사
메소드
preHandle : 컨트롤러가 호출되기 전 실행 메소드, (요청 데이터 전처리,가공)
postHandle : 컨트롤러가 호출된 후 실행 메소드, (후처리 작업)
afterCompletion : 뷰 생성을 포함한 모든 작업이 완료 후 실행 메소드
Filter
보안 관련 공통 작업
모든 요청에 대한 로깅 또는 감사
이미지/데이터 압축 및 문자열 인코딩
web.xml : Encoding Filter 설정
@Order(1) : 우선 순위 1번째, xml에서 순차적으로 코딩하지 않아도 됨
servlet-context.xml : Interceptor 설정
HandlerInterceptor 인터페이스의 메소드를 오버라이딩 해서 사용함
@Slf4j
//@Component // 어차피 servlet-context에 등록해야하므로 사용 X
public class TestInterceptor implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
log.info("preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
@Nullable ModelAndView modelAndView) throws Exception {
log.info("postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
@Nullable Exception ex) throws Exception {
log.info("afterCompletion");
}
}
<!-- servlet-context.xml 에 추가된 내용--->
<!-- 여러 개의 Interceptor를 사용할 경우 순서에 대한 보장은 xml의 코딩된 순서 -->
<interceptors>
<interceptor>
<mapping path="/**"/>
<beans:bean id="testInterceptor" class="com.spring.interceptor.TestInterceptor" />
</interceptor>
<interceptor>
<mapping path="/**"/>
<beans:bean id="testInterceptor2" class="com.spring.interceptor.TestInterceptor2" />
</interceptor>
</interceptors>
commons-fileupload, commons-io 라이브러리 사용
@Slf4j
@Controller
public class FileController {
@RequestMapping(value = "/file-test", method = RequestMethod.GET)
public String home() {
log.info("FileContoller : /file-test");
return "fileTest";
}
@PostMapping(value = "/file-upload")
public void saveFile(@RequestParam("file") MultipartFile file) {
log.info("FileContoller : /file-upload");
// 파일 저장 위치 설정 : savePath
String savePath = "/Users/jh/Desktop/multi/00.spring";
// 기본 파일 이름 + UUID
String fileName = UUID.randomUUID().toString() + "_" + file.getOriginalFilename();
try {
if(!new File(savePath).exists()) { // 해당 위치에 파일이 존재하지 않으면
new File(savePath).mkdir(); // 해당 디렉토리에 생성 (존재하지 않는 상위 폴더 생성 x)
}
// 파일 저장
file.transferTo(new File(savePath + "/" + fileName));
} catch (IllegalStateException | IOException e) {
e.printStackTrace();
}
}
@GetMapping("/file-download")
public ResponseEntity<Resource> loadFile() {
// 지정 경로의 특정 파일 선택 -> resource로 변경 -> Http Header에 컨텐츠의 타입을 지정 후 전달
// uri = 서버상에 존재하는 자원
Path path = Paths.get("/Users/jh/Desktop/multi/00.spring/test.txt");
Resource resource = null;
try {
resource = new InputStreamResource(Files.newInputStream(path));
} catch (IOException e) {
log.error(e.getMessage());
}
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); // OCTET_STREAM : 파일
headers.setContentDisposition(ContentDisposition.builder("attachment").filename("test.txt").build()); // attachment : 첨부 파일
return new ResponseEntity<Resource>(resource, headers, HttpStatus.OK);
}
}
Front에서 필수 설정 : method="POST" enctype="multipart/form-data"
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>File</title>
</head>
<body>
<h1>File</h1>
<form action="/file-upload" method="POST" enctype="multipart/form-data">
<input type="file" name="file"><br />
<input type="submit" value="업로드">
</form>
<hr />
<a href="http://localhost:8082/file-download" >File Download</a>
</body>
</html>
Resolver 추가
<beans:bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></beans:bean>
파일 업로드, 다운로드는 정말 설정해야하는 부분이 많아서 사용자 문법 예외가 많았음
점점 servlet layer, framework layer 중 어디에서 처리되는 것인지 구분이 힘들 때가 있음
Interceptor는 컨트롤러 이전에 전처리 후처리가 가능하고 Filter는 Servlet 전후 처리를 해서 가끔 헷갈림
log를 사용하니까 sysout보다 더 깔끔하고 눈이 덜 아파서 개인적으로 좋았음
클라이언트에서 설정해야하는 부분도 있어서 클라이언트 기술도 조금씩 필요한 것 같음