티스토리 뷰

1.    쿼츠 기반의 Job Sceduling

-      1 ) `Job` interface : 스케줄링되어 실행될 task의 규격

-      -> Job 인터페이스를 상속 받는 구현 클래스 생성 ( jobA, JobB, SimpleJob )

-      + 스케쥴링을 하기 전에 TaskJob 규격에 맞게 생성해야 한다.

-      + 이는 스케쥴링의 대상(Target)이 된다.

-      2 ) ‘JobDetail’ Interface

-      -> `JobBuilder`를 이용하여 구현객체 생성

-      + 1 )Job에 대한 상세정보를 규격에 맞게 생성한다.

-      + 1 )Job 실행에 필요한 데이터도 Map의 형태로 설정할 수 있다.

-      + 1 ) Job에 대한 nameGroup name도 설정할 수 있다.

-      3 ) ‘Trigger’ Interface : 스케줄링에 대한 정보

-      -> `TriggerBuilder`를 이용하여 구현객체 생성

-      + 1 )Job을 어떻게 실행시킬지 스케줄링에 대한 정보를 설정한다.

-      + : 1초마다 수행, 1시간마다 수행

-      + Detail과 다르게 재사용이 가능하다.

-      4 ) ‘Scheduler’ interface : 실제 스케쥴된대로 Job을 수행시키는 서버

-      -> `StdSchedulerFactory` 클래스를 이용하여 구현객체 생성

-      + Job을 이 서버에 등록하기 위해서는 JobDetailTrigger가 필요하다. (**)

