feat : 신고 답변 생성 완료. todo: test

master
Kurt92 6 months ago
parent f91b1c021e
commit ef17b3bbf9

@ -5,6 +5,6 @@ import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface CpAnswerRepository extends JpaRepository<CpAnswer,Integer> {
public interface CpAnswerRepository extends JpaRepository<CpAnswer,String> {
List<CpAnswer> findAllByAsState(String number);
}

@ -5,7 +5,7 @@ import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface CpMainRepository extends JpaRepository<CpMain,Integer> {
public interface CpMainRepository extends JpaRepository<CpMain,String> {
CpMain findTopByMmCodeStartingWithOrderByMmCodeDesc(String prefix);
}

@ -1,7 +0,0 @@
package com.worker.domain.repo.ep;
import com.worker.domain.entity.CpCancel;
import org.springframework.data.jpa.repository.JpaRepository;
public interface EpAnserRepository extends JpaRepository<CpCancel, Integer> {
}

@ -5,6 +5,6 @@ import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface EpAnswerRepository extends JpaRepository<CpAnswer,Integer> {
public interface EpAnswerRepository extends JpaRepository<CpAnswer,String> {
List<CpAnswer> findAllByAsState(String number);
}

@ -5,7 +5,7 @@ import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface EpMainRepository extends JpaRepository<CpMain,Integer> {
public interface EpMainRepository extends JpaRepository<CpMain,String> {
CpMain findTopByMmCodeStartingWithOrderByMmCodeDesc(String prefix);
}

@ -132,10 +132,10 @@ public class SinmungoDto {
}
@Data
@Builder
@NoArgsConstructor
public static class SendTarget {
private Integer mmCode;
private String mmCode;
private String asSysGubunC;
private String asState;
private String asPetiAncCodeV;
@ -147,6 +147,7 @@ public class SinmungoDto {
private String umTelno;
private String umEmail;
private String sgDepCode;
private String sgSggName;
private String ccDate;
private String civil_gist_v; //위반 종류

@ -17,3 +17,4 @@
// return new JPAQueryFactory(em);
// }
//}
// 멀티 db 환경으로 conf 수정 수정

@ -20,7 +20,7 @@ import static com.worker.domain.entity.QCpUser.cpUser;
@RequiredArgsConstructor
public class XmlSendQueryDslRepository {
public List<SinmungoDto.Send.SendTarget> findAllByAsState(JPAQueryFactory queryFactory, String state) {
public List<SinmungoDto.Send.SendTarget> findAllTargetAnswer(JPAQueryFactory queryFactory, String state) {
return queryFactory
.select(
@ -38,6 +38,7 @@ public class XmlSendQueryDslRepository {
cpUser.umTelno,
cpUser.umEmail,
cpSgg.sgDepCode,
cpSgg.sgSggName,
cpCancel.ccDate
)
)

@ -36,48 +36,55 @@ public class SinmungoInOutScheduler {
// esb에이전트 xml파일 읽기
@Scheduled(fixedRate = 10 * 60 * 1000) // 10분
public void sinmungoInOutScheduler() throws IOException {
//setinfo 테이블에서 esb에이전트 정보 조회
SinmungoDto.SetInfo setInfo = dbPolling.findSetInfo();
//파일읽기
XmlParserInterface<SinmungoDto.SinmungoXml> parser = new SinmungoXmlParser();
List<SinmungoDto.SinmungoXml> parseResult = xmlReader.readXmlFiles(setInfo.getCpSetinfo().getStrValue2(), parser);
// cpMain만 추출
// cp와 ep 디비가 따로있다고함.
// db폴링
// save cp
List<SinmungoDto.SinmungoXml> cpList = parseResult.stream()
.filter(item -> {
try {
int deptCode = Integer.parseInt(item.getPcd_dept_v());
return new ObjectMapper()
.readValue(setInfo.getCpSetinfo().getStrValue6(), new TypeReference<Map<String, List<Integer>>>() {})
.values().stream()
.map(list -> list.get(1))
.anyMatch(v -> v == deptCode);
} catch (Exception e) {
return false;
}
})
.collect(Collectors.toList());
dbPolling.saveCP(cpList, setInfo);
// save ep
List<SinmungoDto.SinmungoXml> epList = parseResult.stream()
.filter(item -> {
try {
int deptCode = Integer.parseInt(item.getPcd_dept_v());
return new ObjectMapper()
.readValue(setInfo.getEpSetinfo().getStrValue6(), new TypeReference<Map<String, List<Integer>>>() {})
.values().stream()
.map(list -> list.get(1))
.anyMatch(v -> v == deptCode);
} catch (Exception e) {
return false;
}
})
.collect(Collectors.toList());
dbPolling.saveEP(epList, setInfo);
try{
//setinfo 테이블에서 esb에이전트 정보 조회
SinmungoDto.SetInfo setInfo = dbPolling.findSetInfo();
//파일읽기
XmlParserInterface<SinmungoDto.SinmungoXml> parser = new SinmungoXmlParser();
List<SinmungoDto.SinmungoXml> parseResult = xmlReader.readXmlFiles(setInfo.getCpSetinfo().getStrValue2(), parser);
// cpMain만 추출
// cp와 ep 디비가 따로있다고함.
//deptCode로 cp/ep 대상 분리
// save cp
List<SinmungoDto.SinmungoXml> cpList = parseResult.stream()
.filter(item -> {
try {
int deptCode = Integer.parseInt(item.getPcd_dept_v());
return new ObjectMapper()
.readValue(setInfo.getCpSetinfo().getStrValue6(), new TypeReference<Map<String, List<Integer>>>() {})
.values().stream()
.map(list -> list.get(1))
.anyMatch(v -> v == deptCode);
} catch (Exception e) {
return false;
}
})
.collect(Collectors.toList());
dbPolling.saveCP(cpList, setInfo);
// save ep
List<SinmungoDto.SinmungoXml> epList = parseResult.stream()
.filter(item -> {
try {
int deptCode = Integer.parseInt(item.getPcd_dept_v());
return new ObjectMapper()
.readValue(setInfo.getEpSetinfo().getStrValue6(), new TypeReference<Map<String, List<Integer>>>() {})
.values().stream()
.map(list -> list.get(1))
.anyMatch(v -> v == deptCode);
} catch (Exception e) {
return false;
}
})
.collect(Collectors.toList());
dbPolling.saveEP(epList, setInfo);
} catch (Exception e) {
log.error("🔥 신고 폴링 스케줄러 오류 발생!", e); // 여기서 예외 로그 전체 출력
}
}
@ -94,13 +101,20 @@ public class SinmungoInOutScheduler {
// esb 에이전트 답변 보내기
@Scheduled(fixedRate = 10 * 60 * 1000) // 10분
public void sinmungoAnswerSendScheduler() {
//setinfo 테이블에서 esb에이전트 정보 조회
SinmungoDto.SetInfo setInfo = dbPolling.findSetInfo();
//대상 답변 조회
SinmungoDto.Send.Answers answers = xmlSend.findAnswersByStatus(StateEnum.ANSWER_STATE_ANSWER_WAIT.getCode());
try {
//setinfo 테이블에서 esb에이전트 정보 조회
SinmungoDto.SetInfo setInfo = dbPolling.findSetInfo();
//대상 답변 조회
SinmungoDto.Send.Answers answers = xmlSend.findAnswersByStatus(StateEnum.ANSWER_STATE_ANSWER_WAIT.getCode());
//send 프로세스 실행
xmlSend.send(setInfo, answers);
//send 프로세스 실행
xmlSend.send(setInfo, answers);
log.info("xml 생성 성공!!!");
} catch (Exception e) {
log.error("🔥 답변실행 스케줄러 오류 발생!", e); // 여기서 예외 로그 전체 출력
}

@ -50,7 +50,6 @@ public class DbPolling {
public SinmungoDto.SetInfo findSetInfo() {
// setInfo는 폴링 작업에 필요한 모든정보를 여기서 전부 조회하고 객체로 리턴
// CpUser cpUser = cpUserRepository.;
CpSetinfo cpSetinfo = cpSetinfoRepository.findById(
CpSetinfoId.builder()
.codeName(env.getProperty("esb.info.cp.codeName"))

@ -17,10 +17,11 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -48,10 +49,9 @@ public class XmlSend {
//todo: 이거 쿼리dsl로 main이랑 같이 조인하자 (메인이랑 답변이랑 mmcode가 pk이고 1대1 관계임)
//todo: xml만들때 main의 상태값에 따라 처리하는 부분 있는데 괜히 조회하지말고 한번 조회할때 같이 가져오자
// 아 병싄이냐, 이거 쿼리한방에 해결되겠구만/ reuser랑 상태값으로 전부 조인해서 조회하면 되잖아;;
return SinmungoDto.Send.Answers.builder()
.cpAnswer(xmlSendQueryDslRepository.findAllByAsState(cpQueryFactory, status))
.epAnswer(xmlSendQueryDslRepository.findAllByAsState(epQueryFactory, status))
.cpAnswer(xmlSendQueryDslRepository.findAllTargetAnswer(cpQueryFactory, status))
.epAnswer(xmlSendQueryDslRepository.findAllTargetAnswer(epQueryFactory, status))
.build();
}
@ -62,16 +62,23 @@ public class XmlSend {
// SinmungoDto.Send.UserInfos userInfos = findUserInfos(answers);
// 두번째 파라미터에 다 있음.
// cp작업
answers.getCpAnswer().forEach(target -> {
try {
xmlMacker.writeEsbAnswerXml(target);
//여기서 바로 만들어
//인터페이스키 생성
String makeInterfaceSeq = new SimpleDateFormat("yyyyMMddHHmmssSS").format(new Date()) +
String.valueOf(ThreadLocalRandom.current().nextInt(0, 100_000_000));
//xml 구조 생성
String xmlNode = xmlMacker.writeEsbAnswerXml(target, setInfo.getCpSetinfo(), makeInterfaceSeq);
// xml 생성
xmlMacker.generateSinmungoXml(xmlNode, makeInterfaceSeq, setInfo.getCpSetinfo());
//그리고 만들어진놈 mmcode로 상태 업데이트해
cpAnswerRepository.findById(target.getMmCode())
.ifPresent(entity -> {
entity.changeState("");
entity.changeState(stateCodeByTarget(target));
entity.changePostDtNow();
cpAnswerRepository.save(entity);
});
@ -81,16 +88,25 @@ public class XmlSend {
}
});
//ep작업
answers.getEpAnswer().forEach(target -> {
try {
xmlMacker.writeEsbAnswerXml(target);
// mmcode로 찾아서 cp_answer state 업데이트
//인터페이스키 생성
String makeInterfaceSeq = new SimpleDateFormat("yyyyMMddHHmmssSS").format(new Date()) +
String.valueOf(ThreadLocalRandom.current().nextInt(0, 100_000_000));
//xml 구조 생성
String xmlNode = xmlMacker.writeEsbAnswerXml(target, setInfo.getCpSetinfo(), makeInterfaceSeq);
// xml 생성
xmlMacker.generateSinmungoXml(xmlNode, makeInterfaceSeq, setInfo.getEpSetinfo());
//그리고 만들어진놈 mmcode로 상태 업데이트해
epAnswerRepository.findById(target.getMmCode())
.ifPresent(entity -> {
entity.changeState(stateCodeByTarget(target));
entity.changePostDtNow();
cpAnswerRepository.save(entity);
epAnswerRepository.save(entity);
});
@ -99,73 +115,13 @@ public class XmlSend {
}
});
//awsers 만큼
// 위에서 조회한 정보들 조합해서 xml 생성
//String 으로 xml 만들고 그거 파라미터로 파일생성하는 매서드로 가져가
// answers.getCpAnswer().forEach(cpAnswer ->
// userInfos.getCpUsers().stream()
// .filter(user -> Objects.equals(user.getUmCode(), cpAnswer.getAsReuser()))
// .findFirst()
// .ifPresent(user -> {
// try {
// xmlMacker.writeEsbAnswerXml(cpAnswer, user);
// } catch (IOException e) {
// throw new RuntimeException(e);
// }
// })
// );
// answers.getEpAnswer().forEach(epAnswer ->
// userInfos.getEpUsers().stream()
// .findFirst()
// .filter(user -> Objects.equals(user.getUmCode(), epAnswer.getAsReuser()))
// .ifPresent(user -> {
// try {
// xmlMacker.writeEsbAnswerXml(epAnswer, user);
// } catch (IOException e) {
// throw new RuntimeException(e);
// }
// })
// );
}
// answers 리스트에서 reuser를 통해 유저정보를 추출한다.
// private SinmungoDto.Send.UserInfos findUserInfos(SinmungoDto.Send.Answers answers) {
//
// return SinmungoDto.Send.UserInfos.builder()
// .cpUsers(
// answers.getCpAnswer().stream()
// .map(user -> cpUserRepository.findById(Long.valueOf(user.getAsReuser())))
// .filter(Optional::isPresent)
// .map(Optional::get)
// .collect(Collectors.collectingAndThen(
// Collectors.toMap(CpUser::getUmCode, Function.identity(), (a, b) -> a),
// m -> new ArrayList<>(m.values())
// ))
// )
// .epUsers(
// answers.getEpAnswer().stream()
// .map(user -> epUserRepository.findById(Long.valueOf(user.getAsReuser())))
// .filter(Optional::isPresent)
// .map(Optional::get)
// .collect(Collectors.collectingAndThen(
// Collectors.toMap(CpUser::getUmCode, Function.identity(), (a, b) -> a),
// m -> new ArrayList<>(m.values())
// ))
// )
// .build();
//
// }
private String stateCodeByTarget(SinmungoDto.Send.SendTarget target) {
//ccDate가 빈값이면 상태값 확인
if(target.getCcDate().isEmpty()) {
if(target.getCcDate() != null && !target.getCcDate().isBlank()) {
//상태값이 83이나 84면
if(target.getMmState().equals(StateEnum.STATE_CD_INSTRCTION.getCode()) ||
target.getMmState().equals(StateEnum.STATE_CD_INSTRCTION_OK.getCode())) {

@ -1,6 +1,7 @@
package com.worker.util.fileMaker;
import com.worker.domain.entity.CpAnswer;
import com.worker.domain.entity.CpSetinfo;
import com.worker.domain.entity.CpUser;
import com.worker.dto.SinmungoDto;
import com.worker.util.common.commEnum.StateEnum;
@ -11,6 +12,11 @@ import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.ThreadLocalRandom;
@Component
@Slf4j
@ -18,49 +24,41 @@ public class XmlMacker {
// 답변처리 xml
public String writeEsbAnswerXml(SinmungoDto.Send.SendTarget target) throws IOException {
public String writeEsbAnswerXml(SinmungoDto.Send.SendTarget target, CpSetinfo setinfo, String makeInterfaceSeq) throws IOException {
String xml =
"<?xml version=\"1.0\" encoding=\"euc-kr\"?>\n" +
"<dmndinfo>\n" +
" <interface_seq_n>" + "랜덤으로 시퀀스 만드는데 랜덤으로 만들어도 됨?????" + "</interface_seq_n>\n" +
" <interface_seq_n>" + makeInterfaceSeq + "</interface_seq_n>\n" +
" <sys_gubun_c>" + target.getAsSysGubunC() + "</sys_gubun_c>\n" +
" <anc_code_v>" + target.getAsState() + "</anc_code_v>\n" +
" <peti_gubun_c>" + "180" + "</peti_gubun_c>\n" +
" <peti_anc_code_v>" + target.getAsPetiAncCodeV() + "</peti_anc_code_v>\n" +
" <peti_no_c>" + target.getAsJsno() + "</peti_no_c>\n" +
" <civil_no_c>" + target.getAsJsnoM() + "</civil_no_c>\n" +
" <civil_gist_v>" + "이거 무슨 위반인지 로직" + "</civil_gist_v>\n" +
" <civil_gist_v>" + setinfo.getStrValue11() + "</civil_gist_v>\n" +
" <civil_abstract_l>" + stateCtgyByTarget(target) + "</civil_abstract_l>\n" +
" <pcd_dept_v>" + "SG_DEPCODE??" + "</pcd_dept_v>\n" +
" <pcd_dept_nm_v>" + "SG_SGGNAME" + "</pcd_dept_nm_v>\n" +
" <pcd_dept_v>" + target.getSgDepCode() + "</pcd_dept_v>\n" +
" <pcd_dept_nm_v>" + target.getSgSggName() + "</pcd_dept_nm_v>\n" +
" <duty_id_v>" + target.getUmName() + "</duty_id_v>\n" +
" <pcd_email_v>" + target.getUmEmail() + "</pcd_email_v>\n" +
" <pcd_tel_v>" + target.getUmTelno() + "</pcd_tel_v>\n" +
" <pcd_rst_cont_l>" + target.getAsText() + "</pcd_rst_cont_l>\n" +
" <do_reg_d>" + "현재시간 yyyymmddhhmmss" + "</do_reg_d>\n" +
" <do_reg_d>" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + "</do_reg_d>\n" +
" <pcd_rst_cont_attach_yn_c>" + "N" + "</pcd_rst_cont_attach_yn_c>\n" +
" <pcd_anc_code_v>" + "SG_DEPCODE??" + "</pcd_anc_code_v>\n" +
" <reg_d>" + "현재시간 yyyymmddhhmmss" + "</reg_d>\n" +
" <pcd_anc_code_v>" + target.getSgDepCode() + "</pcd_anc_code_v>\n" +
" <reg_d>" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + "</reg_d>\n" +
" <send_yn_c>" + "2" + "</send_yn_c>\n" +
" <send_d>" + "현재시간 yyyymmddhhmmss" + "</send_d>\n" +
" <apply_d>" + "현재시간 yyyymmddhhmmss" + "</apply_d>\n" +
" <send_d>" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + "</send_d>\n" +
" <apply_d>" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + "</apply_d>\n" +
" <apply_gubun_c>" + "Y" + "</apply_gubun_c>\n" +
" <pcd_gubun_v>" + "" + "</pcd_gubun_v>\n" +
" <pcd_gubun2_v>" + "" + "</pcd_gubun2_v>\n" +
" <pcd_gubun3_v>" + "" + "</pcd_gubun3_v>\n" +
" <ifid>" + "" + "</ifid>\n" +
" <srcorgcd>" + "상위기간 코드 -> setInfo 에서 가져옴" + "</srcorgcd>\n" +
" <srcorgcd>" + setinfo.getIntValue2().toString() + "</srcorgcd>\n" +
" <tgtorgcd>" + "" + "</tgtorgcd>\n" +
"</dmndinfo>\n";
// String fileName = "EPOUGB$" + xmlDto.interface_seq_n() + ".xml";
// Path filePath = sendDir.resolve(fileName);
//
// // 저장 (EUCKR 인코딩)
// Files.write(filePath, xml.getBytes(Charset.forName("EUC-KR")));
return xml;
}
@ -71,6 +69,32 @@ public class XmlMacker {
// send 디렉토리로 파일저장
public void generateSinmungoXml(String xml, String makeInterfaceSeq, CpSetinfo setInfo) {
try {
String fileName = "EPOUGB$" + makeInterfaceSeq + ".xml";
Path esbPath = Paths.get(setInfo.getStrValue3());
Path tempDirPath = esbPath.resolve("../../SMG_SEND_TEMP").normalize();
Path finalTempFilePath = tempDirPath.resolve(fileName);
Path finalEsbFilePath = esbPath.resolve(fileName);
//수원 용인 예외처리
if ("41110".equals(setInfo.getIntValue1().toString())) {
finalTempFilePath = Paths.get("D:/TEMP/EPOUGB$CG131000000768$", fileName);
finalEsbFilePath = esbPath.resolve(fileName);
}
// 임시 디렉토리에 파일 저장 (EUC-KR 인코딩)
Files.write(finalTempFilePath, xml.getBytes(Charset.forName("EUC-KR")));
// 최종 디렉토리로 이동
Files.move(finalTempFilePath, finalEsbFilePath, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
// 답변 상태의 카테고리를 리턴한다.
@ -78,7 +102,7 @@ public class XmlMacker {
private String stateCtgyByTarget(SinmungoDto.Send.SendTarget target) {
//ccDate가 빈값이면 상태값 확인
if(target.getCcDate().isEmpty()) {
if(target.getCcDate() != null && !target.getCcDate().isBlank()) {
//상태값이 83이나 84면
if(target.getMmState().equals(StateEnum.STATE_CD_INSTRCTION.getCode()) ||
target.getMmState().equals(StateEnum.STATE_CD_INSTRCTION_OK.getCode())) {

@ -0,0 +1,49 @@
server:
port: 8011
spring:
datasource:
# 122번 서버 보면 클린파킹 많은데 cp1이 최신임. cp1기준으로 작업.
cp:
url: jdbc:mariadb://211.119.124.122:53306/demon_test_cp?useUnicode=true&characterEncoding=utf8
username: root
password: xit5811807
driver-class-name: org.mariadb.jdbc.Driver
ep:
url: jdbc:mariadb://211.119.124.122:53306/demon_test_ep?useUnicode=true&characterEncoding=utf8
username: root
password: xit5811807
driver-class-name: org.mariadb.jdbc.Driver
# 이미 운영되고있는 서버들 많고 디비 구성 변경시 영향도 파악 어려움.
# ddl은 무조건 수동으로 해줄것.
# jpa는 순수 개발편의를 위한 사용.
# 연관관계 지정하지말고 그대로 쓸것.
jpa:
show-sql: false
hibernate:
ddl-auto: none
properties:
hibernate:
format_sql: true
dialect: org.hibernate.dialect.MySQLDialect
esb:
info:
cp:
codeName: WORKER
groupCode: INFO
detailCode: DEV
ep:
codeName: WORKER
groupCode: INFO
detailCode: DEV
logging:
level:
root: info
org.springframework.scheduling: info
org.springframework.scheduling.support: info
org.hibernate.SQL: debug
org.hibernate.type: trace
org.springframework.data.redis: info

@ -1,13 +1,13 @@
package com.worker;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class CleanParkingWorkerApplicationTests {
@Test
void contextLoads() {
}
}
//package com.worker;
//
//import org.junit.jupiter.api.Test;
//import org.springframework.boot.test.context.SpringBootTest;
//
//@SpringBootTest
//class CleanParkingWorkerApplicationTests {
//
// @Test
// void contextLoads() {
// }
//
//}

Loading…
Cancel
Save