[포스코DX|Spring|7주] 32일차 수업
포스코DX X 비트교육센터 6기 - Spring
로깅이란?
- 비기능적 요구사항
-
로그 : 프로그램 개발이나 운영 시 발생하는 문제점 추적, 운영 상태를 모니터링하는 정보
-
로깅 : 로그를 생성하도록 시스템을 작성하는 활동
1. 버그 정보 제공
2. 성능 관련 통계, 정보 제공
자바의 로깅
- api가 아니다
- java.util.logging
- Log4J (발전버전)
- SLF4J (발전버전 - 현재도 사용 중)
## 로깅 실습
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.poscodx</groupId>
<artifactId>spring-practices</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>logex</artifactId>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<org.springframework-version>5.3.25</org.springframework-version>
<jcloverslf4j.version>1.7.36</jcloverslf4j.version>
<logback.version>1.2.11</logback.version>
</properties>
<dependencies>
<!-- spring mvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework-version}</version>
<!-- JCL 제외 -->
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-jcl</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- jstl -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- Logback -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${jcloverslf4j.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
</dependencies>
<build>
<finalName>logex</finalName>
</build>
</project>
- 추가
- 결과
mysite03 logging
- pom.xml 변화
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.poscodx</groupId>
<artifactId>mysite</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>mysite03</artifactId>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.build.outputEncoding>UTF-8</project.build.outputEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<org-springframework-version>5.3.25</org-springframework-version>
<jcloverslf4j.version>1.7.36</jcloverslf4j.version>
<logback.version>1.2.11</logback.version>
</properties>
<dependencies>
<!-- spring mvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org-springframework-version}</version>
<!-- JCL 제외 -->
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-jcl</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- spring aspect -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${org-springframework-version}</version>
</dependency>
<!-- spring jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${org-springframework-version}</version>
</dependency>
<!-- jstl -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- mariadb jdbc driver -->
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
<version>3.0.8</version>
</dependency>
<!-- logback -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${jcloverslf4j.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<!-- servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
<scope>provided</scope>
</dependency>
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.7</version>
</dependency>
<!-- Common DBCP -->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
<build>
<finalName>mysite03</finalName>
</build>
</project>
- logback.xml 추가
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<charset>UTF-8</charset>
<Pattern>
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{5} - %msg%n
</Pattern>
</encoder>
</appender>
<appender name="fileAppender2" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/mysite-logs/exception.log</file>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<Pattern>
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{5} - %msg%n
</Pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<FileNamePattern>/mysite-logs/exception.%i.log.zip</FileNamePattern>
<MinIndex>1</MinIndex>
<MaxIndex>10</MaxIndex>
</rollingPolicy>
<triggeringPolicy
class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>100MB</MaxFileSize>
</triggeringPolicy>
</appender>
<appender name="fileAppender3" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/logex/logex3.log</file>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<Pattern>
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{5} - %msg%n
</Pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<FileNamePattern>/logex/logex3.%i.log.zip</FileNamePattern>
<MinIndex>1</MinIndex>
<MaxIndex>10</MaxIndex>
</rollingPolicy>
<triggeringPolicy
class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10KB</MaxFileSize>
</triggeringPolicy>
</appender>
<!--
com.douzone.logex2 아래 패키지 로그들만 \logex\logex2.log 파일에만 출력하는 로거
-->
<logger name="com.poscodx.mysite.exception" level="error" additivity="false">
<appender-ref ref="fileAppender2" />
</logger>
<!-- 루트(글로벌) 로거 -->
<root level="debug">
<appender-ref ref="consoleAppender" />
</root>
</configuration>
- globalExceptionHandler.java
package com.poscodx.mysite.exception;
import java.io.PrintWriter;
import java.io.StringWriter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
@ControllerAdvice
public class GlobalExceptionHandler {
private static final Log logger = LogFactory.getLog(GlobalExceptionHandler.class);
@ExceptionHandler(Exception.class)
public String handlerException(Model model, Exception e) {
//1. 로깅(Logging)
StringWriter errors = new StringWriter();
e.printStackTrace(new PrintWriter(errors));
logger.error(errors.toString());
//2. 사과 페이지
model.addAttribute("errors", errors.toString());
return "error/exception";
}
}
- 결과
파일 업로드
enctype 에 준 값(application/x-www-form-urlencoded)이 form에 default로 담겨있다.
그 동안에 이 값을 안주어도 기본적으로 이 값이 들어가있었다.
- enctype에 들어 갈 수 있는 값 : text/plain(사용 안하는 것이 좋음) , multipart/form-data(파일이 바이너리 정보로) , application/x-www-form-urlencoded (이게 default), application/json(이걸 알기!!! ajax..통신)
- pom.xml
<!-- common fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>1.4</version>
</dependency>
- spring-servlet
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config />
<context:component-scan
base-package="com.poscodx.fileupload.controller" />
<!-- ViewResolver 설정 -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
<property name="order" value="1" />
</bean>
<!-- 이곳 내용 추가!!!!!!!!!!! multipart resolver -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 최대업로드 가능한 바이트크기 -->
<property name="maxUploadSize" value="52428800" />
<!-- 디스크에 임시 파일을 생성하기 전에 메모리에 보관할수있는 최대 바이트 크기 -->
<property name="maxInMemorySize" value="52428800" />
<!-- defaultEncoding -->
<property name="defaultEncoding" value="utf-8" />
</bean>
</beans>
- fileUploadController
package com.poscodx.fileupload.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import com.poscodx.fileupload.service.FileUploadService;
@Controller
public class FileUploadController {
@Autowired
private FileUploadService fileUploadService;
@RequestMapping("/form")
public String form() {
return "form";
}
@RequestMapping(value="/upload", method=RequestMethod.POST)
public String upload(
@RequestParam("e") String email,
@RequestParam("f") MultipartFile file,
Model model) {
System.out.println("--->" + email);
/* 이미지 파일 업로드 처리 */
String url = fileUploadService.restore(file);
model.addAttribute("url", url);
return "result";
}
}
- web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<display-name>emaillist03</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- ContextLoad Listener -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Encoding Filter -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Dispatcher Servlet -->
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-servlet.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- Default Files -->
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
- applicationContext
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">
<context:annotation-config />
<context:component-scan base-package="com.poscodx.fileupload.service">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository" />
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service" />
<context:include-filter type="annotation" expression="org.springframework.stereotype.Component" />
</context:component-scan>
</beans>
- fileUploadService.java
package com.poscodx.fileupload.service;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Calendar;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import com.poscodx.fileupload.exception.FileUploadServiceException;
@Service
public class FileUploadService {
private static String SAVE_PATH = "/mysite-uploads";
private static String URL_PATH = "/images";
public String restore(MultipartFile file) {
String url = null;
try {
File uploadDirectory = new File(SAVE_PATH);
if(!uploadDirectory.exists()) {
uploadDirectory.mkdirs();
}
if(file.isEmpty()) {
return url;
}
String originFilename = file.getOriginalFilename();
String extName = originFilename.substring(originFilename.lastIndexOf(".") + 1);
String saveFilename = generateSaveFilename(extName);
Long fileSize = file.getSize();
System.out.println("########" + originFilename);
System.out.println("########" + saveFilename);
System.out.println("########" + fileSize);
byte[] data = file.getBytes();
OutputStream os = new FileOutputStream(SAVE_PATH + "/" + saveFilename);
os.write(data);
os.close();
url = URL_PATH + "/" + saveFilename;
} catch(IOException ex) {
throw new FileUploadServiceException(ex.toString());
}
return url;
}
private String generateSaveFilename(String extName) {
String filename = "";
Calendar calendar = Calendar.getInstance();
filename += calendar.get(Calendar.YEAR);
filename += calendar.get(Calendar.MONTH);
filename += calendar.get(Calendar.DATE);
filename += calendar.get(Calendar.HOUR);
filename += calendar.get(Calendar.MINUTE);
filename += calendar.get(Calendar.SECOND);
filename += calendar.get(Calendar.MILLISECOND);
filename += ("." + extName);
return filename;
}
}