package com.twokimss.config;
import javax.annotation.PostConstruct;
import org.apache.ibatis.javassist.bytecode.stackmap.TypeData.ClassName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import com.twokimss.web.batch.service.ScheduleExec;
import com.twokimss.web.batch.service.SchedulerFuture2Service;
import com.twokimss.web.batch.service.SchedulerFutureService;
import com.twokimss.web.batch.service.SchedulerService;
import com.twokimss.web.util.ContextUtil;
//스케쥴 테스트하고 싶을때 아래 3개 주석 풀어서 사용하기
@Configuration
@EnableScheduling
@EnableAsync
public class ScheduleConfig {
// 스프링 부트에서 스케줄러 기능을 사용하기 위해 @EnableScheduling 설정
private Logger logger = LoggerFactory.getLogger(ClassName.class);
//@ConditionalOnBean(ContextUtil.class)
@Autowired
private SchedulerService schedulerService;
@Autowired
private SchedulerFutureService schedulerFutureService;
@Autowired
private SchedulerFuture2Service schedulerFuture2Service;
// 1. Component는 class level에 선언,
// Bean은 메소드 레벨에 선언
// 2. Bean을 사용시 Configuration 어노테이션을 꼭 사용
// 또는 @SpringBootApplication 어노테이션이 들어간 스프링 실행부에 사용
// 3. Bean은 외부 라이브러리가 제공하는 객체를 사용할 때
// Component는 내부에서 직접 접근 가능한 클래스에 사용
// 4. Bean은 유연한 빈 등록이 필요할때 사용(환경파일읽어서 동적생성)
//순서: 생성자, @PostConstruct, @Bean
public ScheduleConfig() {
logger.debug("ScheduledConfig=================>생성자");
}
@PostConstruct
public void init() {
logger.debug("ScheduledConfig=================>init");
//테스트할때 아래 열고하기...
//schedulerFutureService.start();
//schedulerFuture2Service.scheduleJob("biz003");
// Thread.sleep(10000);
// schedulerFutureService.changeCron("*/3 * * * * *");
// Thread.sleep(20000);
}
@Bean
public ScheduleExec scheduler() {
logger.debug("ScheduleExec=================>ScheduleExec Bean 등록");
ScheduleExec scheduleExec = new ScheduleExec();
scheduleExec.createScheduler();
return scheduleExec;
}
// @Bean
// public TaskScheduler scheduler() {
// logger.debug("ScheduledConfig=================>TaskScheduler Bean 등록");
//
// ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
// scheduler.setPoolSize(4);
// scheduler.setThreadNamePrefix("threadBiz-");//threadNamePrefix
// scheduler.setBeanName("threadPoolTaskScheduler");
// scheduler.initialize();
//
//
// return scheduler;
// }
}
package com.twokimss.web.batch.service;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import javax.annotation.PostConstruct;
import org.apache.ibatis.javassist.bytecode.stackmap.TypeData.ClassName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
public class ScheduleExec {
private Logger logger = LoggerFactory.getLogger(ClassName.class);
@Autowired
private JobBeforeProc jobBeforeProc;
private String beanType = "";
private int SINGLE_POOL_SIZE = 4;
private long delay = 1000 * 2; //2초 주기
private ScheduledExecutorService scheduler = null;
private HashMap<String, ScheduledFuture<?>> mapJobs = null;
public ScheduleExec() {
logger.debug("ScheduleExec=========================>");
this.mapJobs = new HashMap<String, ScheduledFuture<?>>();
this.beanType = JobConst.BEAN_TYPE_ONLY_CLASS;
//this.beanType = JobConst.BEAN_TYPE_WITH_PACKAGE; //다른 서비스 막 호출해서 쓸려면 이방법으로는 안되겠다.
}
public void createScheduler() {
logger.debug("createScheduler=========================>");
this.scheduler = Executors.newScheduledThreadPool(SINGLE_POOL_SIZE);
}
@PostConstruct
public void startScheduleList() {
logger.debug("startScheduleList=========================>");
//사용할 배치 작업 여기에 등록
//현재는 scheduleWithFixedDelay 만 사용했는데, next trigger 운영환경에서 변경할수 있도록 매소드 추가 필요. (Cron, Rate, Fix....)
//테스트 할때 아래 주석 풀고 하기
//this.scheduleJob("job00401");
this.scheduleJob("job00402");
}
public void scheduleJob(String jobKey) {
logger.debug("scheduleJob start=========================>");
logger.debug("futureKey=================================>"+jobKey);
HashMap<String,Object> mapRtn = jobBeforeProc.getClassNm(jobKey, this.beanType);
if("-1".equals(mapRtn.get("rtnCd").toString())){
logger.debug("futureKey================["+jobKey+"]실행중지된 작업");
return;
}
logger.debug("scheduleJob start========classNm=================>"+mapRtn.get("classNm").toString());
Runnable runnable = new JobRunnable(jobKey, mapRtn); //jobKey 에 맞는 Biz Class Get
//long initialDelay = 1000 * 60;
//this.delay = 1000 * 60;
logger.debug(jobKey+"=========>job등록시간 ====>"+JobDateUtil.getDateTime());
//ScheduledFuture<?> job = this.scheduler.scheduleWithFixedDelay(runnable, initialDelay, this.delay, TimeUnit.MILLISECONDS); //schedule 에 Biz Class 등록, job종료시점에서 delay후 재시작
//ScheduledFuture<?> job = this.scheduler.scheduleAtFixedRate(runnable, initialDelay, this.delay, TimeUnit.MILLISECONDS); //schedule 에 Biz Class 등록, job시작시점에서 delay후 재시작
/*
* 오전 6시 30분 30초에 시작
*/
int iH = 6;
int iM = 30;
int iS = 30;
long initialDelay = JobDateUtil.getInitialDelay(iH, iM, iS);
// /**
// * 매일
// */
// this.delay = JobDateUtil.getDelay(1, JobConst.DELAY_TYPE_DAY);
// /**
// * 2시간 주기로
// */
// this.delay = JobDateUtil.getDelay(2, JobConst.DELAY_TYPE_HH);
/**
* 5분 주기로
*/
this.delay = JobDateUtil.getDelay(5, JobConst.DELAY_TYPE_MI);
ScheduledFuture<?> job = this.scheduler.scheduleAtFixedRate(runnable, initialDelay, this.delay, TimeUnit.MILLISECONDS); //schedule 에 Biz Class 등록, job시작시점에서 delay후 재시작
this.mapJobs.put(jobKey, job); //pause, delete, reschedule 용으로 담아두기
}
public void pauseDeleteJob(String jobKey) {
if(jobKey == null|| jobKey.isBlank()) return;
if(this.mapJobs == null || this.mapJobs.isEmpty()) return;
ScheduledFuture<?> targetJob = this.mapJobs.get(jobKey);
if(targetJob == null) return;
if(targetJob.isCancelled()) return;
if(targetJob.isDone()) return;
targetJob.cancel(true);
}
public void rescheduleJob(String jobKey) {
this.pauseDeleteJob(jobKey);
this.mapJobs.remove(jobKey);
this.setDelay(1000 * 10);
this.scheduleJob(jobKey);
}
private void setDelay(long delay) {
this.delay = delay;
logger.debug("setDelay=====>"+this.delay);
}
public void shutdownScheduler(boolean isNow) {
if(isNow) {
logger.debug("shutdownScheduler=====>true");
this.scheduler.shutdownNow();
}else {
logger.debug("shutdownScheduler=====>false");
this.scheduler.shutdown();
}
}
}
package com.twokimss.web.batch.service;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import org.apache.ibatis.javassist.bytecode.stackmap.TypeData.ClassName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.twokimss.web.util.ContextUtil;
public class JobRunnable implements Runnable {
private Logger logger = LoggerFactory.getLogger(ClassName.class);
private String jobKey = "";
private String classNm = "";
private String beanType = null;
public JobRunnable() {
}
public JobRunnable(String jobKey, HashMap<String, Object> clssInfo) {
this.jobKey = jobKey;
this.classNm = clssInfo.get("classNm").toString();
this.beanType = clssInfo.get("beanType").toString();
}
@Override
public void run() {
this.invokeClass(this.beanType);
}
private void invokeClass(String beanType) {
try {
if (beanType.equals(JobConst.BEAN_TYPE_WITH_PACKAGE)) {
this.invokeWithPackage();
} else if (beanType.equals(JobConst.BEAN_TYPE_ONLY_CLASS)) {
this.invokeOnlyClass();
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void invokeOnlyClass() {
try {
String methodNm = "execute";
// Object[] methodArgs = null;
Method method = null;
Object obj = null;
////ContextUtil.getBean 방식으로 했더니 톰켓 start 할때 nullpoint 에러 나서. ( 실행할때는 문제가 없는데 )
try {
obj = ContextUtil.getBean(this.classNm); // 스프링에 등록된 서비스 클래스 가져오기
} catch (NullPointerException ee) {
logger.debug("ContextUtil.getBean 로드 에러");
return;
}
String taskClassName = obj.getClass().getName().split("\\$")[0];
Class<?> taskClass = getClass().getClassLoader().loadClass(taskClassName);
method = taskClass.getDeclaredMethod(methodNm);
// methodArgs = new Object[] {}; //메서드 param
// method.invoke(obj, methodArgs);
method.invoke(obj);
} catch (Exception e) {
}
}
private void invokeWithPackage() {
try {
String methodNm = "execute";
// Object[] methodArgs = null;
Class<?> clss = Class.forName(this.classNm);
Constructor<?> constructor = clss.getConstructor();
Object obj = constructor.newInstance();
Method method = clss.getDeclaredMethod(methodNm);
// methodArgs = new Object[] {}; //메서드 param
// method.invoke(obj, methodArgs); //파라미터 있을때
method.invoke(obj);
} catch (Exception e) {
}
}
}
package com.twokimss.web.batch.service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.javassist.bytecode.stackmap.TypeData.ClassName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.twokimss.web.filemng.service.impl.FileServiceImpl;
@Service("jobBiz00401")
public class JobBiz00401 {
private Logger logger = LoggerFactory.getLogger(ClassName.class);
//JobConst.BEAN_TYPE_WITH_PACKAGE 방식일때 @Autowired 로는 작동을 안해서
@Autowired
private JobSyncBiz jobSyncBiz;
@Autowired
private JobAsyncBiz jobAsyncBiz;
@Autowired
private FileServiceImpl fileServiceImpl;
@Autowired
private ScheduleExec scheduleExec;
// private JobSyncBiz jobSyncBiz;
// private JobAsyncBiz jobAsyncBiz;
public JobBiz00401() {
//다른 서비스 막 호출해서 쓸려면 이방법으로는 안되겠다.
// this.jobSyncBiz = new JobSyncBiz();
// this.jobAsyncBiz = new JobAsyncBiz();
}
@Transactional(value="transactionManagerOracle", propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
public void execute() throws Exception{
//Biz 로직 구현
logger.info("[00401===>실행 시작] : {}", JobDateUtil.getDateTime());
this.jobSyncBiz.saveFileInfo();
//this.jobAsyncBiz.createFile();
//비동기 실행때문에 CompletableFuture 에서 호출
// CompletableFuture<Void> future = CompletableFuture.runAsync(()->{
//
// try {
// this.jobAsyncBiz.createFile();
// } catch (Exception e) {
// throw new CompletionException(e); //jobAsyncBiz.createFile 에서 throw 발생시켰을때
// }
//
// }
// );
// //비동기 실행때문에 CompletableFuture 에서 호출
// //jobAsyncBiz.createFile 에서 return 값이 있을때 supplyAsync 사용후 Integer return 타입으로 받음
// CompletableFuture<Integer> a = CompletableFuture.supplyAsync(() -> {
// try {
// return this.jobAsyncBiz.createFile();
// }
// catch(Exception ex) {
// throw new CompletionException(ex); //jobAsyncBiz.createFile 에서 throw 발생시켰을때
// }
// }
// );
//**********************************************************************************
//결과정보 조회
//**********************************************************************************
Map mapGrqSeq = new HashMap<String,Object>();
//mapGrqSeq.put("GRP_SEQ", "1");
List<?> list = null;
try {
list = fileServiceImpl.selFileList(mapGrqSeq);
} catch (Exception e) {
e.printStackTrace();
}
logger.debug("DB 저장후 조회된 파일건수 >> " + list.size());
//11번 생성후 rollback 처리되고, job 은 멈추고
if(list.size() >= 11) {
logger.debug("강제에러발생===========================>");
scheduleExec.pauseDeleteJob("job00401");
throw new Exception("강제에러");
}
logger.info("[00401===>실행 종료] : {}", JobDateUtil.getDateTime());
}
// public void execute() {
//
// logger.info("[00401===>실행 시작] : {}", JobDateUtil.getDateTime());
//
// try {
// Thread.sleep(1000 * 2); //2초 대기
//
//
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
//
// logger.info("[00401===>실행 종료] : {}", JobDateUtil.getDateTime());
//
// }
}
package com.twokimss.web.batch.service;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.FilenameUtils;
import org.apache.ibatis.javassist.bytecode.stackmap.TypeData.ClassName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.twokimss.web.filemng.service.impl.FileServiceImpl;
@Service("jobSyncBiz")
public class JobSyncBiz {
//빨리 끝나는 업무 : 동기
private Logger logger = LoggerFactory.getLogger(ClassName.class);
@Autowired
private FileServiceImpl fileServiceImpl;
@Transactional(value="transactionManagerOracle", propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
public void saveFileInfo() {
logger.info("[saveFileInfo===>실행 시작] : {}", JobDateUtil.getDateTime());
// try {
// Thread.sleep(1000 * 2); //2초 대기
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
//**********************************************************************************
//결과정보 table 저장
//**********************************************************************************
List<Map<String, Object>> listDs = new ArrayList<Map<String, Object>>();
Map<String, Object> mapRow = new HashMap<String,Object>(); //파일정보 map
String filePath = "D:\\devmine\\fileroot\\";
filePath = filePath.replace("\\\\", "\\").replace("//", "/");
mapRow.put("DEL_YN", "N");
String fileName = "tempTest.png";
long fileSize = 1024;
fileName = FilenameUtils.getName(fileName);
String baseName = FilenameUtils.getBaseName(fileName); //확장자제외한 파일명
String fileExt = FilenameUtils.getExtension(fileName); //확장자만 구하기
mapRow.put("PATH", filePath); //파일경로(파일명을 제외한 PATH)
mapRow.put("FULL_PATH", filePath+fileName); //파일경로(파일명 포함한 PATH)
mapRow.put("FILE_NAME", fileName); //서버에 저장된 파일이름
mapRow.put("ORIGINAL_NAME", fileName); //파일원래이름
mapRow.put("ORIGINAL_EXTENSION", fileExt); //파일원래 확장자
mapRow.put("FILE_SIZE", fileSize); //파일사이즈
mapRow.put("FULL_PATH", filePath+fileName); //파일경로(파일명 포함한 PATH)
mapRow.put("FILE_NAME", fileName); //서버에 저장된 파일이름
listDs.add(mapRow);
Map<String, Object> inListInfo = new HashMap<String,Object>();
inListInfo.put("ds_fileInfo", listDs);
Map mapGrqSeq = null;
try {
mapGrqSeq = fileServiceImpl.saveFileInfo(inListInfo); ////파일그룹번호 return 됨
logger.debug("생성된 파일그룹 SEQ >>> " + mapGrqSeq.get("GRP_SEQ"));
} catch (Exception e) {
e.printStackTrace();
}
logger.info("[saveFileInfo===>실행 종료] : {}", JobDateUtil.getDateTime());
}
}
package com.twokimss.web.batch.service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.javassist.bytecode.stackmap.TypeData.ClassName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import com.twokimss.web.filemng.service.impl.FileServiceImpl;
@Service("jobAsyncBiz")
public class JobAsyncBiz {
//오래걸리는 업무 : 비동기
private Logger logger = LoggerFactory.getLogger(ClassName.class);
@Autowired
private FileServiceImpl fileServiceImpl;
@Async
public int createFile() throws Exception {
logger.info("[createFile==============>실행 시작] : {}", JobDateUtil.getDateTime());
// try {
// Thread.sleep(1000 * 20); //20초 대기
//
// //물리파일 생성 작업 여기에 코딩...
//
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
//**********************************************************************************
//결과정보 조회
//**********************************************************************************
Map mapGrqSeq = new HashMap<String,Object>();
//mapGrqSeq.put("GRP_SEQ", "1");
List<?> list = null;
try {
list = fileServiceImpl.selFileList(mapGrqSeq);
} catch (Exception e) {
e.printStackTrace();
}
logger.debug("DB 저장후 조회된 파일건수 >> " + list.size());
if(list.size() >= 10) {
throw new Exception("강제에러"); //throw 발생시켰을때 확인하려고
}
logger.info("[createFile=============>실행 종료] : {}", JobDateUtil.getDateTime());
return 0;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.twokimss.filemng.database.mapper.FileMngMapper">
<select id="selNewGrpSeq" parameterType="map" resultType="map">
SELECT NVL(MAX(GRP_SEQ), 0) + 1 AS NEW_GRP_SEQ
FROM TBL_FILE_MNG
</select>
<!-- 저장 -->
<insert id="insFileMng" parameterType="map">
<selectKey resultType="map" keyProperty="NEW_SEQ" order="BEFORE">
SELECT TO_NUMBER(NVL(MAX(X.SEQ), 0)) + 1 AS NEW_SEQ
FROM TBL_FILE_MNG X
WHERE X.GRP_SEQ = #{NEW_GRP_SEQ}
</selectKey>
INSERT INTO TBL_FILE_MNG(
GRP_SEQ /*파일그룹번호*/
, SEQ /*파일번호*/
, PATH /*파일경로(파일명을 제외한 PATH)*/
, FULL_PATH /*파일경로(파일명 포함한 PATH)*/
, FILE_NAME /*서버에 저장된 파일이름*/
, ORIGINAL_NAME /*파일원래이름*/
, ORIGINAL_EXTENSION /*파일원래 확장자*/
, FILE_SIZE /*파일사이즈*/
, REF_TABLE /*관련 업무테이블 ID >> 업무테이블에는 FILE_GR_NO(파일 다건 저장시는 이컬럼만 관리), FILE_NO(파일 단건 저장시 이 컬럼까지 관리)*/
, REF_TABLE_KEY /*관련 업무테이블의 KEY (||)JOIN 으로 입력*/
, DEL_YN /*삭제여부*/
, REG_DT /*등록일*/
, REG_ID /*등록자*/
, MOD_DT /*수정일*/
, MOD_ID /*수정자*/
)VALUES(
#{NEW_GRP_SEQ} /*파일그룹번호*/
, #{NEW_SEQ} /*파일번호*/
, #{PATH} /*파일경로(파일명을 제외한 PATH)*/
, #{FULL_PATH} /*파일경로(파일명 포함한 PATH)*/
, #{FILE_NAME} /*서버에 저장된 파일이름*/
, #{ORIGINAL_NAME} /*파일원래이름*/
, #{ORIGINAL_EXTENSION} /*파일원래 확장자*/
, #{FILE_SIZE} /*파일사이즈*/
, #{REF_TABLE} /*관련 업무테이블 ID >> 업무테이블에는 FILE_GR_NO(파일 다건 저장시는 이컬럼만 관리), FILE_NO(파일 단건 저장시 이 컬럼까지 관리)*/
, #{REF_TABLE_KEY} /*관련 업무테이블의 KEY (||)JOIN 으로 입력*/
, #{DEL_YN} /*삭제여부*/
, TO_CHAR(SYSDATE, 'YYYYMMDD') /*등록일*/
, #{USER_ID} /*등록자*/
, TO_CHAR(SYSDATE, 'YYYYMMDD') /*수정일*/
, #{USER_ID} /*수정자*/
)
</insert>
<select id="selFileInfo" parameterType="map" resultType="map">
SELECT 'N' AS CHK
, GRP_SEQ AS GRP_SEQ /*파일그룹번호*/
, SEQ AS SEQ /*파일번호*/
, PATH AS PATH /*파일경로(파일명을 제외한 PATH)*/
, FULL_PATH AS FULL_PATH /*파일경로(파일명 포함한 PATH)*/
, FILE_NAME AS FILE_NAME /*서버에 저장된 파일이름*/
, ORIGINAL_NAME AS ORIGINAL_NAME /*파일원래이름*/
, ORIGINAL_EXTENSION AS ORIGINAL_EXTENSION /*파일원래 확장자*/
, FILE_SIZE AS FILE_SIZE /*파일사이즈*/
, REF_TABLE AS REF_TABLE /*관련 업무테이블 ID >> 업무테이블에는 FILE_GR_NO(파일 다건 저장시는 이컬럼만 관리), FILE_NO(파일 단건 저장시 이 컬럼까지 관리)*/
, REF_TABLE_KEY AS REF_TABLE_KEY /*관련 업무테이블의 KEY (||)JOIN 으로 입력*/
, DEL_YN AS DEL_YN /*삭제여부*/
FROM TBL_FILE_MNG
WHERE 1=1
<if test="GRP_SEQ != null and GRP_SEQ != '' ">
AND GRP_SEQ = #{GRP_SEQ}
</if>
ORDER BY GRP_SEQ, SEQ
</select>
</mapper>
package com.twokimss.web.filemng.service.impl;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.session.SqlSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service("fileServiceImpl")
public class FileServiceImpl {
private static final Logger logger = LoggerFactory.getLogger(ClassName.class);
@Autowired
@Qualifier("sqlSessionOracle")
private SqlSession sqlSessionOracle;
private final static String baseDomain = "com.twokimss.filemng.database.mapper.";
//파일정보저장 - 신규
@Transactional(value="transactionManagerOracle", propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
@SuppressWarnings({ "unchecked", "rawtypes" })
public Map saveFileInfo(Map inListInfo) throws Exception {
List<Map> listSave = (List<Map>)inListInfo.get("ds_fileInfo");
logger.debug("saveFileInfo>>listSave>>{}", listSave);
String sUserId = "adminTEST";
String querySel = baseDomain + "FileMngMapper.selNewGrpSeq";
String queryIns = baseDomain + "FileMngMapper.insFileMng";
logger.debug("querySel>>"+querySel);
logger.debug("queryIns>>"+queryIns);
Map mapNewGrpSeq = new HashMap<String,Object>();
for(int i=0;i<listSave.size();i++) {
Map mapRow = listSave.get(i);
logger.debug("saveFileInfo>>{}", mapRow);
if(i == 0) {
Object oResult = sqlSessionOracle.selectOne(querySel, mapRow);
mapNewGrpSeq = (Map)oResult;
}
mapRow.put("USER_ID", sUserId);
mapRow.put("NEW_GRP_SEQ", mapNewGrpSeq.get("NEW_GRP_SEQ"));
sqlSessionOracle.insert(queryIns, mapRow);
}
Map mapReturn = new HashMap<String, Object>();
mapReturn.put("GRP_SEQ", mapNewGrpSeq.get("NEW_GRP_SEQ"));
return mapReturn;
}
@SuppressWarnings("rawtypes")
public List selFileList(Map map) throws Exception {
String queryId = baseDomain + "FileMngMapper.selFileInfo";
List<Map> list = sqlSessionOracle.selectList(queryId, map);
logger.debug("selFileList >> list cnt >>" + list.size());
return list;
}
}
package com.twokimss.web.batch.service;
import java.io.Serializable;
public class JobConst implements Cloneable, Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
public static final String BEAN_TYPE_WITH_PACKAGE = "1";
public static final String BEAN_TYPE_ONLY_CLASS = "2";
public static final String DELAY_TYPE_DAY = "Day";
public static final String DELAY_TYPE_HH = "HH";
public static final String DELAY_TYPE_MI = "Mi";
}
package com.twokimss.web.batch.service;
import java.util.HashMap;
import org.apache.ibatis.javassist.bytecode.stackmap.TypeData.ClassName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component("jobBeforeProc")
public class JobBeforeProc {
private Logger logger = LoggerFactory.getLogger(ClassName.class);
public HashMap<String, Object> getClassNm(String jobKey, String beanType) {
HashMap<String, Object> mapRtn = new HashMap<String,Object>();
if(JobConst.BEAN_TYPE_WITH_PACKAGE.equals(beanType)) {
mapRtn = this.getBizClassNmWithPackage(jobKey);
}else if(JobConst.BEAN_TYPE_ONLY_CLASS.equals(beanType)) {
mapRtn = this.getBizClassNmOnlyClass(jobKey);
}
mapRtn.put("beanType", beanType);
return mapRtn;
}
//db/xml ( sm 하기 편한 방법 찾아서 변경 필요 ) : 운영하다가 사용여부 변경하고, 정지시킬수 있도록 처리 필요.
private HashMap<String, Object> getBizClassNmWithPackage(String jobKey) {
HashMap<String,Object> mapRtn = new HashMap<String, Object>();
mapRtn.put("classNm", "");
mapRtn.put("rtnCd", "-1");
mapRtn.put("rtnMsg", "");
String sPackage = "com.twokimss.web.batch.service.";
switch (jobKey) {
case "job00401":
mapRtn.put("classNm", sPackage+"JobBiz00401");
mapRtn.put("rtnCd", "0");
mapRtn.put("rtnMsg", "가능");
break;
case "job00402":
mapRtn.put("classNm", sPackage+"JobBiz00402");
mapRtn.put("rtnCd", "0");
mapRtn.put("rtnMsg", "가능");
break;
default:
break;
}
return mapRtn;
}
private HashMap<String, Object> getBizClassNmOnlyClass(String jobKey) {
HashMap<String,Object> mapRtn = new HashMap<String, Object>();
mapRtn.put("classNm", "");
mapRtn.put("rtnCd", "-1");
mapRtn.put("rtnMsg", "");
switch (jobKey) {
case "job00401":
mapRtn.put("classNm", "jobBiz00401");
mapRtn.put("rtnCd", "0");
mapRtn.put("rtnMsg", "가능");
break;
case "job00402":
mapRtn.put("classNm", "jobBiz00402");
//mapRtn.put("rtnCd", "-1"); //실행중지된 작업
mapRtn.put("rtnCd", "0");
mapRtn.put("rtnMsg", "가능");
break;
default:
break;
}
return mapRtn;
}
}
package com.twokimss.web.batch.service;
import org.apache.ibatis.javassist.bytecode.stackmap.TypeData.ClassName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
@Service("jobBiz00402")
public class JobBiz00402 {
private Logger logger = LoggerFactory.getLogger(ClassName.class);
public void execute() {
//Biz 로직 구현
logger.info("[00402===>실행 시작] : {}", JobDateUtil.getDateTime());
try {
Thread.sleep(1000 * 2); //2초 대기
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.info("[00402===>실행 종료] : {}", JobDateUtil.getDateTime());
}
}
package com.twokimss.web.login.controller;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.ibatis.javassist.bytecode.stackmap.TypeData.ClassName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import com.twokimss.web.batch.service.JobDateUtil;
import com.twokimss.web.batch.service.ScheduleExec;
@Controller
public class MyAjaxController {
private Logger logger = LoggerFactory.getLogger(ClassName.class);
@Autowired
private ScheduleExec scheduleExec;
@RequestMapping(value="/simpleTest.do")
@ResponseBody
public void simpleTest(HttpServletRequest req) {
trace("[simpleTest]=====================start");
//http://localhost:9080/simpleTest.do?targetH=12&targetM=0&targetS=0
//http://localhost:9080/simpleTest.do?targetH=03&targetM=0&targetS=0
Object objH = req.getParameter("targetH");
Object objM = req.getParameter("targetM");
Object objS = req.getParameter("targetS");
if(!ObjectUtils.isEmpty(objH)
&& !ObjectUtils.isEmpty(objM)
&& !ObjectUtils.isEmpty(objS)) {
String sH = objH.toString();
String sM = objM.toString();
String sS = objS.toString();
logger.debug("sH===============>{}", sH);
logger.debug("sM===============>{}", sM);
logger.debug("sS===============>{}", sS);
//long delay3 = JobDateUtil.getInitialDelay2(10, 54, 0);
long delay3 = JobDateUtil.getInitialDelay(Integer.parseInt(sH), Integer.parseInt(sM), Integer.parseInt(sS));
logger.debug("delay3===========>{}", delay3);
}
// long delay =JobDateUtil.getInitialDelay(6);
// logger.debug("delay===========>"+delay);
//
// long delay2 =JobDateUtil.getInitialDelay(20);
// logger.debug("delay2===========>"+delay2);
//
// //date
// LocalDate localDate = JobDateUtil.getNowDate();
// logger.debug("localDate===========>{}", localDate);
//
// String sLocalDate = JobDateUtil.formatDate(localDate);
// logger.debug("sLocalDate===========>{}", sLocalDate);
//
// String sLocalDate2 = JobDateUtil.formatDate2(localDate);
// logger.debug("sLocalDate2===========>{}", sLocalDate2);
//
// //plus
// LocalDate nextDate = localDate.plusDays(1);
// logger.debug("nextDate===========>{}", nextDate);
//
//
// //현재시간
// LocalDateTime ldtNow = JobDateUtil.getNowTime();
// logger.debug("ldtNow===========>{}", ldtNow);
//
// String sLdtNow = JobDateUtil.formatDateTime2(ldtNow);
// logger.debug("sLdtNow===========>{}", sLdtNow);
//
// LocalDateTime nextTime = ldtNow.plusHours(1);
// logger.debug("nextTime===========>{}", nextTime);
//
// //오늘 + 특정시간
// //String sDateTime = sLocalDate + "063000";
// String sToday = JobDateUtil.getToday();
// logger.debug("sToday===========>{}", sToday);
//
// String sDateTime = JobDateUtil.getToday() + "063000";
// LocalDateTime ldt = JobDateUtil.parseDateTime(sDateTime);
// logger.debug("ldt===========>{}", ldt);
//
// String sLdt = JobDateUtil.formatDateTime(ldt);
// logger.debug("sLdt===========>{}", sLdt);
//
// String sLdt2 = JobDateUtil.formatDateTime2(ldt);
// logger.debug("sLdt2===========>{}", sLdt2);
}
@RequestMapping(value="/pauseDeleteJob.do")
@ResponseBody
public void pauseDeleteJob(HttpServletRequest req) {
trace("[pauseDeleteJob]=====================start");
//http://localhost:9080/pauseDeleteJob.do?jobKey=job00401
//http://localhost:9080/pauseDeleteJob.do?jobKey=job00402
Object obj = req.getParameter("jobKey");
if(!ObjectUtils.isEmpty(obj)) {
String jobKey = obj.toString();
logger.debug("jobKey===============>{}", jobKey);
scheduleExec.pauseDeleteJob(jobKey);
}
}
@RequestMapping(value="/rescheduleJob.do")
@ResponseBody
public void rescheduleJob(HttpServletRequest req) {
trace("[rescheduleJob]=====================start");
//http://localhost:9080/rescheduleJob.do?jobKey=job00401
//http://localhost:9080/rescheduleJob.do?jobKey=job00402
Object obj = req.getParameter("jobKey");
if(!ObjectUtils.isEmpty(obj)) {
String jobKey = obj.toString();
logger.debug("jobKey===============>{}", jobKey);
scheduleExec.rescheduleJob(jobKey);
}
}
@RequestMapping(value="/shutdownScheduler.do")
@ResponseBody
public void shutdownScheduler(HttpServletRequest req) {
trace("[shutdownScheduler]=====================start");
//http://localhost:9080/shutdownScheduler.do?isNow=true
//http://localhost:9080/shutdownScheduler.do?isNow=false
Object obj = req.getParameter("isNow");
if(!ObjectUtils.isEmpty(obj)) {
boolean isNow = Boolean.parseBoolean(obj.toString());
logger.debug("isNow===============>{}", isNow);
scheduleExec.shutdownScheduler(isNow);
}else {
scheduleExec.shutdownScheduler(true);
}
}
@RequestMapping(value="/changeCron.do")
@ResponseBody
public void changeCron() {
trace("[changeCron]=====================start");
//http://localhost:9080/changeCron.do
// try {
// Thread.sleep(10000);
// //schedulerFutureService.changeCron("*/5 * * * * *");//5초 주기로 변경
// //schedulerFuture2Service.reScheduleJob(1000*5);//5초 주기로 변경
// Thread.sleep(20000);
//
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
}
// 요청 매핑 어트리뷰트
@RequestMapping(value = "/hello.do")
@ResponseBody
public String helloworld(Model model) {
ExecutorService execTP = Executors.newCachedThreadPool();
// 오래걸리는업무 (스레드)
execTP.submit(() -> {
trace("[오래걸리는업무]=====================start");
try {
Thread.sleep(5000); //5초
} catch (InterruptedException e) {
e.printStackTrace();
}
trace("[오래걸리는업무]=======================end");
});
// 작업2
trace("[간단업무]=====================start");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
trace("[간단업무]=====================end");
execTP.shutdown();
// HashMap<String,Object> mapResult = new HashMap<String, Object>();
// mapResult.put("RTN_CODE", "0");
// mapResult.put("RTN_MSG", "성공적으로 처리되었습니다.");
// 결과는 hello world
return "hello world react call"; //Json return
}
// 요청 매핑 어트리뷰트
@RequestMapping(value = "/helloJson.do")
@ResponseBody
public ModelAndView helloJson(Model model) {
trace("[helloJson.do]=====================start");
ModelAndView mv = new ModelAndView("/helloJson");
ExecutorService execTP = Executors.newCachedThreadPool();
// 오래걸리는업무 (스레드)
execTP.submit(() -> {
trace("[오래걸리는업무]=====================start");
try {
Thread.sleep(5000); //5초
} catch (InterruptedException e) {
e.printStackTrace();
}
trace("[오래걸리는업무]=======================end");
});
// 작업2
trace("[간단업무]=====================start");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
trace("[간단업무]=====================end");
execTP.shutdown();
HashMap<String,Object> mapResult = new HashMap<String, Object>();
mapResult.put("RTN_CODE", "0");
mapResult.put("RTN_MSG", "성공적으로 처리되었습니다.");
logger.debug("mapResult========={}", mapResult);
mv.addObject("mapResult", mapResult);
mv.addObject("msg", "테스트입니다");
// 결과는 hello world
//return "hello world react call"; //Json return
return mv;
}
// 출력을 어떤 스레드에서 하고 있는지 확인
private static void trace(String strLog) {
System.out.println(Thread.currentThread().getName() + ">>>>" + strLog);
}
}
package com.twokimss.web.batch.service;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import org.apache.ibatis.javassist.bytecode.stackmap.TypeData.ClassName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class JobDateUtil {
private static Logger logger = LoggerFactory.getLogger(ClassName.class);
public static final DateTimeFormatter ymd = DateTimeFormatter.ofPattern("yyyyMMdd");
public static final DateTimeFormatter ymdHms = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
public static final DateTimeFormatter ymd2 = DateTimeFormatter.ofPattern("yyyy.MM.dd");
public static final DateTimeFormatter ymdHms2 = DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss");
public static long getInitialDelay(int targetH, int targetM, int targetS) {
long initialDelay = 0;
LocalDate nowDate = LocalDate.now();
LocalDateTime nowDateTime = LocalDateTime.now();
int nowY = nowDate.getYear();
int nowM = nowDate.getMonthValue();
int nowD = nowDate.getDayOfMonth();
System.out.println("nowY==========>"+nowY);
System.out.println("nowM==========>"+nowM);
System.out.println("nowD==========>"+nowD);
LocalDateTime compareDateTime = LocalDateTime.of(nowY, nowM, nowD, targetH, targetM, targetS);
LocalDateTime targetDateTime = null;
if(nowDateTime.isBefore(compareDateTime)) {
System.out.println("현재시간은 목표시간보다 이전");
targetDateTime = compareDateTime;
}else {
System.out.println("현재시간은 목표시간보다 이후");
targetDateTime = compareDateTime.plusDays(1);
}
logger.debug("targetDateTime=========================>{}", targetDateTime);
initialDelay = ChronoUnit.MILLIS.between(nowDateTime, targetDateTime);
//initialDelay = ChronoUnit.SECONDS.between(nowDateTime, targetDateTime);
//initialDelay = ChronoUnit.MINUTES.between(nowDateTime, targetDateTime);
logger.debug("initialDelay===============>[{}]", initialDelay);
return initialDelay;
}
public static long getDelay(long aNum, String type) {
long delay = 0;
switch (type) {
case JobConst.DELAY_TYPE_DAY:
delay = aNum * 24 * 60 * 60 * 1000;
break;
case JobConst.DELAY_TYPE_HH:
delay = aNum * 60 * 60 * 1000;
break;
case JobConst.DELAY_TYPE_MI:
delay = aNum * 60 * 1000;
break;
default:
break;
}
return delay;
}
public static String getDateTime() {
// SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
// Date nowDate = new Date();
// String strDate = sdf.format(nowDate);
return formatDateTime2(getNowTime());
}
public static String getToday() {
return formatDate(getNowDate());
}
/**
* date
* @param type
* @return
*/
public static LocalDate getNowDate() {
return LocalDate.now(ZoneId.of("Asia/Seoul"));
}
public static String formatDate(LocalDate date) {
return ymd.format(date);
}
public static String formatDate2(LocalDate date) {
return ymd2.format(date);
}
public static LocalDate parseDate(String strYmd) {
return LocalDate.parse(strYmd, ymd);
}
/**
* date time
* @param type
* @return
*/
public static LocalDateTime getNowTime() {
return LocalDateTime.now(ZoneId.of("Asia/Seoul"));
}
public static String formatDateTime(LocalDateTime datetime) {
return ymdHms.format(datetime);
}
public static String formatDateTime2(LocalDateTime datetime) {
return ymdHms2.format(datetime);
}
public static LocalDateTime parseDateTime(String strYmdHms) {
return LocalDateTime.parse(strYmdHms, ymdHms);
}
}