-      5 ) ListenerManager` interface

-      + 4 )scheduler의 이벤트를 모니터링하고, 적절한 CallBack마다 무엇을 수행할 수 있는 리스너 객체를 만들어 등록하는 곳

-      + : 시작할 때, 오류가 났을 때 등등 로그를 찍게 할 수 있다.


[ 1. 동적 SQL 처리 ] (***)

 

[ 1 - 1. mapper에 sql문 준비 ]

 

    <!-- 4. 게시판 검색어 조건에 맞게, 특정 게시글 번호로 검색해서 반환 1 ( 안전하지 않음 )  -->
    <select id="findBoardByBno" resultType="org.zerock.myapp.domain.BoardVO">
        SELECT bno, title, content, writer, insert_ts, update_ts 
        FROM tbl_board 
        WHERE 

        <if test="bno != null">
            bno = #{bno}
        </if>

    </select>

    <!-- 5. 게시판 검색어 조건에 맞게, 특정 제목으로 검색해서 반환 2 (****) -->
    <select id="findBoardByTitle" resultType="org.zerock.myapp.domain.BoardVO">
        SELECT bno, title, content, writer, insert_ts, update_ts 
        FROM tbl_board 

        <where>

            <if test="title != null">
                title LIKE '%'||#{title}||'%'
                <!-- 와일드 카드로 title로 검색 -->
            </if>

        </where>

    </select>

    <!-- 5 - 2. 게시판 검색어 조건에 맞게, 특정 제목으로 검색해서 반환 2 (****) -->
    <select id="findBoardByTitle2" resultType="org.zerock.myapp.domain.BoardVO">
        SELECT bno, title, content, writer, insert_ts, update_ts 
        FROM tbl_board 

        <where>

            <if test="title != null">
                title LIKE #{title}
            </if>

        </where>

    </select>

    <!-- 6. 게시판 검색어 조건에 맞게, 특정 작가로 검색해서 반환 3  -->
    <select id="findBoardByWriter" resultType="org.zerock.myapp.domain.BoardVO">
        SELECT bno, title, content, writer, insert_ts, update_ts 
        FROM tbl_board 

        <trim prefix="WHERE" prefixOverrides="AND | OR">

            <if test="writer != null">
                writer LIKE '%'||#{witer}||'%'
                <!-- 와일드 카드로 writer 검색 -->
            </if>

        </trim>
    </select>

    <!-- 7. 게시판 검색어 조건에 맞게, 특정 게시글 번호와 제목을 검색해서 반환 4  -->
    <select id="findBoardByBnoAndtitle" resultType="org.zerock.myapp.domain.BoardVO">
        SELECT bno, title, content, writer, insert_ts, update_ts 
        FROM tbl_board 

        <!-- 다중 조건식( 체크 조건이 여러개인 경우 )의 처리 -->
        <!-- prefix는 실행될 쿼리의 <trim> 태그 안에 쿼리 가장 앞에 붙여준다. -->
        <!-- prefixOverrides는 조건식이 2개 이상일 때 사용한다. -->
        <!-- prefixOverrides는 실행될 쿼리의 <trim> 문 안에 쿼리 가장 앞에 해당하는 문자들이 있으면 자동으로 지워준다. -->
        <trim prefix="WHERE" prefixOverrides="AND | OR">

            <if test="bno != null">
                bno = #{bno}
            </if>

            <if test="title != null">
                AND title LIKE '%'||#{title}||'%'
            </if>

        </trim>

    </select>

    <!-- 8. 게시판 검색어 조건에 맞게, 특정 게시글 번호 또는 제목을 검색해서 반환 5 (******)  -->
    <select id="findBoardByBnoOrWriter" resultType="org.zerock.myapp.domain.BoardVO">
        SELECT bno, title, content, writer, insert_ts, update_ts 
        FROM tbl_board 

        <!-- switch 문 -->
        <where>

            <choose>

                <!-- when은 하나만 실행이 된다. -->
                <!-- switch와 동일! -->
                <when test="bno != null">
                    bno = #{bno}
                </when>

                <when test="title != null">
                    OR title LIKE '%'||#{title}||'%'
                </when>

                <!-- 그렇지 않으면 컨탠츠 내용내에서 검색하라 -->
                <!-- otherwise는 필수사항이 아닌 선택사항이다. -->
                <otherwise>
                    content LIKE %||#{content}||'%'
                </otherwise>

            </choose>

        </where>

    </select>

    <!-- 9. 게시판 검색어 조건에 맞게, 특정 게시글 번호를 검색해서 반환 ( 검색어가 여러개 ) 6 (******)  -->
    <select id="findBoardsBySomeBnos" resultType="org.zerock.myapp.domain.BoardVO">
        SELECT bno, title, content, writer, insert_ts, update_ts 
        FROM tbl_board 

        <where>

            <!-- ( bno1, bno2, bno3 ... ) -->
            <!-- item은 list의 원소를 bno로 꺼내겠다는 의미이다. -->
            <!-- collection="list"은 타입이기에 이름을 바꾸면 안된다. -->
            <foreach collection="list" item="bno" index="index" open="bno IN (" close=")" separator=",">
                #{bno}
            </foreach>

        </where>
    </select>

 

[ 1 - 2. 동적 sql 실행 ]

 

import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.Timeout;
import org.zerock.myapp.domain.BoardVO;

import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;

@Log4j2
@NoArgsConstructor

@TestInstance(Lifecycle.PER_CLASS)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class DynamicSQLWithConfigXmlTests {
	
	private SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
	private SqlSessionFactory sqlSessionFactory;
	
//	=========================================================================================
	
	@BeforeAll
	void beforeAll() throws IOException {
		
		log.debug("beforeAll() invoked.");
		
		String mybatisConfigXml = "mybatis-config.xml";
		InputStream is = Resources.getResourceAsStream(mybatisConfigXml);
		
		try( is; ){
			this.sqlSessionFactory = builder.build(is);
			
			Objects.requireNonNull(this.sqlSessionFactory);
			log.info( "\t + sqlSessionFactory : {}", this.sqlSessionFactory );
		} // try - with - resources
		
	} // beforeAll()
	
//	=========================================================================================
//	<!-- 1. 게시판 검색어 조건에 맞게, 특정 게시글 번호로 검색해서 반환 1 ( 안전하지 않음 )  -->
//	 <select id="findBoardByBno" resultType="org.zerock.myapp.domain.BoardVO">
//	     SELECT bno, title, content, writer, insert_ts, update_ts 
//	     FROM tbl_board 
//	     WHERE 
//	
//	     <if test="bno != null">
//	         bno = #{bno}
//	     </if>
//     </select>
//	=========================================================================================
	
	// @Disabled
	@Test
	@Order(1)
	@DisplayName("1. findBoardByBno")
	@Timeout(value=5000, unit=TimeUnit.MILLISECONDS)
	public void findBoardByBno() {
		
		log.info("findBoardByBno() invoked.");
		
		SqlSession sqlSession = this.sqlSessionFactory.openSession();
		log.info("\t + 1. sqlSession : {}", sqlSession);
		
		try ( sqlSession; ){
			
			Integer bno = 172;
			
			String namespace = "BoardMapper";
			String sqlId = "findBoardByBno";
			
			 BoardVO board = sqlSession.<BoardVO>selectOne(namespace+"."+sqlId, bno);
			 Objects.requireNonNull(board);
			 log.info("\t + 1. board : {}", board);
			
			// ============================================================================
				// List도 가능
			// List <BoardVO> boards = sqlSession.<BoardVO>selectList(namespace+"."+sqlId, bno);
			// Objects.requireNonNull(boards);
			// boards.forEach(log::info);
			// ============================================================================
			
		} // try - with - resources
		
	} // selectAllBoards
	
//	=========================================================================================
//	<!-- 2. 게시판 검색어 조건에 맞게, 특정 제목으로 검색해서 반환 2 (*****) -->
//    <select id="findBoardByTitle" resultType="org.zerock.myapp.domain.BoardVO">
//	
//        SELECT bno, title, content, writer, insert_ts, update_ts 
//        FROM tbl_board 
//
//        <where>
//
//            <if test="title != null">
//                title LIKE '%'||#{title}||'%'
//                <!-- 와일드 카드로 title로 검색 -->
//            </if>
//
//        </where>
//
//    </select>
//	=========================================================================================
	
	// @Disabled
	@Test
	@Order(2)
	@DisplayName("2. findBoardByTitle")
	@Timeout(value = 5000, unit = TimeUnit.MILLISECONDS)
	public void findBoardByTitle() {
		
		log.info("findBoardByTitle() invoked.");
		
		SqlSession sqlSession = this.sqlSessionFactory.openSession();
		log.info("\t + 2. sqlSession : {}", sqlSession);
		
		try ( sqlSession; ) {
			
			// '%'||#{title}||'%'로 제목에 7이 들어간 것을 출력하게 지정
			String title = "7";
			
			// String title = null;
			// null을 넣으면 where절이 만들어지지 않기에 
			// SELECT bno, title, content, writer, insert_ts, update_ts FROM tbl_board만 수행되어
			// 모든 칼럼이 출력된다.
			
			String namesapce = "BoardMapper";
			String sqlId = "findBoardByTitle";
			
			List<BoardVO> boards = sqlSession.<BoardVO>selectList(namesapce + "." + sqlId, title);
			Objects.requireNonNull(boards);
			boards.forEach(log::info);
			
		} // try - with - resources
		
	} // findBoardByTitle
	
	
//	=========================================================================================
//	<!-- 5 - 2. 게시판 검색어 조건에 맞게, 특정 제목으로 검색해서 반환 2 (****) -->
//    <select id="findBoardByTitle2" resultType="org.zerock.myapp.domain.BoardVO">
//        SELECT bno, title, content, writer, insert_ts, update_ts 
//        FROM tbl_board 
//
//        <where>
//
//            <if test="title != null">
//                title LIKE #{title}
//            </if>
//
//        </where>
//
//    </select>
//	=========================================================================================
	
	// @Disabled
	@Test
	@Order(3)
	@DisplayName("3. findBoardByTitle2")
	@Timeout(value = 5000, unit = TimeUnit.MILLISECONDS)
	public void findBoardByTitle2() {
		
		log.info("findBoardByTitle2() invoked.");
		
		SqlSession sqlSession = this.sqlSessionFactory.openSession();
		log.info("\t + 3. sqlSession : {}", sqlSession);
		
		try ( sqlSession; ) {
			
			// 정확히 제목이 TITLE_7인 칼럼을 출력하게 지정
			// String title에 7을 넣으면, 제목이 7인 칼럼은 없기에 출력되지 않는다.
			String title = "TITLE_7";
			
			// String title = null;
			// null을 넣으면 where절이 만들어지지 않기에 
			// SELECT bno, title, content, writer, insert_ts, update_ts FROM tbl_board만 수행되어
			// 모든 칼럼이 출력된다.
			
			String namesapce = "BoardMapper";
			String sqlId = "findBoardByTitle2";
			
			List<BoardVO> boards = sqlSession.<BoardVO>selectList(namesapce + "." + sqlId, title);
			Objects.requireNonNull(boards);
			boards.forEach(log::info);
			
		} // try - with - resources
		
	} // findBoardByTitle2
	
	
//	=========================================================================================
//	<!-- 6. 게시판 검색어 조건에 맞게, 특정 작가로 검색해서 반환 3  -->
//    <select id="findBoardByWriter" resultType="org.zerock.myapp.domain.BoardVO">
//        SELECT bno, title, content, writer, insert_ts, update_ts 
//        FROM tbl_board 
//
//        <trim prefix="WHERE" prefixOverrides="AND | OR">
//
//            <if test="writer != null">
//                writer LIKE '%'||#{witer}||'%'
//                <!-- 와일드 카드로 writer 검색 -->
//            </if>
//	
//        </trim>
//    </select>
//	=========================================================================================
	
	// @Disabled
	@Test
	@Order(4)
	@DisplayName("4. findBoardByWriter")
	@Timeout(value = 5000, unit = TimeUnit.MILLISECONDS)
	public void findBoardByWriter() {
		
		log.info("findBoardByWriter() invoked.");
		
		SqlSession sqlSession = this.sqlSessionFactory.openSession();
		log.info("\t + 4. sqlSession : {}", sqlSession);
		
		try ( sqlSession; ) {
			
			// 작가 이름 중에 17이 포함되어있는 칼럼을 출력
			String writer = "17";
						
			String namesapce = "BoardMapper";
			String sqlId = "findBoardByWriter";
			
			List<BoardVO> boards = sqlSession.<BoardVO>selectList(namesapce + "." + sqlId, writer);
			Objects.requireNonNull(boards);
			boards.forEach(log::info);
			
		} // try - with - resources
		
	} // findBoardByWriter
	
//	=========================================================================================
//	 <!-- 7. 게시판 검색어 조건에 맞게, 특정 게시글 번호와 제목을 검색해서 반환 4  -->
//    <select id="findBoardByBnoAndWriter" resultType="org.zerock.myapp.domain.BoardVO">
//        SELECT bno, title, content, writer, insert_ts, update_ts 
//        FROM tbl_board 
//
//        <!-- 다중 조건식( 체크 조건이 여러개인 경우 )의 처리 -->
//        <!-- prefix는 실행될 쿼리의 <trim> 태그 안에 쿼리 가장 앞에 붙여준다. -->
//        <!-- prefixOverrides는 조건식이 2개 이상일 때 사용한다. -->
//        <!-- prefixOverrides는 실행될 쿼리의 <trim> 문 안에 쿼리 가장 앞에 해당하는 문자들이 있으면 자동으로 지워준다. -->
//        <trim prefix="WHERE" prefixOverrides="AND | OR">
//
//            <if test="bno != null">
//                bno = #{bno}
//            </if>
//
//            <if test="title != null">
//                AND title LIKE '%'||#{title}||'%'
//            </if>
//
//        </trim>
//
//    </select>
//	=========================================================================================
	
	// @Disabled
	@Test
	@Order(5)
	@DisplayName("5. findBoardByBnoAndtitle")
	@Timeout(value = 5000, unit = TimeUnit.MILLISECONDS)
	public void findBoardByBnoAndtitle() {
		
		log.info("findBoardByBnoAndtitle() invoked.");
		
		SqlSession sqlSession = this.sqlSessionFactory.openSession();
		log.info("\t + 5. sqlSession : {}", sqlSession);
		
		try ( sqlSession; ) {
			
			Integer bno = 33;
			String title = "17";
						
			String namesapce = "BoardMapper";
			String sqlId = "findBoardByBnoAndtitle";
			
			Map<String, Object> params = new HashMap<>();
			params.put("bno", bno);
			params.put("title", title);
			
			List<BoardVO> boards = sqlSession.<BoardVO>selectList(namesapce + "." + sqlId, params);
			Objects.requireNonNull(boards);
			boards.forEach(log::info);
			
		} // try - with - resources
		
	} // findBoardByBnoAndWriter
	
//	=========================================================================================
//	 <!-- 8. 게시판 검색어 조건에 맞게, 특정 게시글 번호 또는 제목을 검색해서 반환 5 (*******)  -->
//    <select id="findBoardByBnoOrWriter" resultType="org.zerock.myapp.domain.BoardVO">
//        SELECT bno, title, content, writer, insert_ts, update_ts 
//        FROM tbl_board 
//
//        <!-- switch 문 -->
//        <where>
//
//            <choose>
//
//                <when test="bno != null">
//                    bno = #{bno}
//                </when>
//
//                <when test="title != null">
//                    OR title LIKE '%'||#{title}||'%'
//                </when>
//
//                <!-- 그렇지 않으면 컨탠츠 내용내에서 검색하라 -->
//                <!-- otherwise는 필수사항이 아닌 선택사항이다. -->
//                <otherwise>
//                    content LIKE %||#{content}||'%'
//                </otherwise>
//
//            </choose>
//
//        </where>
//
//    </select>
//	=========================================================================================
	
	// @Disabled
	@Test
	@Order(6)
	@DisplayName("6. findBoardByBnoOrWriter")
	@Timeout(value = 5000, unit = TimeUnit.MILLISECONDS)
	public void findBoardByBnoOrWriter() {
		
		log.info("findBoardByBnoOrWriter() invoked.");
		
		SqlSession sqlSession = this.sqlSessionFactory.openSession();
		log.info("\t + 6. sqlSession : {}", sqlSession);
		
		try ( sqlSession; ) {
			
			Integer bno = 33;
			String title = "17";
						
			String namesapce = "BoardMapper";
			String sqlId = "findBoardByBnoOrWriter";
			
			Map<String, Object> params = new HashMap<>();
			params.put("bno", bno);
			params.put("title", title);
			
			// case - when의 경우에는 swith문과 동일하게
			// 같은 조건을 달성하는 when이 많을지라도 하나의 when만 실행시킨다.
			// 만약 title만 작성되어, 2번째 when이 실행되면 앞의 OR로 인해 문제가 발생한다고 걱정할 수 있지만,
			// 마이 바티스가 자동으로 지워주기에 괜찮은 부분이다.
			
			List<BoardVO> boards = sqlSession.<BoardVO>selectList(namesapce + "." + sqlId, params);
			Objects.requireNonNull(boards);
			boards.forEach(log::info);
			
		} // try - with - resources
		
	} // findBoardByBnoOrWriter
	
//	=========================================================================================
//	<!-- 9. 게시판 검색어 조건에 맞게, 특정 게시글 번호를 검색해서 반환 ( 검색어가 여러개 ) 6 (******)  -->
//    <select id="findBoardsBySomeBnos" resultType="org.zerock.myapp.domain.BoardVO">
//        SELECT bno, title, content, writer, insert_ts, update_ts 
//        FROM tbl_board 
//
//        <where>
//            
//            bno IN
//
//            <!-- ( bno1, bno2, bno3 ... ) -->
//            <!-- item은 list의 원소를 bno로 꺼내겠다는 의미이다. -->
//            <foreach collection="list" item="bno" index="index" open="(" close=")" separator=",">
//                #{bno}
//            </foreach>
//
//        </where>
//    </select>
//	=========================================================================================
	
	// @Disabled
	@Test
	@Order(7)
	@DisplayName("7. findBoardsBySomeBnos")
	@Timeout(value = 5000, unit = TimeUnit.MILLISECONDS)
	public void findBoardsBySomeBnos() {
		
		log.info("findBoardsBySomeBnos() invoked.");
		
		SqlSession sqlSession = this.sqlSessionFactory.openSession();
		log.info("\t + 7. sqlSession : {}", sqlSession);
		
		try ( sqlSession; ) {
			
			List<Integer> bnoList = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
			log.info("\t + 7. bnoList : {}", bnoList);
						
			String namesapce = "BoardMapper";
			String sqlId = "findBoardsBySomeBnos";
						
			List<BoardVO> boards = sqlSession.<BoardVO>selectList(namesapce + "." + sqlId, bnoList);
			Objects.requireNonNull(boards);
			boards.forEach(log::info);
			
		} // try - with - resources
		
	} // findBoardsBySomeBnos
		
//	=========================================================================================
	
} // end class

[ 2. 쿼츠 - pom.xml 파일 설정 ]

 

<?xml version="1.0" encoding="UTF-8"?>


<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/maven-v4_0_0.xsd">

	<modelVersion>4.0.0</modelVersion>

	<groupId>org.zerock</groupId>
	<artifactId>studyquartz</artifactId>
	<version>1.0.0-BUILD-SNAPSHOT</version>

	<packaging>jar</packaging>

	<name>studyquartz</name>
	<url>http://studyquartz.example.com</url>
	<description>Learing the Quartz Job Scheduler</description>


	<properties>
		<java-version>11</java-version>
		<!-- <java-home>${env.JAVA_HOME}</java-home> -->

		<!-- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<maven.compiler.source>11</maven.compiler.source>
		<maven.compiler.target>11</maven.compiler.target> -->

		<org.apache.logging.log4j-version>2.17.2</org.apache.logging.log4j-version>
	</properties>


	<dependencies>

		<!-- =============== Logging =============== -->

		<dependency>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-core</artifactId>
			<version>${org.apache.logging.log4j-version}</version>
		</dependency>

		<!-- For Spring framework, HikariCP, DriverSpy logging -->
		<dependency>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-slf4j-impl</artifactId>
			<version>${org.apache.logging.log4j-version}</version>
		</dependency>
			

		<!-- =============== Testing =============== -->

		<dependency>
			<groupId>org.junit.jupiter</groupId>
			<artifactId>junit-jupiter-api</artifactId>
			<version>5.8.2</version>
			<scope>test</scope>
		</dependency>
			

		<!-- =============== Misc =============== -->
		
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.18.24</version>
			<scope>provided</scope>
		</dependency>

		<dependency>
			<groupId>org.quartz-scheduler</groupId>
			<artifactId>quartz</artifactId>
			<version>2.3.2</version>
		</dependency>
		     
	</dependencies>


	<build>

	    <plugins>
	
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-eclipse-plugin</artifactId>
				<version>2.10</version>
				
				<configuration>
					<downloadSources>true</downloadSources>
					<downloadJavadocs>false</downloadJavadocs>
				</configuration>
			</plugin>
	
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.10.0</version>
				
				<configuration>
				  <release>${java-version}</release>
				</configuration>
			</plugin>
	
	    </plugins>

	</build>

</project>

[ 3. 쿼츠 - 스케줄 ] (****)

 

[ 3 - 1. Job 생성 ]

 

[ JobA ]

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;


@Log4j2
@NoArgsConstructor
public class JobA implements Job {

	@Override
	public void execute(JobExecutionContext ctx) throws JobExecutionException {
		
		log.trace("execute({}) invoked.", ctx);
		
		try {
			
			log.info("--------------- JobA invoked. ---------------");
			
		} catch ( Exception e ) {
			
			throw new JobExecutionException (e);
			
		} // try - catch

	} // execute

} // JobA

[ JobB ]

import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;


@Log4j2
@NoArgsConstructor
public class JobB implements Job {

	@Override
	public void execute(JobExecutionContext ctx) throws JobExecutionException {
		
		log.trace("execute({}) invoked.", ctx);
		
		try {
			
			log.info("--------------- JobB invoked. ---------------");
			
			// JobDetail에서 넘겨준 데이터를 작업 처리에 사용
			JobDataMap map = ctx.getJobDetail().getJobDataMap();
			
			// JobDetail에서 넘겨준 데이터에서 Value 빼오기
			String key1 = (String)map.get("KEY_1");
			String key2 = map.getString("KEY_2");
			String key3 = map.getString("KEY_3");
			
			log.info("\t + Key1 : {}, Key2 :{}, Key3 : {}", key1, key2, key3);
			
		} catch ( Exception e ) {
			
			throw new JobExecutionException (e);
			
		} // try - catch

	} // execute

} // JobB

 

[ 3 - 2. Job 스케줄링 및 실행 ] (*****)

 

import org.quartz.DailyTimeIntervalScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.ListenerManager;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerListener;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.DateBuilder.IntervalUnit;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.calendar.DailyCalendar;
import org.zerock.myapp.job.JobA;
import org.zerock.myapp.job.JobB;
import org.zerock.myapp.listener.SchedulerListenerlmpl;

import lombok.extern.log4j.Log4j2;

@Log4j2
public class SchedulingServer {

	// 우리가 생성한 3개의 Job을 스케줄링해서 실행시킨다.
	public static void main(String[] args) {
		
		log.trace("SchedulingServer invoked.");
		
		try {
			
			// ================================================
			// 1단계 : 'Scheduler' 인터페이스의 구현객체 획득
			// ================================================
			Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
			log.info("\t + 1. scheduler : {}", scheduler);
			
			
			// ================================================
			// 2단계 : JobA를 위한 'JobDetail' 인터페이스의 구현객체 생성
			// ================================================
			
			// 2 - 1. 쿼츠 JOB Detail to be scheduled
			// + JobDetail은 JobA만을 위한 것이기에, 재사용은 불가능하다.
			JobDetail jobADetail =
					JobBuilder.newJob(JobA.class).
					withIdentity("JobA", "GROUP1"). // withIdentity(Job name, Job 소속 group) Job의 이름과 Job의 소속이름을 생성
					withDescription("JOB A"). // withDescription는 이에 대한 설명을 작성할 수 있다.
					usingJobData("KEY1", "VALUE1").
					usingJobData("KEY2", "VALUE2").
					build(); // .build는 JobDetail 객체를 만들어 준다.
			
			// 2 - 2. 트리거는 잡 스케쥴을 어떻게 수행시킬지 정해준다. ( 스케줄링 정보 )
			// + 트리거는 JobA를 위한 트리거가 아니기에, 재사용이 가능하다.
			// + Job Scheduling registered to the Quartz Scheduler
			Trigger jobATrigger = 
					TriggerBuilder.
					newTrigger(). // 새로운 트리거 생성
					withIdentity("JobA Trigger", "GROUP1"). // 트리거의 이름 생성
					withDescription("Scheduling for JobA"). // 트리거 설명
					withPriority(15). // 트리거의 우선순위
					startNow(). // 지금 시작해라
					withSchedule( SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1).repeatForever() ). // 반복되는 시간과 횟수를 지정
					build();
			
			// + 이러한 트리거를 통해 구동 시에는 1초마다 무한으로 반복해서 수행된다.
			// + repeatForever()대신 다른 것을 넣어 제한적인 횟수만 반복되게 할 수도 있다.
			// + 횟수는 시작하는 횟수를 제외한 횟수로 10을 지정했을 시에는 처음 시작 1번 + 반복횟수 10번이 찍힌다.
			
			
			// ================================================
			// 2단계 : JobB를 위한 'JobDetail' & jobTrigger 인터페이스의 구현객체 생성
			// ================================================
			
			// jobB를 위한 상세 정보
			JobDetail jobBDetail = 
					JobBuilder.
					newJob(JobB.class).
					withIdentity(JobKey.jobKey("JobB", "GROUP1")).
					withDescription("Job Description for JobB").
					usingJobData("KEY_1","VALUE_1").
					usingJobData("KEY_2","VALUE_2").
					usingJobData("KEY_3","VALUE_3").
					build();
			
			// jobB 트리거
			Trigger jobBTrigger = 
					TriggerBuilder.
					newTrigger().
					withIdentity(TriggerKey.triggerKey("JobB Trigger", "GROUP1")).
					withDescription("Scheduling for JobB").
					startNow().								// 어느때 시작할까? (***)
					withSchedule( 							// 시작이후에 어떻게 재기동할까? (****)
							DailyTimeIntervalScheduleBuilder.
							dailyTimeIntervalSchedule().
							withInterval(3, IntervalUnit.SECOND). // 3초 간격으로 ( 여기에서는 밀리세컨드가 불가능 ) 
							withRepeatCount(3) 				// 반복 횟수
					).
					build();
			
			
			// ================================================
			// 3단계 : Scheduler에 JobA / jobADetail / jobATrigger 등록
			// + Scheduler를 이용하여 지정된 Job을 지정한 대로 schedule 등록
			// + JobA는 jobADetail이 가지고 있다.
			// ================================================
			scheduler.scheduleJob(jobADetail , jobATrigger);
			scheduler.scheduleJob(jobBDetail , jobBTrigger);
			
			// ================================================
			// 4단계 : Listener 객체를 생성 및 등록하여,
			// + scheduler / Job / Trigger 이벤트를 모니터링할 수 있다.
			// + SchedulerListener을 implement하는 리스너를 생성해야 한다. (***)
			// ================================================
			ListenerManager lm = scheduler.getListenerManager();
			lm.addSchedulerListener(new SchedulerListenerlmpl());
			
			// ================================================
			// 5단계 : 3단계에 등록한 jobADetail / jobATrigger대로 Job을 수행
			// ================================================
			scheduler.start();
			
		} catch (SchedulerException e) {
			
			// 발생한 예외를 출력하고 정상 종료를 시킨다.
			e.printStackTrace();
			
		} finally {
			log.info("Done!");
		} // try - catch - finally

	} // main

} // end class

[ 4. 실행환경 jar파일로 export하기 ] (****)

 

[ 4 - 1. 프로젝트 선택 -> 오른쪽 클릭 -> Export 클릭 -> Runnable JAR file 선택 ]

 

 

[ 4 - 2. 1 ) jar파일 만들 프로젝트 선택 / 2 ) jar파일 저장할 경로 선택 / 저장할 타입 선택 ]

 

 

[ 4 - 3. 파워쉘에서 확인 ]

 

 - PS C:\jar저장위치> java -jar .\jar파일명.jar

728x90
댓글
«   2024/11   »
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
최근에 올라온 글
Total
Today
Yesterday
공지사항