반응형

1. 개요

 jenkins 자체에서 war파일을 만드는 것은 성공하였으나, 이 war 파일을 tomcat 서버에서 실행 시키는 과정에서 에러가 발생하고 있다. 에러 문구는 다음과 같다.

 

 Deployed application at context path /context but context failed to start instead of the expected "OK" message

 .....

 Build step 'Deploy war/ear to a container' marked build as failure

 

 확인결과 war파일을 tomcat container에 Deploy 하는 과정에서 에러가 발생하고 있음을 알 수 있고, 정확한 원인은 톰캣 로그를 확인해야 한다.

 

2. 확인

 Deploy 과정에서 발생한 로그를 확인해봐야 한다. 배포 과정의 로그가 담긴 tomcat 경로/logs/catalina.log를 확인하여 에러 코드를 확인해보았다.

 확인 결과 다음과 같은 에러 로그를 확인할 수 있었다.

 Unsupported major.minor version 52.0

 오우오우.. 빌드하려는 프로젝트의 컴파일 버전은 1.8(52.0)이나 tomcat에서는 그보다 낮은 jdk 버전으로 빌드를 시도하여 위 에러가 발생하였다. 즉, jdk 1.8은 지원안해요~ 이뜻이다.

 

3. 해결

 (tomcat마다 뭔가 설정을 해주지 않는 한) tomcat은 일반적으로 시스템 변수의 JAVA_HOME을 사용한다.

 시스템 변수의 JAVA_HOME을 직접 들어가서 확인해보면 낮은 버전의 JDK 버전이 설정되어 있을 것이다.

시스템 환경변수의 JAVA_HOME

 이를 jdk 1.8 버전으로 수정하면 된다.

 올바르게 수정됐는지 확인하고 싶다면 pc 재부팅 후 javac -version 명령어를 입력해보면 된다.

javac -version

 

반응형
반응형

1. 개요

 Jenkins와 tomcat 연동 및 빌드 과정에서 다음과 같은 에러가 발생했다.

 Server returned HTTP response code: 401 for URL ~~

 

2. 확인

 401 에러는 자격인증 실패 에러이다. 쉽게 말게 인증이 실패한건데, 로그를 자세히 보니 The username and password you provided are not correct 라는 문구가 보였다.

3. 해결

 jenkins 설정의 빌드 후 조치 / Deploy war/ear to a container 항목에 Contatiners를 새로 추가해주었다.

자격인증 추가

 

add 선택 후 Username와 Password를 설정한다.

자격인증 추가

Username와 Password를 모르겠다면 tomcat경로의 conf/tomcat-users.xml 파일에 기입된 username과 password를 입력하면 된다. 만약 주석처리 되어 있을 경우 다음과 같이 새로 추가해준다.

tomcat-user.xml

4. 결과

 해당 에러는 발생하지 않으며 정상 빌드됨을 확인할 수 있다.

반응형
반응형

1. 개요

 jenkins 에서 빌드 도중 다음과 같은 경고가 나타났다.

 1) Using platform encoding (MS949 actually) to copy filtered resources, i.e. build is platform dependent!

 2) File encoding has not been set, using platform encoding MS949, i.e. build is platform dependent!

 

2. 원인

 maven 빌드 시 인코딩 타입을 따로 지정하지 않아 발생한다.

 

3. 해결

 pom.xml에 노란색으로 표시된 프로퍼티를 추가한다.

 

반응형
반응형

1. 개요

 젠킨스와 github 연동 이후 webhook을 통해 자동 build를 테스트하고 있던 도중 다음과 같은 에러가 발생했다.

build error

 

2. 환경

 jenkins

 window 10

 tomcat 8.0.x

 

3. 해결

javax.servlet.http 는 tomcat 경로의 lib 폴더 안에 servlet-api.jar 에 존재한다.

tomcat을 설정하는 부분은 있으나 빌드하는 과정에서 해당 jar 파일을 못 읽어온다고 가정하고 maven에 servlet-api.jar 의존성을 추가하였다.

sevlet-api 추가

그 후 다시 빌드를 하니 해당 오류가 발생하지 않고 빌드가 성공했다는 메시지를 받을 수 있었다.

