Bom Master 동기화 배치 작업

This commit is contained in:
rjy1537 2024-11-08 16:54:01 +09:00
parent 137d46d06e
commit 299bc998e3
6 changed files with 216 additions and 1 deletions

View File

@ -148,4 +148,34 @@ public class JobLauncherController {
return "OK"; return "OK";
} }
/**
* BOM 아이템 동기화 배치
*
* @return
* @throws JobInstanceAlreadyCompleteException
* @throws JobExecutionAlreadyRunningException
* @throws JobParametersInvalidException
* @throws JobRestartException
*/
@Scheduled(cron = "0 0 0 * * *")
public String bomJob()
throws JobInstanceAlreadyCompleteException,
JobExecutionAlreadyRunningException,
JobParametersInvalidException,
JobRestartException {
String jobName = "bomJob";
Job job = jobs.get(jobName);
if (job == null) {
return "Job " + jobName + " not found";
}
JobParameters jobParameters =
new JobParametersBuilder().addDate("time", new Date()).toJobParameters();
jobLauncher.run(job, jobParameters);
return "OK";
}
} }

View File

@ -0,0 +1,81 @@
package com.interplug.qcast.batch.master;
import com.fasterxml.jackson.core.type.TypeReference;
import com.interplug.qcast.biz.displayItem.DisplayItemService;
import com.interplug.qcast.biz.displayItem.dto.BomSyncResponse;
import com.interplug.qcast.util.InterfaceQsp;
import java.util.Collections;
import java.util.List;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.transaction.PlatformTransactionManager;
/** chunk 방식의 Job을 생성하는 Configuration */
@Configuration
public class BomConfiguration implements JobExecutionListener {
private final DisplayItemService displayItemService;
private final InterfaceQsp interfaceQsp;
List<BomSyncResponse> bomSyncList;
@Value("${qsp.master-bom-batch-url}")
private String qspInterfaceUrl;
public BomConfiguration(DisplayItemService displayItemService, InterfaceQsp interfaceQsp) {
this.displayItemService = displayItemService;
this.interfaceQsp = interfaceQsp;
}
@Bean
public Job bomJob(JobRepository jobRepository, Step bomStep) {
return new JobBuilder("bomJob", jobRepository).start(bomStep).build();
}
@Bean
public Step bomStep(JobRepository jobRepository, PlatformTransactionManager transactionManager)
throws Exception {
return new StepBuilder("bomStep", jobRepository)
.<BomSyncResponse, BomSyncResponse>chunk(100, transactionManager)
.reader(bomReader())
.processor(bomProcessor())
.writer(bomWriter())
.build();
}
@Bean
@StepScope
public ItemReader<BomSyncResponse> bomReader() throws Exception {
this.bomSyncList =
interfaceQsp.callApiData(
HttpMethod.GET, qspInterfaceUrl, null, new TypeReference<List<BomSyncResponse>>() {});
return (bomSyncList != null)
? new ListItemReader<>(bomSyncList)
: new ListItemReader<>(Collections.emptyList());
}
@Bean
public ItemProcessor<BomSyncResponse, BomSyncResponse> bomProcessor() {
return item -> item;
}
@Bean
public ItemWriter<BomSyncResponse> bomWriter() {
return items -> {
displayItemService.setBomSyncSave((List<BomSyncResponse>) items.getItems());
};
}
}

View File

@ -1,5 +1,6 @@
package com.interplug.qcast.biz.displayItem; package com.interplug.qcast.biz.displayItem;
import com.interplug.qcast.biz.displayItem.dto.BomSyncResponse;
import com.interplug.qcast.biz.displayItem.dto.DisplayItemRequest; import com.interplug.qcast.biz.displayItem.dto.DisplayItemRequest;
import com.interplug.qcast.biz.displayItem.dto.ItemResponse; import com.interplug.qcast.biz.displayItem.dto.ItemResponse;
import com.interplug.qcast.biz.displayItem.dto.ItemSyncResponse; import com.interplug.qcast.biz.displayItem.dto.ItemSyncResponse;
@ -24,4 +25,22 @@ public interface DisplayItemMapper {
* @throws Exception * @throws Exception
*/ */
int setItemSyncSave(ItemSyncResponse itemInfoSync); int setItemSyncSave(ItemSyncResponse itemInfoSync);
/**
* BOM 아이템 정보 삭제
*
* @param bomInfoSync 아이템 정보
* @return
* @throws Exception
*/
int deleteBomSync(BomSyncResponse bomInfoSync);
/**
* BOM 아이템 정보 동기화
*
* @param bomInfoSync 아이템 정보
* @return
* @throws Exception
*/
int setBomSyncSave(BomSyncResponse bomInfoSync);
} }