반응형
반응형

1. 개요

 서버에서 API 통신이나 HTTP 통신에 대한 응답 값으로 Json 형식의 문자열 데이터가 오는 경우가 있다. 이때 데이터의 특정 key에 해당하는 값에 접근하기 위해 String 클래스에서 제공하는 메서드를 사용할 수도 있으나, 데이터가 복잡해지고, Node 가 많아질 수록 데이터 조작 및 접근에 한계를 느끼게 된다.

 이를 해소할 수 있는 방안으로 문자열 데이터를 JsonObject로 변환하는 방식이 있다. 이를 사용해보자.

 

2. 로직

 간단한 구조에서는 아래 4가지만 기억하면 된다. 

 

 1) String 형식의 JSON 문자열

 2) JSONParser

 3) To Object

 4) To JSONObject

 

 위 4가지를 기억하고 아래 코드를 보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
    public static void jsonTest() throws ParseException{
        //1. Json 문자열
        String strJson = "{\"userId\":\"sim\", "
                        + "\"userPw\":\"simpw\","
                        + "\"userInfo\":{"
                            + "\"age\":50,"
                            + "\"sex\":\"male\""
                            + "}"
                        + "}";
        
        //2. Parser
        JSONParser jsonParser = new JSONParser();
        
        //3. To Object
        Object obj = jsonParser.parse(strJson);
        
        //4. To JsonObject
        JSONObject jsonObj = (JSONObject) obj;
        
        //print
        System.out.println(jsonObj.get("userId")); //sim
        System.out.println(jsonObj.get("userPw")); //simpw
        System.out.println(jsonObj.get("userInfo")); // {"sex":"male","age":50}
 
    }
cs

 1) Json 문자열을 준비한다. (3 line)

  - API를 통해 받아왔다고 가정하고 String 형식의 userId, userPw와 Object 형식의 userInfo 데이터를 준비한다.

  - Json 형식은 {key:value} 형식이며, key값은 큰따옴표(")로 묶여있다. Parser 는 이 큰따옴표를 통해 파싱 처리를 하기 때문에 키 값에 \" 문자열을 추가해주었다.

 

 2) JSONParser (12 line)

  - 문자열을 Json 형식에 맞게 Object로 파싱할 수 있는 Parser를 생성한다. 

 

 3) To Object (15 line)

  - jsonParser를 통해 Json 문자열을 Object 형식으로 파싱한다.

 

 4) To JSONObject (18 line)

  - Object 형식의 데이터를 JSONObject 형식으로 형변환한다.

 

3. 테스트 결과

 JSONObject 형 객체를 통해 String, Object 등의 모든 Json 형식의 데이터에 접근할 수 있다.

반응형
반응형
반응형

1. 개요

 교재를 보며 스프링 부트 환경에서 MVC 패턴을 사용하여 통신 테스트를 하던 도중 예기치 못한 상황이 발생했다.

Controller에서 String 형태로 View의 이름을 반환하려 했으나, 실제 반환된 것은 뷰가 아닌 스트링 자체였다.

test 를 리턴했을 때 test.html 리소스가 반환되는 것이 아닌 test 문자열 자체가 반환된 것이다. 코드를 확인해 보니 이 두 어노테이션을 적절히 사용하지 못해 발생한 문제였다.

 

2. @Controller

 Controller 어노테이션을 사용 시 일반적으로 View Resolver에 설정한 값 기준으로 return 하는 값과 일치하는 View 를 찾아 반환한다. @ResponseBody 어노테이션을 사용할 시 데이터 자체를 반환할 수 있으며, JSON 또는 String 형태로 값을 반환할 수 있다.

 

3. @RestController

 @Controller + @ResponseBody 이다. 해당 컨트롤러에서 View를 리턴하지 않고, REST API를 사용한다면 이 설정이 적절하다.

 

만약 Controller 통신 후 view 페이지를 예상했는데 view 이름만 달랑 있는 페이지가 나오거나, 반대 상황이 나온다면 컨트롤러의 어노테이션을 확인해보자.

 

반응형
반응형
반응형

1. 개요

 JUnit 을 사용하는 테스트 클래스에는 RunWith, ContextConfiguration 어노테이션이 붙는다. 책에서 RunWith는 스프링와 JUnit 간 인터페이스 역할을, ContextConfiguration은 스프링 컨텍스트 설정파일을 읽는 역할을 한다고 하나 크게 와닿지 않았다.

 이런 마음을 갖고 공부를 하던 중 저 의미를 이해하게 되어 글을 남긴다.

 

2. @RunWith

 RunWith(SpringJUnit4ClassRunner.class)는 말 그대로 SpringJUnit4ClassRunner.class를 실행한다는 것이고, 이 클래스는 내부적으로 스프링 컨테이너를 생성해준다.

 

3. @ContextConfiguration

 생성된 스프링 컨테이너에 스프링 빈을 추가하기 위해서는 application-context.xml 파일과 같은 설정 파일을 읽어야 하는데, 이런 설정파일을 로드하는 어노테이션이 ContextConfiguration이다.

 만약 스프링 컨테이너가 필요 없다면, 즉, 스프링 빈 팩토리에서 빈을 로드하는 것이 아닌, 직접 new로 객체를 생성해가며 테스트 코드를 작성할 것이라면 위의 어노테이션을 제거해도 된다.

 

4. 결론

 JUnit 테스트에 스프링 컨테이너를 사용할거면 위의 어노테이션을 넣어주자.

 

반응형
반응형

1. 개요

실무 투입한지 거의 1년이 다 되어갈 무렵, web.xml 코드를 보던 중 문득 이런 생각이 들었다.

'웹 애플리케이션의 첫 단추인 web.xml에 대해 누군가에게 설명할 수 있을까?'  

1년간 일은 열심히 했는데 가장 기본적인것에 대한 공부가 전혀 안되있음을 느껴, 공부 후 포스팅을 한다.

참고로 web.xml에 대한 예제는 MVC 패턴 기준으로 작성했다.


2. 정의

web.xml은 DD (Deployment Descriptor : 배포 설명자)라고 불리며, Web Application의 설정파일이다.

DD는 Web Application 실행 시 메모리에 로드된다.

즉, web.xml이란 웹 어플리케이션을 실행시킬 때 함께 올라가야할 설정(설명)들을 정의해놓은 것이다.

그렇다면 web.xml에는 어떤 설정을 할까?


3. 설정

Web.xml 에서는 크게 DispatcherServlet, ContextLoaderListener, Filter 설정을 한다.

 

클라이언트의 요청을 처리하는 DispatcherServlet.

웹 어플리케이션 컨텍스트 단위의 설정을 로드하는 ContextLoaderListener,

이건 꼭 거쳤으면 좋겠네. Filter.

 

3.1) DispatcherServlet

DispatcherServlet은 클라이언트의 요청을 전달받는 객체이다. 하는 일은? 당연히 클라이언트의 요청을 처리하는 일이다. 그럼 어떻게 처리할까?

 

클라이언트의 요청을 처리하려면 크게 4가지 일이 진행되어야 한다.

 

첫째, 클라이언트의 요청을 처리해줄 컨트롤러를 찾는다.

둘째, 컨트롤러를 실행시킨다. (비지니스 로직 처리)

셋째, 클라이언트에게 보여질 View를 찾는다.

넷째, 응답 데이터와 View를 클라이언트에게 전달한다.

 

요청을 처리할 컨트롤러를 찾는 일은 Handler Mapping이라는 객체가 처리한다. 이 객체는 클라이언트의 요청 경로를 이용해서 컨트롤러를 검색하고, 검색된 객체를 DispatcherServlet에게 리턴한다.

만약 클라이언트가 'http://~~/test' 를 요청할 경우 /test를 처리할 컨트롤러 객체를 리턴하는 것이다. 

 

컨트롤러를 실행시키는 일은 Handler Adapter라는 객체가 처리한다. 이 객체는 @Controller 어노테이션을 이용해 구현한 컨트롤러 뿐만 아니라, Controller 인터페이스를 구현한 컨트롤러, 특수 목적으로 사용되는 HttpRequestHandler 인터페이스를 구현한 클래스를 동일한 방식으로 실행할 수 있도록 만들어졌다. (출처 : 스프링5 입문. 최범균)