View File

@ -1,5 +1,6 @@
package com.interplug.qcast.biz.displayItem; package com.interplug.qcast.biz.displayItem;
import com.interplug.qcast.biz.displayItem.dto.BomSyncResponse;
import com.interplug.qcast.biz.displayItem.dto.DisplayItemRequest; import com.interplug.qcast.biz.displayItem.dto.DisplayItemRequest;
import com.interplug.qcast.biz.displayItem.dto.ItemResponse; import com.interplug.qcast.biz.displayItem.dto.ItemResponse;
import com.interplug.qcast.biz.displayItem.dto.ItemSyncResponse; import com.interplug.qcast.biz.displayItem.dto.ItemSyncResponse;
@ -82,7 +83,28 @@ public class DisplayItemService {
public int setItemSyncSave(List<ItemSyncResponse> itemSyncList) throws Exception { public int setItemSyncSave(List<ItemSyncResponse> itemSyncList) throws Exception {
int cnt = 0; int cnt = 0;
for (ItemSyncResponse itemSyncData : itemSyncList) { for (ItemSyncResponse itemSyncData : itemSyncList) {
displayItemMapper.setItemSyncSave(itemSyncData); cnt += displayItemMapper.setItemSyncSave(itemSyncData);
}
return cnt;
}
/**
* 아이템 정보 동기화
*
* @param bomSyncList 아이템 목록
* @return
* @throws Exception
*/
public int setBomSyncSave(List<BomSyncResponse> bomSyncList) throws Exception {
int cnt = 0;
for (BomSyncResponse bomSyncData : bomSyncList) {
if ("D".equals(bomSyncData.getStatCd())) {
// Bom 아이템 삭제 처리
cnt += displayItemMapper.deleteBomSync(bomSyncData);
} else {
// Bom 아이템 수정/등록 처리
cnt += displayItemMapper.setBomSyncSave(bomSyncData);
}
} }
return cnt; return cnt;
} }

View File

@ -0,0 +1,25 @@
package com.interplug.qcast.biz.displayItem.dto;
import com.interplug.qcast.util.DefaultResponse;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/** Bom 아이템 동기화 Response */
@Data
public class BomSyncResponse extends DefaultResponse {
@Schema(description = "Material Number")
String packageItemId;
@Schema(description = "Bom Code")
String itemId;
@Schema(description = "Amount")
String amount;
@Schema(description = "Manual Flag")
String manualFlg;
@Schema(description = "Status Code(A, D)")
String statCd;
}

View File

@ -240,4 +240,42 @@
, GETDATE() , GETDATE()
); );
</insert> </insert>
<delete id="deleteBomSync" parameterType="com.interplug.qcast.biz.displayItem.dto.BomSyncResponse" >
DELETE FROM M_PACKAGE_ITEM
WHERE
PACKAGE_ITEM_ID = #{packageItemId}
AND ITEM_ID = #{itemId}
</delete>
<insert id="setBomSyncSave" parameterType="com.interplug.qcast.biz.displayItem.dto.BomSyncResponse" >
/* sqlid : com.interplug.qcast.displayItem.setBomSyncSave */
MERGE M_PACKAGE_ITEM AS A
USING
( SELECT #{itemId} AS ITEM_ID
, #{packageItemId} AS PACKAGE_ITEM_ID
) AS D
ON (
A.PACKAGE_ITEM_ID = D.PACKAGE_ITEM_ID
AND A.ITEM_ID = D.ITEM_ID
)
WHEN MATCHED THEN
UPDATE SET
AMOUNT = #{amount}
, LAST_EDIT_DATETIME = GETDATE()
WHEN NOT MATCHED THEN
INSERT (
PACKAGE_ITEM_ID
, ITEM_ID
, AMOUNT
, MANUAL_FLG
, LAST_EDIT_DATETIME
) VALUES (
#{packageItemId}
, #{itemId}
, #{amount}
, CASE WHEN #{manualFlg} = 'FALSE' THEN 0 ELSE 1 END
, GETDATE()
);
</insert>
</mapper> </mapper>