즉, 컨트롤러 실행 업무에 특화된 객체로 Controller를 실행하는 것이다.

Controller가 실행되면 개발자가 구현한 비지니스 로직을 거쳐 응답 데이터가 추출된다. 실행된 Controller는 리턴할 데이터와 View를 Handler Adapter에게 리턴한다.

Handler Adapter는 데이터와 view를 ModelAndView 형태로 DispatcherServlet에게 리턴한다.

 

여기서 view는 단순히 view의 이름이다. 뭔 소리냐면 이 이름에 해당하는 실제 view를 찾아야한다는 것이다.

클라이언트에게 보여질 view를 찾는 일은 ViewResolver 객체가 처리한다.

ViewReolver bean 객체 설정

위는 viewResolver 객체를 설정하는 부분인데 설정된 prefix(접두사), suffix(접미사)를 참조하여 처리한다.

만약 Controller에서 리턴한 view 이름이 hello였다면 /WEB-INF/view/hello.jsp를 찾아 dispatcher Servlet에게 리턴한다.

 

최종적으로 viewResolver가 리턴한 View 객체에 응답 데이터를 넣어 클라이언트에게 리턴한다.

 

이처럼 클라이언트의 요청은 DispatcherServlet라는 감독관(?)이 처리한다. 다만 직접 처리하지 않고 적절한 객체들에게 일을 위임하여 처리하고 있다.

 

3.2) ContextLoaderListener

앞서 Dispatcher Servlet은 클라이언트의 요청을 처리하는 객체라고 설명했다. 웹 어플리케이션의 규모가 커진다면, 클라이언트의 요청또한 다양해질 것이고, 이를 처리할 Dispatcher Servlet도 늘어날 가능성이 있다. 다른 성격을 가진 서블릿이 생성될 것이고, 설정 또한 서블릿의 성격에 맞게 각각 적용시켜야 한다.

반면에, 모든 서블릿이 공통으로 가져야할 설정들도 있다. 즉 Servlet Context 단위가 아닌 Application Context 단위의 설정이 필요한데 이를 ContextLoaderListener 객체가 처리한다.

이 객체는 Application Context 단위의 설정을 생성한다.

참고로 Application Context 는 Web Application 의 Context이며, 모든 Servlet들이 참조가 가능한 부모 Context이다.

 

3.3) Filter

클라이언트에서 온 요청을 Dispatcher Servlet이 받기 전 거치는 부분이 있다. 바로 이 Filter 객체이다.

만약 스프링 시큐리티 필터가 적용되어 있다면, 인가 및 인증 처리를 먼저 처리하고, 인코딩 필터가 적용되어 있다면 클라이언트의 요청데이터를 인코딩하는 작업이 선 처리된 후 Dispatcher Servlet에게 필터링 된 데이터가 전달된다.


4. 예제

이제 나같은 코린이가 흔히 봤던... 그저 작성만 했던... web.xml 코드를 분석해보자

 

4.1) web.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
 
 <!-- Dispatcher Servlet 생성 -->
 <servlet>
     <servlet-name>myDispatcherServlet</servlet-name>
     <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
     <init-param>
         <param-name>contextConfigLocation</param-name>
         <param-value>classpath:/config/servlet-config.xml</param-value>
     </init-param>
     
     <load-on-startup>1</load-on-startup>
 </servlet>
 <servlet-mapping>
     <servlet-name>myDispatcherServlet</servlet-name>
     <url-pattern>/</url-pattern>
 </servlet-mapping>
 
 <!-- web application context -->
 <listener>
     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>
 <context-param>
     <param-name>contextConfigLocation</param-name>
     <param-value>
         /WEB-INF/config/application-context.xml
     </param-value>
 </context-param>
 
 <!-- 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>
     <init-param>
         <param-name>forceEncoding</param-name>
         <param-value>true</param-value>
     </init-param>
 </filter>
 <filter-mapping>
     <filter-name>encodingFilter</filter-name>
     <url-pattern>/*</url-pattern>
 </filter-mapping>
</web-app>
cs

분석 전 다시 되새겨보겠다.

첫째, web.xml은 DD(Deploy Descriptor, 배포 설명자)이다.

둘째, DD는 Web Application 실행 시 메모리에 로드된다.

셋째, web.xml에는 크게 dispatcherServlet, contextLoaderListener, filter 를 설정한다.

 

만약 tomcat이라는 WAS(Web Application Server)를 통해 이 web Application을 실행시킨다고 가정하면, web.xml 파일에 설정한 내용들이 메모리에 로드될 것이다.

 

본격적으로 코드를 분석해보자.

 

7 ~ 16 line - 클라이언트의 요청을 처리하는 Dispatcher Servlet을 myDispatcherServlet이란 이름으로 생성하고, 이 서블릿에 대한 설정파일로 servlet-config.xml을 지정한다. (controller 스캔용, 코드는 글의 최하단에 첨부)

 

17 ~ 20 line - 설정한 Dispatcher Servlet이 처리할 url-pattern을 설정한다. '/' 경로로 들어오는 모든 요청에 대해서 myDispatcherServlet이 처리를 담당한다.

 

23 ~ 31 line - web application context 단위의 설정파일로 application-context.xml을 설정한다. 이 설정은 servelt으로 생성한 myDispatcherServlet에게 공유된다. (view-resolver 설정용, 코드는 글의 최하단에 첨부)

 

34 ~ 47 line - 스프링에서 지원하는 encoding Filter를 filter에 추가한다.

 

48 ~ 51 line - encoding Filter가 처리할 url-pattern을 설정한다. '/*' 모든 경로에 대해 인코딩 필터를 적용한다.

 

정리하면 이 예제 web.xml은 클라이언트의 요청을 처리할 인코딩 필터와 Dispatcher Servelt을 생성하고, view Resolver를 web application context 단위로 설정하였다.

 

> servlet-config.xml

1
2
3
4
5
6
7
8
9
10
11
12
<?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: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/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
 
 
    <context:component-scan base-package="controller"/>
    
</beans>
 
cs

 

> application-context.xml

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
 
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/view/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>
 
cs

 

반응형
반응형

STS의 Spring Web 프로젝트를 생성했더니, tomcat 연동이 되지 않는 오류 발생.

 

에러 내용은

There are no resource that can be added or removed from the server.

 

두둥.

 

구글링 결과,

 

  1) 프로젝트 우클릭 > Properties > Project Facets > Dynamic Web Module, Java, Javascript를 체크

    2) Further configuration available ... 클릭!

 

    3) 아래와 같이 설정 및 web.xml 체크

 

하면 된다고 했으나, 그래도 되질 않아서 삽질에 삽질 중 해결.

 

   4) Cloud Foundry Standalone Application 체크 해제!

 

STS 버전에 따라 저게 체크된 채로 프로젝트가 생성되더군요..

 

해제하니까 add and Remove 성공...

 

즐코!

반응형
반응형

1. 개요

 quartz 를 사용하여 1초마다 로그 클래스를 실행시키고, 발생하는 로그를 1분마다 Rolling 하여 파일로 남겨보자!


2. 환경

 1) maven

 2) JDK 1.8

 3) Tomcat 8.0


3. 준비

 3.1) Maven 라이브러리 추가

  스프링 라이브러리와 quartz 라이브러리를 추가해주자

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.8.RELEASE</version>
    </dependency>
    
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>5.2.8.RELEASE</version>
    </dependency>
    
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>5.2.8.RELEASE</version>
    </dependency>
    
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
    <!-- dispatcherServlet 지원 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.8.RELEASE</version>
    </dependency>
        
    <!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
    <dependency>
        <groupId>org.quartz-scheduler</groupId>
        <artifactId>quartz</artifactId>
        <version>2.3.0</version>
    </dependency>
cs

 

 3.2) web.xml 파일 설정

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  
      <!-- Controller가 공유하는 Bean들을 포함하는 Spring Container를 생성한다. 
             공통 설정파일은 여기에 생성한다. 즉 quartz 또한 이곳에 생성하는 것이 좋다.
      -->
      
      <context-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>
              /WEB-INF/spring/quartz-context.xml
          </param-value>
      </context-param>
      
      <listener>
          <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
      </listener>
      
      
     <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>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    
    <!-- /의 형식으로 시작하는 url에 대하여 UTF-8로 인코딩 -->
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
 
</web-app>
cs

 contextConfigLocation을 /WEB-INF/spring/quartz-context.xml 로 설정하고, UTF-8 인코딩 설정한다(인코딩 부분은 딱히 필요없지만 넣었다.)

 

 3.3) quartz-context.xml 파일 생성

 WEB-INF에 spring 폴더를 생성하고 내부에 quartz-context.xml 파일을 생성하자.

요로코롬.

이제 기본적인 준비가 끝났다. 실제 동작을 위한 코드를 삽입하자.


4. 클래스 생성 및 코딩

 - TestJob.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package quartz;
 
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
 
public class TestJob implements Job{
    
    private Logger logger = LogManager.getLogger(TestJob.class);
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        // TODO Auto-generated method stub
        logger.debug("this is log and for you");
        logger.trace("this is log and for you");
        logger.info("this is log and for you");
        logger.warn("this is log and for you");
        logger.error("this is log and for you");
    }
}
 
cs

quartz를 적용시키려면 반드시 Job 인터페이스를 상속받아야 한다.

그리고 execute에 실행시킬 로직을 삽입한다.

보는것과 같이 log를 level 별로 찍고있다.

 

 - CronTrigger.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package quartz;
 
import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;
 
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.Trigger;
import org.quartz.impl.StdSchedulerFactory;
 
public class CronTrigger {
    
    public CronTrigger() {
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        try {
            Scheduler scheduler = schedulerFactory.getScheduler();
            
            JobDetail job = newJob(TestJob.class)
                    .withIdentity("jobName""jobGroup")
                    .build();
            
            Trigger trigger = newTrigger()
                    .withIdentity("triggerName1""triggerGroup1")
                    .withSchedule(cronSchedule("0/1 * * * * ?"))
                    .build();
 
            scheduler.scheduleJob(job, trigger);
            
            scheduler.start();
        }catch(Exception e){
            System.out.println(e.getMessage());
        }
        
    }
}
cs

 

JobDetail 에는 스케줄링 하려는 클래스 정보를, Trigger에는 cron 설정을 통해 스케줄링 시간을 설정한다.

* "0/1 * * * * ?" : 1초마다 실행

 

29번 줄을 통해 스케줄러 잡에 job, trigger를 등록시키고, 31번줄에서 start 시킨다.

결과적으로 1초마다 TestJob의 execute 메서드가 실행된다.


5. quartz-context

 앞서 생성한 quartz-context 설정을 통해 CronTrigger 객체를 bean으로 등록하도록 한다.

 bean으로 등록하는 과정에서 기본생성자인 CronTrigger()를 호출하고, 이 생성자를 통해 설정이 세팅 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.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
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
 
    <!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
    
    <beans:bean id = "cronTrigger" class = "quartz.CronTrigger"/>
    
</beans:beans>
cs

quartz.CronTrigger 객체를 bean으로 등록한다.

 

그 후 서버 tomcat 서버를 실행시키면 아래와 같은 라이프 사이클을 통해 quartz가 시작된다!

 

web.xml load -> quartz-context load -> CronTrigger bean 객체 생성 -> 기본생성자 호출 -> quartz 세팅 및 start!

 

실행 결과 아래와 같은 화면이 출력된다면 quartz 구현에 성공한 것이다.

console 로그

 

추가적으로! 앞의 게시글에서 설정했던 Rolling 파일을 확인해보자.

생성된 Rolling 폴더 및 log 파일
Rolling 파일

매 분마다 폴더가 생성되고, 그 시간동안 쌓였던 로그데이터가 해당 폴더로 들어가 zip 파일로 남게되는 것을 확인할 수 있을 것이다!

 

만약 이를 1일단위로 설정한다면 1일마다 쌓인 로그들이 압축파일 형태로 저장되기 때문에 로그로 인한 저장공간 사용량을 줄일 수 있고, 필요할 때마다 해당 일자의 로그를 살펴볼 수 있기 때문에 로그 관리의 효율성이 높아진다!

 

 

------끄읕------

반응형

+ Recent posts