增加服务端exception与schedule扥类文件
This commit is contained in:
parent
54df592222
commit
6812c00e95
|
|
@ -0,0 +1,12 @@
|
||||||
|
package com.aisino.iles.lawenforcement.exception;
|
||||||
|
|
||||||
|
public class DataSyncException extends RuntimeException {
|
||||||
|
|
||||||
|
public DataSyncException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataSyncException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
package com.aisino.iles.lawenforcement.schedule.config;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当 application 属性schedule.enabled设置为true的时候,开启调度任务
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableScheduling
|
||||||
|
@ConditionalOnProperty(prefix = "scheduler", name = "enabled", havingValue = "true")
|
||||||
|
public class SchedulerConfig {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,520 @@
|
||||||
|
package com.aisino.iles.lawenforcement.schedule.service;
|
||||||
|
|
||||||
|
import com.aisino.iles.common.util.StringUtils;
|
||||||
|
import com.aisino.iles.lawenforcement.model.Agency;
|
||||||
|
import com.aisino.iles.lawenforcement.repository.AgencyRepository;
|
||||||
|
import com.aisino.iles.lawenforcement.service.AuthService;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonAlias;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.smartlx.sso.client.model.AccessToken;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import lombok.ToString;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.http.*;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.web.client.HttpClientErrorException;
|
||||||
|
import org.springframework.web.client.RestClientException;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同步执法机构信息数据
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class AgencyScheduleService {
|
||||||
|
|
||||||
|
private final AgencyRepository agencyRepository;
|
||||||
|
private final RestTemplate restTemplate;
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
private final AuthService authService; // 用于获取和刷新令牌
|
||||||
|
|
||||||
|
@Value("${third-party.agency.query:}")
|
||||||
|
private String agencyUrl;
|
||||||
|
|
||||||
|
@Value("${third-party.enterprise.yddh:}") // 使用正确的配置项获取令牌标识
|
||||||
|
private String agencyTokenMobilePhone;
|
||||||
|
|
||||||
|
public AgencyScheduleService(AgencyRepository agencyRepository, RestTemplate restTemplate, ObjectMapper objectMapper, AuthService authService) {
|
||||||
|
this.agencyRepository = agencyRepository;
|
||||||
|
this.restTemplate = restTemplate;
|
||||||
|
this.objectMapper = objectMapper;
|
||||||
|
this.authService = authService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Scheduled(cron = "${scheduler.task.agency.cron.expression:0 0 1 * * ?}")
|
||||||
|
@Transactional
|
||||||
|
public void scheduleTask() {
|
||||||
|
log.info("开始执行执法机构信息同步任务...");
|
||||||
|
|
||||||
|
if (agencyUrl == null || agencyUrl.isEmpty()) {
|
||||||
|
log.error("执法机构API URL (third-party.agency.query) 未配置.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (agencyTokenMobilePhone == null || agencyTokenMobilePhone.isEmpty()) {
|
||||||
|
log.error("执法机构API令牌IDNO (third-party.enterprise.idno) 未配置.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 单次请求获取所有 dwlb=1 的机构信息
|
||||||
|
Map<String, Object> requestBody = new HashMap<>();
|
||||||
|
requestBody.put("page", 1);
|
||||||
|
requestBody.put("limit", 4000); // 设置较大的限制以获取所有数据,根据实际情况调整
|
||||||
|
Map<String, String> entity = new HashMap<>();
|
||||||
|
entity.put("dwlb", "1"); // 只获取 dwlb=1 的机构
|
||||||
|
requestBody.put("entity", entity);
|
||||||
|
|
||||||
|
log.info("准备从API获取所有 dwlb=1 的机构数据. URL: {}, TokenIDNO: {}", agencyUrl, agencyTokenMobilePhone);
|
||||||
|
|
||||||
|
String responseBody = fetchDataFromApi(requestBody, agencyUrl);
|
||||||
|
|
||||||
|
List<ApiAgency> allApiAgencies = new ArrayList<>();
|
||||||
|
if (responseBody != null) {
|
||||||
|
ApiResponse apiResponse = objectMapper.readValue(responseBody, ApiResponse.class);
|
||||||
|
if (apiResponse != null && apiResponse.isSuccess() && apiResponse.getData() != null) {
|
||||||
|
allApiAgencies.addAll(apiResponse.getData().getList());
|
||||||
|
|
||||||
|
// 检查是否需要分页获取
|
||||||
|
int totalPages = apiResponse.getData().getTotalPage();
|
||||||
|
int currentPage = 1;
|
||||||
|
|
||||||
|
// 如果有多页数据,继续获取剩余页
|
||||||
|
while (currentPage < totalPages) {
|
||||||
|
currentPage++;
|
||||||
|
requestBody.put("page", currentPage);
|
||||||
|
|
||||||
|
log.info("获取第 {} 页机构数据,共 {} 页", currentPage, totalPages);
|
||||||
|
String pageResponseBody = fetchDataFromApi(requestBody, agencyUrl);
|
||||||
|
|
||||||
|
if (pageResponseBody != null) {
|
||||||
|
ApiResponse pageApiResponse = objectMapper.readValue(pageResponseBody, ApiResponse.class);
|
||||||
|
if (pageApiResponse != null && pageApiResponse.isSuccess() && pageApiResponse.getData() != null) {
|
||||||
|
allApiAgencies.addAll(pageApiResponse.getData().getList());
|
||||||
|
} else {
|
||||||
|
log.warn("获取第 {} 页数据失败. Code: {}, Msg: {}",
|
||||||
|
currentPage,
|
||||||
|
pageApiResponse != null ? pageApiResponse.getCode() : "N/A",
|
||||||
|
pageApiResponse != null ? pageApiResponse.getMsg() : "N/A");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("共获取 {} 页数据,总计 {} 条机构记录", totalPages, allApiAgencies.size());
|
||||||
|
} else {
|
||||||
|
log.warn("API响应表明操作未成功或数据为空. Code: {}, Msg: {}",
|
||||||
|
apiResponse != null ? apiResponse.getCode() : "N/A",
|
||||||
|
apiResponse != null ? apiResponse.getMsg() : "N/A");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allApiAgencies.isEmpty()) {
|
||||||
|
log.info("未从API获取到任何执法机构数据。");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 去重,以 gajgjgdm 为准
|
||||||
|
List<ApiAgency> distinctApiAgencies = allApiAgencies.stream()
|
||||||
|
.filter(apiAgency -> apiAgency.getGajgjgdm() != null)
|
||||||
|
.collect(Collectors.toMap(ApiAgency::getGajgjgdm, p -> p, (p, q) -> p))
|
||||||
|
.values()
|
||||||
|
.stream()
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
log.info("从API获取到 {} 条去重后的执法机构数据,准备进行处理...", distinctApiAgencies.size());
|
||||||
|
|
||||||
|
// 筛选出 01610100000000000 及其所有下级机构
|
||||||
|
String rootAgencyCode = "01610100000000000";
|
||||||
|
|
||||||
|
// 构建机构代码到API机构的映射,方便后续处理
|
||||||
|
Map<String, ApiAgency> apiAgencyMap = distinctApiAgencies.stream()
|
||||||
|
.collect(Collectors.toMap(ApiAgency::getGajgjgdm, a -> a, (a1, a2) -> a1));
|
||||||
|
|
||||||
|
// 找出所有属于 01610100000000000 下级的机构(包括自身)
|
||||||
|
Set<String> relevantAgencyCodes = new HashSet<>();
|
||||||
|
relevantAgencyCodes.add(rootAgencyCode); // 添加根机构自身
|
||||||
|
|
||||||
|
// 递归查找所有下级机构
|
||||||
|
findAllChildAgencies(rootAgencyCode, apiAgencyMap, relevantAgencyCodes);
|
||||||
|
|
||||||
|
log.info("筛选出 {} 条与根机构 {} 相关的机构数据", relevantAgencyCodes.size(), rootAgencyCode);
|
||||||
|
|
||||||
|
// 筛选出相关的机构数据
|
||||||
|
List<ApiAgency> relevantApiAgencies = distinctApiAgencies.stream()
|
||||||
|
.filter(agency -> relevantAgencyCodes.contains(agency.getGajgjgdm()))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
Map<String, Agency> processedAgencies = new HashMap<>();
|
||||||
|
List<Agency> agenciesToSave = new ArrayList<>();
|
||||||
|
|
||||||
|
// 先处理所有机构的基本信息,并存入 processedAgencies
|
||||||
|
for (ApiAgency apiAgency : relevantApiAgencies) {
|
||||||
|
if (apiAgency.getGajgmc() == null || apiAgency.getGajgmc().isEmpty()) {
|
||||||
|
log.warn("API返回的机构数据缺少 gajgmc (机构名称),跳过此条记录: {}", apiAgency);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 检查 gajgjgdm 是否为空,因为它仍然是重要的属性
|
||||||
|
if (apiAgency.getGajgjgdm() == null) {
|
||||||
|
log.warn("API返回的机构数据缺少 gajgjgjgdm (机构代码),但仍会尝试按名称处理: {}", apiAgency);
|
||||||
|
// 决定是否跳过,或者允许没有代码的机构(如果业务允许)
|
||||||
|
continue; // 如果 gajgjgdm 必须存在,则取消注释此行
|
||||||
|
}
|
||||||
|
|
||||||
|
Agency agency = agencyRepository.findByAgencyCode(apiAgency.getGajgjgdm()).orElse(new Agency());
|
||||||
|
|
||||||
|
agency.setAgencyName(apiAgency.getGajgmc());
|
||||||
|
agency.setAgencyCode(apiAgency.getGajgjgdm()); // 执法机构代码,即使通过名称找到,也用API的code更新
|
||||||
|
agency.setOrderNum(apiAgency.getXssx()); // 排序号
|
||||||
|
|
||||||
|
// 执法机构简码 - 使用StringUtils.trimEven0
|
||||||
|
agency.setAgencySimpleCode(generateAgencySimpleCode(apiAgency.getGajgjgdm()));
|
||||||
|
agenciesToSave.add(agency);
|
||||||
|
processedAgencies.put(agency.getAgencyCode(), agency);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 再次遍历,设置父级关系
|
||||||
|
for (Agency currentAgency : agenciesToSave) {
|
||||||
|
ApiAgency correspondingApiAgency = relevantApiAgencies.stream()
|
||||||
|
.filter(aa -> currentAgency.getAgencyCode().equals(aa.getGajgjgdm()))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
if (correspondingApiAgency != null && correspondingApiAgency.getSjgajgjgdm() != null) {
|
||||||
|
Agency parentAgency = processedAgencies.get(correspondingApiAgency.getSjgajgjgdm());
|
||||||
|
if (parentAgency != null) {
|
||||||
|
currentAgency.setParent(parentAgency);
|
||||||
|
} else {
|
||||||
|
// 如果在本次同步的数据中找不到父级,尝试从数据库中查找已存在的父级
|
||||||
|
Optional<Agency> parentInDb = agencyRepository.findByAgencyCode(correspondingApiAgency.getSjgajgjgdm());
|
||||||
|
parentInDb.ifPresent(currentAgency::setParent);
|
||||||
|
if (parentInDb.isEmpty()) {
|
||||||
|
log.warn("机构 {} (代码: {}) 的上级机构 (代码: {}) 在本次同步和数据库中均未找到。",
|
||||||
|
currentAgency.getAgencyName(), currentAgency.getAgencyCode(), correspondingApiAgency.getSjgajgjgdm());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算并设置执法机构级别
|
||||||
|
Map<String, Integer> agencyLevelsCache = new HashMap<>();
|
||||||
|
int anchorLevel = 2;
|
||||||
|
// 第一遍:递归计算并缓存所有级别
|
||||||
|
for (Agency agency : agenciesToSave) {
|
||||||
|
computeAndCacheLevelRecursive(agency, agencyLevelsCache, rootAgencyCode, anchorLevel, processedAgencies);
|
||||||
|
}
|
||||||
|
// 第二遍:从缓存中设置级别到实体
|
||||||
|
for (Agency agency : agenciesToSave) {
|
||||||
|
agency.setAgencyLevel(agencyLevelsCache.get(agency.getAgencyCode()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据级别设置是否为叶子节点
|
||||||
|
for (Agency agency : agenciesToSave) {
|
||||||
|
agency.setLeaf(processedAgencies.values().stream()
|
||||||
|
.noneMatch(a -> a.getParent() != null && a.getParent().getAgencyCode().equals(agency.getAgencyCode())));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在所有父子关系和级别设置完毕后,计算路径
|
||||||
|
for (Agency agency : agenciesToSave) {
|
||||||
|
agency.setAgencyPath(calculateAgencyPath(agency, processedAgencies, agencyRepository));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!agenciesToSave.isEmpty()) {
|
||||||
|
agencyRepository.saveAll(agenciesToSave);
|
||||||
|
log.info("成功同步 {} 条执法机构信息到数据库。", agenciesToSave.size());
|
||||||
|
} else {
|
||||||
|
log.info("没有需要保存的执法机构信息。");
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
log.error("解析API响应时发生JSON处理错误。", e);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("执行执法机构信息同步任务时发生未知错误。", e);
|
||||||
|
}
|
||||||
|
log.info("执法机构信息同步任务结束。");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归查找所有下级机构
|
||||||
|
*
|
||||||
|
* @param agencyCode 当前机构代码
|
||||||
|
* @param apiAgencyMap 所有API机构的映射
|
||||||
|
* @param collectedCodes 收集的相关机构代码集合
|
||||||
|
*/
|
||||||
|
private void findAllChildAgencies(String agencyCode, Map<String, ApiAgency> apiAgencyMap, Set<String> collectedCodes) {
|
||||||
|
// 查找所有直接下级机构
|
||||||
|
apiAgencyMap.values().stream()
|
||||||
|
.filter(agency -> agencyCode.equals(agency.getSjgajgjgdm()))
|
||||||
|
.forEach(childAgency -> {
|
||||||
|
String childCode = childAgency.getGajgjgdm();
|
||||||
|
if (childCode != null && !collectedCodes.contains(childCode)) {
|
||||||
|
collectedCodes.add(childCode);
|
||||||
|
// 递归查找子机构的下级
|
||||||
|
findAllChildAgencies(childCode, apiAgencyMap, collectedCodes);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从外部API获取数据,包含令牌刷新和重试逻辑
|
||||||
|
*
|
||||||
|
* @param requestBody 请求体
|
||||||
|
* @param url API的URL
|
||||||
|
* @return API响应体字符串,如果失败则返回null或抛出异常
|
||||||
|
* @throws JsonProcessingException 如果请求体序列化失败
|
||||||
|
*/
|
||||||
|
@SneakyThrows
|
||||||
|
private String fetchDataFromApi(Map<String, Object> requestBody, String url) throws JsonProcessingException {
|
||||||
|
int maxRetries = 2; // 允许一次初始尝试和一次重试
|
||||||
|
|
||||||
|
for (int attempt = 1; attempt <= maxRetries; attempt++) {
|
||||||
|
AccessToken accessToken = authService.getTokenBackend(agencyTokenMobilePhone);
|
||||||
|
if (accessToken == null || accessToken.getAccess_token() == null) {
|
||||||
|
log.error("获取访问令牌失败 (尝试 {}/{}),URL: {}. 请检查AuthService配置和令牌提供者。", attempt, maxRetries, url);
|
||||||
|
throw new RuntimeException("获取API调用的访问令牌失败。");
|
||||||
|
}
|
||||||
|
String currentToken = accessToken.getAccess_token();
|
||||||
|
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
headers.setBearerAuth(currentToken);
|
||||||
|
|
||||||
|
HttpEntity<String> entity = new HttpEntity<>(objectMapper.writeValueAsString(requestBody), headers);
|
||||||
|
ResponseEntity<String> responseEntity;
|
||||||
|
|
||||||
|
try {
|
||||||
|
log.info("尝试API调用 (尝试 {}/{}) 到 URL: {},请求体: {}", attempt, maxRetries, url, requestBody);
|
||||||
|
responseEntity = restTemplate.postForEntity(url, entity, String.class);
|
||||||
|
|
||||||
|
if (responseEntity.getStatusCode().is2xxSuccessful()) {
|
||||||
|
log.info("API调用成功 (尝试 {}/{}),URL: {}", attempt, maxRetries, url);
|
||||||
|
return responseEntity.getBody();
|
||||||
|
} else {
|
||||||
|
log.error("API调用失败 (尝试 {}/{}),状态码 {}: {}. URL: {}, 请求体: {}",
|
||||||
|
attempt, maxRetries, responseEntity.getStatusCode(), responseEntity.getBody(), url, requestBody);
|
||||||
|
// 对于非2xx但非401的错误,当前不重试
|
||||||
|
return null; // 或根据需要抛出特定异常
|
||||||
|
}
|
||||||
|
} catch (HttpClientErrorException e) {
|
||||||
|
if (e.getStatusCode() == HttpStatus.UNAUTHORIZED) {
|
||||||
|
log.warn("API调用未授权 (尝试 {}/{}),可能令牌已过期. URL: {}. 正在尝试刷新令牌...",
|
||||||
|
attempt, maxRetries, url);
|
||||||
|
if (attempt < maxRetries) {
|
||||||
|
try {
|
||||||
|
authService.refreshTokenBackend(accessToken.getAccess_token(), accessToken.getToken_type(), accessToken.getRefresh_token(), agencyTokenMobilePhone); // 请求刷新令牌
|
||||||
|
log.info("请求刷新令牌成功。下一次尝试将使用新令牌。");
|
||||||
|
// 循环将继续,下一次迭代将再次调用getTokenBackendByYddh
|
||||||
|
} catch (Exception refreshException) {
|
||||||
|
log.error("请求刷新令牌期间发生异常: {}. 中止对URL: {} 的重试。",
|
||||||
|
refreshException.getMessage(), url, refreshException);
|
||||||
|
throw new RuntimeException("API调用未授权后,请求刷新令牌失败。", refreshException);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.error("API调用未授权,尝试 {} 次后仍然失败 (已达最大重试次数),URL: {}.", attempt, url);
|
||||||
|
throw new RuntimeException("多次重试后,API调用因授权问题失败,URL: " + url, e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 其他 HttpClientErrorException (非401的4xx或5xx错误)
|
||||||
|
log.error("API调用时发生HttpClientErrorException (尝试 {}/{}),URL {}: {} - {}. 请求体: {}",
|
||||||
|
attempt, maxRetries, url, e.getStatusCode(), e.getResponseBodyAsString(), requestBody, e);
|
||||||
|
throw e; // 重新抛出其他HTTP客户端错误
|
||||||
|
}
|
||||||
|
} catch (RestClientException e) {
|
||||||
|
// 一般的 RestClientException (例如网络问题)
|
||||||
|
log.error("API调用时发生RestClientException (尝试 {}/{}),URL {}: {}. 请求体: {}",
|
||||||
|
attempt, maxRetries, url, e.getMessage(), requestBody, e);
|
||||||
|
if (attempt == maxRetries) { // 如果是最后一次尝试,则抛出异常
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
log.warn("发生RestClientException后进行重试,尝试 {}/{},URL: {}", attempt, maxRetries, url);
|
||||||
|
// 可选:在重试网络相关错误前添加短暂延迟
|
||||||
|
// try { Thread.sleep(1000); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 如果循环结束仍未返回或抛出异常 (理论上不应发生)
|
||||||
|
log.error("多次重试后未能成功从API获取数据,URL: {}", url);
|
||||||
|
throw new RuntimeException("多次重试后未能从API获取数据,URL: " + url);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成执法机构简码。
|
||||||
|
*
|
||||||
|
* @param gajgjgdm 完整的执法机构代码
|
||||||
|
* @return 生成的执法机构简码
|
||||||
|
*/
|
||||||
|
private String generateAgencySimpleCode(String gajgjgdm) {
|
||||||
|
if (gajgjgdm == null || gajgjgdm.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return StringUtils.trimEven0(gajgjgdm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算并生成机构的层级路径字符串。
|
||||||
|
* 路径由机构代码组成,以 '.' 分隔,从最高层级到当前机构。
|
||||||
|
* 例如:root.parent.child.currentAgencyCode
|
||||||
|
*
|
||||||
|
* @param currentAgency 需要计算路径的当前机构实体。父级关系应已在此实体中设置。
|
||||||
|
* @param processedAgencies 当前批次中已处理的机构映射 (agencyCode -> Agency),此方法当前未使用,但保留以备将来扩展。
|
||||||
|
* @param agencyRepository 机构仓库,此方法当前未使用,但保留以备将来扩展。
|
||||||
|
* @return 生成的机构路径字符串,如果无法生成(例如,机构或其代码为空),则返回null。
|
||||||
|
* 如果达到最大层级深度,则返回以 "ERROR_MAX_DEPTH_" 开头的路径。
|
||||||
|
*/
|
||||||
|
private String calculateAgencyPath(Agency currentAgency, Map<String, Agency> processedAgencies, AgencyRepository agencyRepository) {
|
||||||
|
if (currentAgency == null || currentAgency.getAgencyCode() == null) {
|
||||||
|
log.warn("计算机构路径时,当前机构或机构代码为空。");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// Placeholder log removed as we are implementing the logic now.
|
||||||
|
|
||||||
|
List<String> pathParts = new ArrayList<>();
|
||||||
|
Agency tempAgency = currentAgency;
|
||||||
|
int depth = 0;
|
||||||
|
final int maxDepth = 20; // Max depth to prevent infinite loops in case of data issues
|
||||||
|
|
||||||
|
while (tempAgency != null && depth < maxDepth) {
|
||||||
|
if (tempAgency.getAgencyCode() == null) {
|
||||||
|
log.warn("在为起始机构 '{}' ({}) 计算路径时,遇到机构代码为空的机构。当前已构建路径: [{}]. 跳过此路径部分。",
|
||||||
|
currentAgency.getAgencyName(), currentAgency.getAgencyCode(), String.join(".", pathParts));
|
||||||
|
break; // 或根据需求处理,例如,对此空代码使用占位符
|
||||||
|
}
|
||||||
|
pathParts.add(tempAgency.getAgencySimpleCode());
|
||||||
|
tempAgency = tempAgency.getParent(); // 正确地向上遍历父级链
|
||||||
|
depth++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (depth >= maxDepth) {
|
||||||
|
log.error("calculateAgencyPath: 机构 '{}' (代码: {}) 计算路径时达到最大深度 ({})。可能存在循环依赖或层级过深。已构建路径: [{}]",
|
||||||
|
maxDepth, currentAgency.getAgencyName(), currentAgency.getAgencyCode(), String.join(".", pathParts));
|
||||||
|
// 返回一个独特的错误路径或根据需求处理,例如,返回已构建路径并添加错误前缀
|
||||||
|
Collections.reverse(pathParts); // 反转已有的路径部分,使其顺序正确
|
||||||
|
return "ERROR_MAX_DEPTH_" + String.join(".", pathParts);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pathParts.isEmpty()) {
|
||||||
|
log.warn("calculateAgencyPath: 机构 '{}' (代码: {}) 的路径部分列表为空。将其自身代码作为路径返回。", currentAgency.getAgencyName(), currentAgency.getAgencyCode());
|
||||||
|
return currentAgency.getAgencyCode(); // 理想情况下,如果当前机构及其代码有效,则不应发生此情况
|
||||||
|
}
|
||||||
|
|
||||||
|
Collections.reverse(pathParts);
|
||||||
|
return String.join(".", pathParts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归计算并缓存机构级别。
|
||||||
|
* "西安市应急管理局" 为级别2,其子级为父级级别+1。
|
||||||
|
*
|
||||||
|
* @param agency 当前处理的机构
|
||||||
|
* @param levelCache 存储已计算级别的缓存 (agencyCode -> level)
|
||||||
|
* @param anchorAgencyCode 锚点机构代码
|
||||||
|
* @param anchorLevel 锚点机构的级别
|
||||||
|
* @param allAgenciesMap 当前批次中已处理的机构映射 (agencyCode -> Agency),用于查找父级实体
|
||||||
|
*/
|
||||||
|
private void computeAndCacheLevelRecursive(Agency agency, Map<String, Integer> levelCache,
|
||||||
|
String anchorAgencyCode, int anchorLevel,
|
||||||
|
Map<String, Agency> allAgenciesMap) {
|
||||||
|
if (agency == null || agency.getAgencyCode() == null || levelCache.containsKey(agency.getAgencyCode())) {
|
||||||
|
return; // 无效机构或已处理
|
||||||
|
}
|
||||||
|
|
||||||
|
// 锚点机构处理
|
||||||
|
if (anchorAgencyCode.equals(agency.getAgencyCode())) {
|
||||||
|
levelCache.put(agency.getAgencyCode(), anchorLevel);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 非锚点机构,依赖父级级别
|
||||||
|
Agency parent = agency.getParent(); // 父级关系应已在此前步骤中设置
|
||||||
|
|
||||||
|
if (parent == null) {
|
||||||
|
// 没有父级且不是锚点机构,无法通过此逻辑确定级别
|
||||||
|
log.warn("机构 '{}' ({}) 非锚点且无父级,无法基于锚点逻辑确定其级别。",
|
||||||
|
agency.getAgencyName(), agency.getAgencyCode());
|
||||||
|
levelCache.put(agency.getAgencyCode(), null); // 标记为无法计算或设为默认值
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保父级级别已计算(递归调用)
|
||||||
|
computeAndCacheLevelRecursive(parent, levelCache, anchorAgencyCode, anchorLevel, allAgenciesMap);
|
||||||
|
|
||||||
|
Integer parentLevel = levelCache.get(parent.getAgencyCode());
|
||||||
|
if (parentLevel != null) {
|
||||||
|
levelCache.put(agency.getAgencyCode(), parentLevel + 1);
|
||||||
|
} else {
|
||||||
|
// 父级级别未能确定,则子级也无法确定
|
||||||
|
log.warn("未能确定父级机构 '{}' ({}) 的级别,因此无法确定子级机构 '{}' ({}) 的级别。",
|
||||||
|
parent.getAgencyName(), parent.getAgencyCode(),
|
||||||
|
agency.getAgencyName(), agency.getAgencyCode());
|
||||||
|
levelCache.put(agency.getAgencyCode(), null); // 标记为无法计算或设为默认值
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Inner DTO classes for API Response ---
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private static class ApiResponse {
|
||||||
|
private String code;
|
||||||
|
private boolean success;
|
||||||
|
private ApiData data;
|
||||||
|
private String msg;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private static class ApiData {
|
||||||
|
private int offset;
|
||||||
|
private int limit;
|
||||||
|
@JsonAlias("totalCount")
|
||||||
|
private String totalCountStr;
|
||||||
|
private List<ApiAgency> list;
|
||||||
|
@JsonProperty("totalPage")
|
||||||
|
private int totalPage;
|
||||||
|
|
||||||
|
public int getTotalCount() {
|
||||||
|
try {
|
||||||
|
return Integer.parseInt(totalCountStr);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString
|
||||||
|
private static class ApiAgency {
|
||||||
|
private String ywlsh;
|
||||||
|
@JsonProperty("gajgjgdm")
|
||||||
|
private String gajgjgdm;
|
||||||
|
@JsonProperty("sjgajgjgdm")
|
||||||
|
private String sjgajgjgdm;
|
||||||
|
@JsonProperty("gajgmc")
|
||||||
|
private String gajgmc;
|
||||||
|
@JsonProperty("xssx")
|
||||||
|
private Integer xssx;
|
||||||
|
private String sjztdm;
|
||||||
|
@JsonProperty("gajgmcjc")
|
||||||
|
private String gajgmcjc;
|
||||||
|
private String dwlb;
|
||||||
|
private String xzqhdm;
|
||||||
|
@JsonProperty("gajgmclbdm")
|
||||||
|
private String gajgmclbdm;
|
||||||
|
@JsonProperty("gajgbmlbdm")
|
||||||
|
private String gajgbmlbdm;
|
||||||
|
private Integer subnum;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,230 @@
|
||||||
|
package com.aisino.iles.lawenforcement.schedule.service;
|
||||||
|
|
||||||
|
import cn.hutool.http.HttpRequest;
|
||||||
|
import cn.hutool.http.HttpUtil;
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import com.aisino.iles.lawenforcement.model.Enterprise;
|
||||||
|
import com.aisino.iles.lawenforcement.model.Enterprise_;
|
||||||
|
import com.aisino.iles.lawenforcement.repository.*;
|
||||||
|
import com.aisino.iles.lawenforcement.service.AuthService;
|
||||||
|
import com.smartlx.sso.client.model.AccessToken;
|
||||||
|
import com.smartlx.sso.client.properties.SsoClientProperties;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.PageRequest;
|
||||||
|
import org.springframework.data.jpa.domain.Specification;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Propagation;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 企业设备接入信息定时任务
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class EnterpriseJoinScheduleService {
|
||||||
|
|
||||||
|
private final EnterpriseRepository enterpriseRepository;
|
||||||
|
private final EnterpriseCameraRepository enterpriseCameraRepository;
|
||||||
|
private final EnterpriseWarnRepository enterpriseWarnRepository;
|
||||||
|
private final AuthService authService;
|
||||||
|
private final SsoClientProperties ssoClientProperties;
|
||||||
|
|
||||||
|
@Value("${third-party.enterprise.yddh:}") // 使用正确的配置项获取令牌标识
|
||||||
|
private String tokenMobilePhone;
|
||||||
|
|
||||||
|
@Value("${third-party.enterprise.selfInsAndSelfReport:}")
|
||||||
|
private String selfInsAndSelfReportUrl;
|
||||||
|
|
||||||
|
|
||||||
|
public Page<Enterprise> pageEnterprise(int page, int limit) {
|
||||||
|
Specification<Enterprise> spec = (root, query, cb) -> cb.and(cb.equal(root.get(Enterprise_.delFlag), 0), cb.isNotNull(root.get(Enterprise_.unifiedSocialCode)));
|
||||||
|
return enterpriseRepository.findAll(spec, PageRequest.of(page, limit));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 企业摄像头信息和预警信息同步任务
|
||||||
|
* 每天定时执行(通过配置文件动态指定 cron 表达式)
|
||||||
|
*/
|
||||||
|
@Scheduled(cron = "0 0 1 * * ?")
|
||||||
|
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||||
|
public void scheduledUpdateEnterpriseTask() {
|
||||||
|
log.info("===== 开始执行企业摄像头信息和预警信息同步任务 =====");
|
||||||
|
|
||||||
|
int page = 0;
|
||||||
|
final int limit = 2000;
|
||||||
|
Page<Enterprise> pageResult;
|
||||||
|
|
||||||
|
do {
|
||||||
|
// 分页查询企业信息
|
||||||
|
pageResult = pageEnterprise(page, limit);
|
||||||
|
List<Enterprise> enterprises = pageResult.getContent();
|
||||||
|
|
||||||
|
if (!enterprises.isEmpty()) {
|
||||||
|
// 更新企业摄像头信息和预警信息
|
||||||
|
batchUpdate(enterprises);
|
||||||
|
log.info("已处理企业数据:page={}, size={}", page, enterprises.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
page++;
|
||||||
|
} while (pageResult.hasNext());
|
||||||
|
|
||||||
|
log.info("===== 企业摄像头信息和预警信息同步任务完成 =====");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(propagation = Propagation.MANDATORY)
|
||||||
|
public void batchUpdate(List<Enterprise> enterprises) {
|
||||||
|
List<String> unifiedSocialCodes = enterprises.stream().map(Enterprise::getUnifiedSocialCode).collect(Collectors.toList());
|
||||||
|
List<Map<String, Object>> cameraList = enterpriseCameraRepository.countGroupByUnifiedSocialCode(unifiedSocialCodes);
|
||||||
|
Map<String, Long> cameraMap = cameraList.stream().collect(Collectors.toMap(row -> (String) row.get("unified_social_code"), row -> ((Number) row.get("num")).longValue()));
|
||||||
|
// List<Map<String, Object>> warnList = enterpriseWarnRepository.countGroupByUnifiedSocialCode(unifiedSocialCodes);
|
||||||
|
// Map<String, Long> warnMap = warnList.stream().collect(Collectors.toMap(row -> (String) row.get("unified_social_code"), row -> ((Number) row.get("num")).longValue()));
|
||||||
|
// 批量更新视频接入状态
|
||||||
|
enterprises.forEach(enterprise -> {
|
||||||
|
Long count = cameraMap.getOrDefault(enterprise.getUnifiedSocialCode(), 0L);
|
||||||
|
enterprise.setVideoAccess(count > 0 ? "1" : "0");
|
||||||
|
|
||||||
|
// Long count2 = warnMap.getOrDefault(enterprise.getUnifiedSocialCode(), 0L);
|
||||||
|
// enterprise.setPermitAccess(count2 > 0 ? "1" : "0");
|
||||||
|
});
|
||||||
|
enterpriseRepository.saveAll(enterprises);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 企业感知信息同步任务
|
||||||
|
* 每天定时执行(通过配置文件动态指定 cron 表达式)
|
||||||
|
*/
|
||||||
|
@Scheduled(cron = "0 0 2 * * ?")
|
||||||
|
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||||
|
public void scheduledUpdateEnterpriseTask2() {
|
||||||
|
log.info("===== 开始执行企业感知设备信息同步任务 =====");
|
||||||
|
|
||||||
|
int page = 0;
|
||||||
|
final int limit = 2000;
|
||||||
|
Page<Enterprise> pageResult;
|
||||||
|
|
||||||
|
do {
|
||||||
|
// 分页查询企业信息
|
||||||
|
pageResult = pageEnterprise(page, limit);
|
||||||
|
List<Enterprise> enterprises = pageResult.getContent();
|
||||||
|
|
||||||
|
if (!enterprises.isEmpty()) {
|
||||||
|
// 更新企业感知设备信息
|
||||||
|
batchUpdate2(enterprises);
|
||||||
|
log.info("已处理企业数据:page={}, size={}", page, enterprises.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
page++;
|
||||||
|
} while (pageResult.hasNext());
|
||||||
|
|
||||||
|
log.info("===== 企业感知设备信息同步任务完成 =====");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(propagation = Propagation.MANDATORY)
|
||||||
|
public void batchUpdate2(List<Enterprise> enterprises) {
|
||||||
|
String body = HttpUtil.createGet("http://10.22.245.227:1084/dah-api/public/monitor/units/list").execute().body();
|
||||||
|
log.info("企业感知设备信息:body={}", body);
|
||||||
|
JSONObject jsonObject = JSONUtil.parseObj(body);
|
||||||
|
Long code = jsonObject.getLong("code");
|
||||||
|
if (code == 200) {
|
||||||
|
List<String> socialCodes = jsonObject.getJSONArray("data")
|
||||||
|
.stream()
|
||||||
|
.filter(JSONObject.class::isInstance)
|
||||||
|
.map(obj -> ((JSONObject) obj).getStr("socialCode"))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
// 批量更新企业感知设备信息
|
||||||
|
enterprises.forEach(enterprise -> {
|
||||||
|
String unifiedSocialCode = enterprise.getUnifiedSocialCode();
|
||||||
|
boolean hasPerceptionAccess = socialCodes.contains(unifiedSocialCode);
|
||||||
|
enterprise.setPerceptionAccess(hasPerceptionAccess ? "1" : "0");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
enterpriseRepository.saveAll(enterprises);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 企业自查自报信息同步任务
|
||||||
|
* 每天定时执行(通过配置文件动态指定 cron 表达式)
|
||||||
|
*/
|
||||||
|
@Scheduled(cron = "0 0 3 * * ?")
|
||||||
|
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||||
|
public void scheduledUpdateEnterpriseTask3() {
|
||||||
|
if (tokenMobilePhone == null || tokenMobilePhone.isEmpty()) {
|
||||||
|
log.error("API令牌YDDH (third-party.enterprise.yddh) 未配置.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("===== 开始执行企业自查自报信息同步任务 =====");
|
||||||
|
|
||||||
|
int page = 0;
|
||||||
|
final int limit = 2000;
|
||||||
|
Page<Enterprise> pageResult;
|
||||||
|
|
||||||
|
do {
|
||||||
|
// 分页查询企业信息
|
||||||
|
pageResult = pageEnterprise(page, limit);
|
||||||
|
List<Enterprise> enterprises = pageResult.getContent();
|
||||||
|
|
||||||
|
if (!enterprises.isEmpty()) {
|
||||||
|
// 更新企业自查自报信息
|
||||||
|
batchUpdate3(enterprises);
|
||||||
|
log.info("已处理企业数据:page={}, size={}", page, enterprises.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
page++;
|
||||||
|
} while (pageResult.hasNext());
|
||||||
|
|
||||||
|
log.info("===== 企业自查自报信息同步任务完成 =====");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(propagation = Propagation.MANDATORY)
|
||||||
|
public void batchUpdate3(List<Enterprise> enterprises) {
|
||||||
|
try {
|
||||||
|
AccessToken tokenBackend = authService.getTokenBackend(tokenMobilePhone);
|
||||||
|
String accessToken = tokenBackend.getAccess_token();
|
||||||
|
String tokenType = tokenBackend.getToken_type();
|
||||||
|
String clientId = ssoClientProperties.getClientId();
|
||||||
|
for (Enterprise enterprise : enterprises) {
|
||||||
|
try {
|
||||||
|
Map<String, Object> param = new HashMap<>();
|
||||||
|
param.put("limit", "1");
|
||||||
|
param.put("page", 1);
|
||||||
|
Map<String, String> entity = new HashMap<>();
|
||||||
|
entity.put("unifiedSocialCode", enterprise.getUnifiedSocialCode());
|
||||||
|
param.put("entity", entity);
|
||||||
|
log.info("url:{}, token:{}, clientId:{}", selfInsAndSelfReportUrl, accessToken, clientId);
|
||||||
|
String body = HttpRequest.post(selfInsAndSelfReportUrl)
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.header("Authorization", tokenType + " " + accessToken)
|
||||||
|
.header("appId", clientId)
|
||||||
|
.body(JSONUtil.toJsonStr(param))
|
||||||
|
.execute()
|
||||||
|
.body();
|
||||||
|
JSONObject jsonObject = JSONUtil.parseObj(body);
|
||||||
|
log.info("企业自查自报信息结果:{}", jsonObject);
|
||||||
|
if (jsonObject.getBool("success")) {
|
||||||
|
Long totalCount = Long.valueOf(jsonObject.getJSONObject("data").getStr("totalCount"));
|
||||||
|
enterprise.setInfoAccess(totalCount > 0 ? "1" : "0");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("处理企业 {} 时出错: {}", enterprise.getUnitName(), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enterpriseRepository.saveAll(enterprises);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("获取 Token 失败: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,699 @@
|
||||||
|
package com.aisino.iles.lawenforcement.schedule.service;
|
||||||
|
|
||||||
|
import cn.hutool.http.HttpUtil;
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.aisino.iles.lawenforcement.model.*;
|
||||||
|
import com.aisino.iles.lawenforcement.model.dto.IndustryEnterpriseDto;
|
||||||
|
import com.aisino.iles.lawenforcement.model.dto.WaferEnterpriseDto;
|
||||||
|
import com.aisino.iles.lawenforcement.repository.*;
|
||||||
|
import com.aisino.iles.lawenforcement.service.AuthService;
|
||||||
|
import com.aisino.iles.lawenforcement.service.DictInterfaceService;
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.smartlx.sso.client.model.AccessToken;
|
||||||
|
import com.smartlx.sso.client.properties.SsoClientProperties;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 企业信息定时任务
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class EnterprisePoniteScheduleService {
|
||||||
|
private final EnterpriseRepository enterpriseRepo;
|
||||||
|
private final EnterpriseHistoryRepository enterpriseHistoryRepo;
|
||||||
|
private final AgencyRepository agencyRepo;
|
||||||
|
private final AuthService authService;
|
||||||
|
private final TransactionTemplate transactionTemplate;
|
||||||
|
private final String mobilePhone;
|
||||||
|
private final DictInterfaceService dictService;
|
||||||
|
private String accessToken;
|
||||||
|
private String tokenType;
|
||||||
|
private String refreshToken;
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
|
public EnterprisePoniteScheduleService(EnterpriseRepository enterpriseRepo,
|
||||||
|
EnterpriseHistoryRepository enterpriseHistoryRepo,
|
||||||
|
AgencyRepository agencyRepo,
|
||||||
|
AuthService authService,
|
||||||
|
ObjectMapper objectMapper,
|
||||||
|
@Value("${third-party.enterprise.yddh:}") String mobilePhone,
|
||||||
|
TransactionTemplate transactionTemplate,
|
||||||
|
DictInterfaceService dictService) {
|
||||||
|
this.enterpriseRepo = enterpriseRepo;
|
||||||
|
this.enterpriseHistoryRepo = enterpriseHistoryRepo;
|
||||||
|
this.agencyRepo = agencyRepo;
|
||||||
|
this.authService = authService;
|
||||||
|
this.objectMapper = objectMapper;
|
||||||
|
this.mobilePhone = mobilePhone;
|
||||||
|
this.transactionTemplate = transactionTemplate;
|
||||||
|
this.dictService = dictService;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工作台信息导入
|
||||||
|
* 每天10点执行一次
|
||||||
|
* (cron = "0 0 15 * * ?")
|
||||||
|
* (cron = "${scheduler.expression}")
|
||||||
|
* (fixedRate = 120000)
|
||||||
|
*/
|
||||||
|
@Scheduled(cron = "${scheduler.task.enterprise.cron.expression}")
|
||||||
|
public void scheduledEnterpriseTask() {
|
||||||
|
getToken();
|
||||||
|
dictService.getDictItem("YJ_CODE_9017", tokenType, accessToken);
|
||||||
|
//enterpriseTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工作台信息导入
|
||||||
|
* 每天15点执行一次
|
||||||
|
* (cron = "0 15 * * * ?")
|
||||||
|
* (cron = "${scheduler.expression}")
|
||||||
|
* (fixedRate = 120000)
|
||||||
|
*/
|
||||||
|
// @Scheduled(cron = "0 * * * * ?")
|
||||||
|
@Scheduled(cron = "${scheduler.task.waferEnterprise.cron.expression}")
|
||||||
|
public void scheduledWaferEnterpriseTask() {
|
||||||
|
getToken();
|
||||||
|
dictService.getDictItem("YJ_CODE_9017", tokenType, accessToken);
|
||||||
|
enterpriseTask();
|
||||||
|
enterpriseWaferTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导入企业信息
|
||||||
|
*/
|
||||||
|
public void enterpriseTask() {
|
||||||
|
log.info("开始导入企业信息...");
|
||||||
|
int page = 1;
|
||||||
|
boolean b = updateOrImportIndustryEnterprise(page);
|
||||||
|
while (b) {
|
||||||
|
page++;
|
||||||
|
b = updateOrImportIndustryEnterprise(page);
|
||||||
|
}
|
||||||
|
log.info("企业信息导入完成...");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 危化导入企业信息
|
||||||
|
*/
|
||||||
|
public void enterpriseWaferTask() {
|
||||||
|
log.info("开始导入危化企业信息...");
|
||||||
|
int page = 1;
|
||||||
|
boolean b = updateOrImportWaferEnterprise(page);
|
||||||
|
while (b) {
|
||||||
|
page++;
|
||||||
|
b = updateOrImportWaferEnterprise(page);
|
||||||
|
}
|
||||||
|
log.info("危化企业信息导入完成...");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取token
|
||||||
|
*/
|
||||||
|
private void getToken() {
|
||||||
|
try {
|
||||||
|
AccessToken accessTokenObj = authService.getTokenBackend(mobilePhone);
|
||||||
|
if (accessTokenObj != null) {
|
||||||
|
accessToken = accessTokenObj.getAccess_token();
|
||||||
|
tokenType = accessTokenObj.getToken_type();
|
||||||
|
refreshToken = accessTokenObj.getRefresh_token();
|
||||||
|
log.info("获取token成功");
|
||||||
|
} else {
|
||||||
|
log.error("获取token失败,返回为null");
|
||||||
|
throw new RuntimeException("无法获取有效的访问令牌");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("获取token失败", e);
|
||||||
|
throw new RuntimeException("无法获取有效的访问令牌", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新token
|
||||||
|
*/
|
||||||
|
private void refreshToken() {
|
||||||
|
try {
|
||||||
|
authService.refreshTokenBackend(accessToken, tokenType, refreshToken, mobilePhone);
|
||||||
|
// 刷新后重新获取token
|
||||||
|
getToken();
|
||||||
|
log.info("刷新token成功");
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("刷新token失败,尝试重新获取token", e);
|
||||||
|
getToken();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public boolean updateOrImportIndustryEnterprise(int page) {
|
||||||
|
boolean flag = false;
|
||||||
|
try {
|
||||||
|
JSONObject jsonBody = new JSONObject();
|
||||||
|
JSONObject jsonPram = new JSONObject();
|
||||||
|
jsonBody.set("method", "GET");
|
||||||
|
jsonBody.set("jsonObject", jsonPram);
|
||||||
|
jsonBody.set("pageNum", page);
|
||||||
|
jsonBody.set("pageSize", 1000);
|
||||||
|
jsonBody.set("path", "/edataservice/api/gmqyxx");
|
||||||
|
jsonBody.set("secret", "805cd25953b1ba8852aac00564fe163213567518a5a509a849d8384b7b090b70");
|
||||||
|
String body = HttpUtil.createPost("http://10.22.245.216:29999/jeecg-data-service/edataservice/api/")
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.body(jsonBody.toString())
|
||||||
|
.execute()
|
||||||
|
.body();
|
||||||
|
JsonNode jsonNode = objectMapper.readValue(body, JsonNode.class);
|
||||||
|
if (jsonNode.has("code") && 200 == jsonNode.get("code").asInt() && jsonNode.has("result")) {
|
||||||
|
JsonNode data = objectMapper.readValue(jsonNode.get("result").toString(), JsonNode.class);
|
||||||
|
if (null != data && data.has("records")) {
|
||||||
|
JsonNode arrNode = data.get("records");
|
||||||
|
if (arrNode.isArray()) {
|
||||||
|
|
||||||
|
long current = data.get("current").asLong();
|
||||||
|
long pages = data.get("pages").asLong();
|
||||||
|
if (current < pages) flag = true;
|
||||||
|
List<IndustryEnterpriseDto> dtos = objectMapper.readValue(arrNode.toString(), new TypeReference<>() {});
|
||||||
|
|
||||||
|
Set<String> usccSet = dtos.stream().map(IndustryEnterpriseDto::getTyshxydm).filter(StringUtils::hasText).collect(Collectors.toSet());
|
||||||
|
// 历史企业
|
||||||
|
List<Enterprise> enterpriseList = enterpriseRepo.findByUnifiedSocialCodeIn(usccSet);
|
||||||
|
List<Enterprise> enterprises = new ArrayList<>();
|
||||||
|
log.info("开始处理:{}条数据",dtos.size());
|
||||||
|
for (IndustryEnterpriseDto dto : dtos) {
|
||||||
|
if (StringUtils.hasText(dto.getTyshxydm())) {
|
||||||
|
Enterprise oldLtd = enterpriseList.stream().filter(o -> o.getUnifiedSocialCode().equals(dto.getTyshxydm())).findFirst().orElse(null);
|
||||||
|
if (null != oldLtd) {
|
||||||
|
EnterpriseHistory history = new EnterpriseHistory();
|
||||||
|
BeanUtils.copyProperties(oldLtd, history);
|
||||||
|
history.setTheType("定时任务修改");
|
||||||
|
LocalDateTime now = LocalDateTime.now();
|
||||||
|
history.setHistoryTime(now);
|
||||||
|
enterpriseHistoryRepo.save(history);
|
||||||
|
|
||||||
|
oldLtd.setUnitName(dto.getQymc()); // 企业名称
|
||||||
|
//oldLtd.setUnitCode(); // 生产经营单位编码
|
||||||
|
oldLtd.setUnifiedSocialCode(dto.getTyshxydm()); // 统一社会信用代码
|
||||||
|
if ("0".equals(dto.getScjyztxh())) {
|
||||||
|
oldLtd.setBusinessStatus("11"); // 营业状态
|
||||||
|
} else {
|
||||||
|
oldLtd.setBusinessStatus("13"); // 营业状态
|
||||||
|
}
|
||||||
|
Optional.ofNullable(dto.getQxbm()).filter(StringUtils::hasText).flatMap(agencyRepo::findByAgencyCode).ifPresent(oldLtd::setAgency); // 机构
|
||||||
|
//oldLtd.setRegulatedIndustry(); // 国民经济行业分类
|
||||||
|
//oldLtd.setAreaComb(); // 注册地址(全)
|
||||||
|
oldLtd.setDetailedAddress(dto.getDz()); // 注册详细地址
|
||||||
|
//oldLtd.setOpLocAreaComb(); // 经营地址(全)
|
||||||
|
oldLtd.setOpLocAddress(dto.getDz()); // 经营详细地址
|
||||||
|
if (null != dto.getHylb() && "1".equals(dto.getHylb())) {
|
||||||
|
oldLtd.setIndustryType("7"); // 监管行业
|
||||||
|
} else {
|
||||||
|
oldLtd.setIndustryType("6"); // 监管行业
|
||||||
|
}
|
||||||
|
oldLtd.setLegalRepresentative(dto.getFddbr()); // 法定代表人姓名
|
||||||
|
oldLtd.setLegalPhone(dto.getFddbrlxdh()); // 法人联系电话
|
||||||
|
//oldLtd.setLegalDuty(); // 法定代表人职位
|
||||||
|
//oldLtd.setOpScope(); // 主营业务
|
||||||
|
//oldLtd.setAffiliation(); // 行政隶属关系
|
||||||
|
//oldLtd.setOilExtract(); // 是否石油开采
|
||||||
|
//oldLtd.setSafetyFocus(); // 是否安全生产监管重点企业
|
||||||
|
//oldLtd.setIsScaleEnterprise(); // 是否规模以上企业
|
||||||
|
//oldLtd.setSafetyLic(); // 是否有安全生产许可证
|
||||||
|
//oldLtd.setProvince(); // 注册地址-省
|
||||||
|
//oldLtd.setCity(); // 注册地址-市
|
||||||
|
//oldLtd.setCounty(); // 注册地址-县/区
|
||||||
|
//国民经济行业分类代码《国民经济行业分类》(GB/T 4754—2017)
|
||||||
|
// if (StringUtils.hasText(dto.getGmjjhyfldm())) {
|
||||||
|
// String xxdm = dictService.getTopXxdm(dto.getGmjjhyfldm());
|
||||||
|
// enterprise.setRegulatedIndustry(xxdm);
|
||||||
|
// String[] ss = xxdm.split("/");
|
||||||
|
// for (int i = 0; i < ss.length; i++) {
|
||||||
|
// if (i == 0) enterprise.setEconCategory(ss[i]); // 国民经济行业分类代码
|
||||||
|
// if (i == 1) enterprise.setEconCategoryTypea(ss[i]); // 国民经济行业分类A型
|
||||||
|
// if (i == 2) enterprise.setEconCategoryTypeb(ss[i]); // 国民经济行业分类B型
|
||||||
|
// if (i == 3) enterprise.setEconCategoryTypec(ss[i]); // 国民经济行业分类C型
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//oldLtd.setOpLocProvince(); // 经营地址-省
|
||||||
|
//oldLtd.setOpLocCity(); // 经营地址-市
|
||||||
|
oldLtd.setOpLocArea(dto.getQxmc()); // 经营地址-区
|
||||||
|
//oldLtd.setBusinessRating(); // 企业分级
|
||||||
|
//oldLtd.setBusinessCategory(); // 企业分类
|
||||||
|
//oldLtd.setPostalCode(); // 邮政编码
|
||||||
|
if (null != dto.getJjlxxh() && StringUtils.hasText(dto.getJjlxxh())) { // 国民经济类型
|
||||||
|
String economicType = dto.getJjlxxh();
|
||||||
|
switch (economicType) {
|
||||||
|
case "110" -> oldLtd.setEconomicType("1");
|
||||||
|
case "120" -> oldLtd.setEconomicType("2");
|
||||||
|
case "130" -> oldLtd.setEconomicType("3");
|
||||||
|
case "140" -> oldLtd.setEconomicType("4");
|
||||||
|
case "150" -> oldLtd.setEconomicType("5");
|
||||||
|
case "160" -> oldLtd.setEconomicType("6");
|
||||||
|
case "170" -> oldLtd.setEconomicType("7");
|
||||||
|
case "190" -> oldLtd.setEconomicType("8");
|
||||||
|
case "290" -> oldLtd.setEconomicType("9");
|
||||||
|
case "310" -> oldLtd.setEconomicType("10");
|
||||||
|
case "330" -> oldLtd.setEconomicType("11");
|
||||||
|
case "159" -> oldLtd.setEconomicType("12");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//oldLtd.setLegalPersonIdType(); // 法定代表人证件类型
|
||||||
|
//oldLtd.setLegalPersonIdNumber(); // 法定代表人证件号码
|
||||||
|
//oldLtd.setIsInChemicalPark(); // 是否位于化工园区
|
||||||
|
//oldLtd.setExpiryDate(); // 营业执照有效期
|
||||||
|
//oldLtd.setOrgCode(); // 组织机构代码
|
||||||
|
oldLtd.setUnitScale(dto.getQygm()); // 企业规模
|
||||||
|
//oldLtd.setEstablishmentDate(); // 成立日期
|
||||||
|
//oldLtd.setRegisteredCapital(); // 注册资本(万元)
|
||||||
|
Optional.ofNullable(dto.getJd()).filter(StringUtils::hasText).ifPresent(oldLtd::setLongitude); // 经度
|
||||||
|
Optional.ofNullable(dto.getWd()).filter(StringUtils::hasText).ifPresent(oldLtd::setLatitude); // 纬度
|
||||||
|
|
||||||
|
oldLtd.setRegistrationType(dto.getJjxz()); // 登记注册企业类别
|
||||||
|
//oldLtd.setLicenseNumber(); // 许可证编号
|
||||||
|
//oldLtd.setSafetyLevel(); // 安全生产标准化等级
|
||||||
|
//oldLtd.setIssuingAuthority(); // 发证机关
|
||||||
|
oldLtd.setEmployeeCount(dto.getZgzrs()); // 从业人员数量
|
||||||
|
//oldLtd.setIsTraining(); // 是否为培训机构
|
||||||
|
//oldLtd.setProductionManageInfoExp(); // 安全基础管理信息
|
||||||
|
//oldLtd.setProductionEquipmentExp(); // 生产设备设施信息
|
||||||
|
//oldLtd.setNocoalIndustryExpansion(); // 非煤行业扩展信息
|
||||||
|
//oldLtd.setDangerFeatureInfo(); // 危化行业扩展信息
|
||||||
|
//oldLtd.setFireworksAddInfo(); // 烟花爆竹行业扩展信息
|
||||||
|
oldLtd.setIndustryExpandInfos(dto.toString()); // 工贸行业扩展信息
|
||||||
|
oldLtd.setMainName(dto.getZyfzr()); // 主要负责人姓名
|
||||||
|
oldLtd.setMainPhone(dto.getZyfzrlxdh()); // 主要负责人电话
|
||||||
|
//oldLtd.setMajorAccidentHazard(); // 重大事故隐患年份
|
||||||
|
//oldLtd.setMajorDanger(); // 是否有重大危险源
|
||||||
|
//oldLtd.setInterid(dto.getYwlsh()); // 第三方对接ID
|
||||||
|
try {
|
||||||
|
Optional.ofNullable(dto.getCjsj()).filter(StringUtils::hasText).ifPresent(cjsj -> oldLtd.setEntryTime(LocalDateTime.parse(cjsj.substring(0, 19), DATE_TIME_FORMATTER))); // 录入时间
|
||||||
|
Optional.ofNullable(dto.getXgsj()).filter(StringUtils::hasText).ifPresent(xgsj -> oldLtd.setModifyTime(LocalDateTime.parse(xgsj.substring(0, 19), DATE_TIME_FORMATTER)));// 修改时间
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.info("时间转换问题:{}", e);
|
||||||
|
}
|
||||||
|
//oldLtd.setModifyUserName(); // 修改用户名
|
||||||
|
//oldLtd.setModifyNickName(); // 修改用户昵称
|
||||||
|
//oldLtd.setDataSource(); // 数据来源
|
||||||
|
//oldLtd.setDelFlag(); // 是否删除
|
||||||
|
//oldLtd.setIsRemove(); // 是否移除计划清单
|
||||||
|
oldLtd.setPumpTime(now); // 抽取时间
|
||||||
|
//oldLtd.setShortName(); // 单位简称
|
||||||
|
oldLtd.setContactPerson(dto.getZyfzr()); // 单位联系人
|
||||||
|
oldLtd.setContactPhone(dto.getZyfzrlxdh()); // 联系电话
|
||||||
|
//oldLtd.setDynamicRiskLevel(); // 动态风险等级
|
||||||
|
//oldLtd.setBusinessScope(); // 经营范围
|
||||||
|
//oldLtd.setTown(); // 所在乡镇
|
||||||
|
//oldLtd.setVillage(); // 所在村
|
||||||
|
oldLtd.setStreet(dto.getXzjdmc()); // 所在街道
|
||||||
|
//oldLtd.setRiskCategory(); // 风险类别
|
||||||
|
//oldLtd.setUnitType(); // 单位类型
|
||||||
|
if ("0".equals(dto.getScjyztxh())) { // 运营状态
|
||||||
|
oldLtd.setOperationStatus("正常");
|
||||||
|
} else {
|
||||||
|
oldLtd.setOperationStatus("停业");
|
||||||
|
}
|
||||||
|
//oldLtd.setMunicipalRegulator(); // 市监管部门
|
||||||
|
//oldLtd.setDistrictRegulator(); // 区县监管部门
|
||||||
|
//oldLtd.setDistrictName(); // 区县名称
|
||||||
|
//oldLtd.setVideoAccess("0"); // 视频接入状态
|
||||||
|
//oldLtd.setPerceptionAccess("0"); // 感知接入状态
|
||||||
|
//oldLtd.setInfoAccess("0"); // 资料接入状态
|
||||||
|
//oldLtd.setPermitAccess("0"); // 许可接入状态
|
||||||
|
//oldLtd.setInsEnterprses(); // 巡查企业列表
|
||||||
|
//oldLtd.setIsWithin(); // 是否规上限上企业
|
||||||
|
//oldLtd.setGyqyfl(); // 工业企业分类
|
||||||
|
enterprises.add(oldLtd);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
Enterprise enterprise = new Enterprise();
|
||||||
|
enterprise.setUnitName(dto.getQymc()); // 企业名称
|
||||||
|
enterprise.setUnifiedSocialCode(dto.getTyshxydm()); // 统一社会信用代码
|
||||||
|
if ("0".equals(dto.getScjyztxh())) {
|
||||||
|
enterprise.setBusinessStatus("11"); // 营业状态
|
||||||
|
} else {
|
||||||
|
enterprise.setBusinessStatus("13"); // 营业状态
|
||||||
|
}
|
||||||
|
Optional.ofNullable(dto.getQxbm()).filter(StringUtils::hasText).flatMap(agencyRepo::findByAgencyCode).ifPresent(enterprise::setAgency); // 机构
|
||||||
|
enterprise.setDetailedAddress(dto.getDz()); // 注册详细地址
|
||||||
|
enterprise.setOpLocAddress(dto.getDz()); // 经营详细地址
|
||||||
|
enterprise.setLegalRepresentative(dto.getFddbr()); // 法定代表人姓名
|
||||||
|
enterprise.setLegalPhone(dto.getFddbrlxdh()); // 法人联系电话
|
||||||
|
//国民经济行业分类代码《国民经济行业分类》(GB/T 4754—2017)
|
||||||
|
// if (StringUtils.hasText(dto.getGmjjhyfldm())) {
|
||||||
|
// String xxdm = dictService.getTopXxdm(dto.getGmjjhyfldm());
|
||||||
|
// enterprise.setRegulatedIndustry(xxdm);
|
||||||
|
// String[] ss = xxdm.split("/");
|
||||||
|
// for (int i = 0; i < ss.length; i++) {
|
||||||
|
// if (i == 0) enterprise.setEconCategory(ss[i]); // 国民经济行业分类代码
|
||||||
|
// if (i == 1) enterprise.setEconCategoryTypea(ss[i]); // 国民经济行业分类A型
|
||||||
|
// if (i == 2) enterprise.setEconCategoryTypeb(ss[i]); // 国民经济行业分类B型
|
||||||
|
// if (i == 3) enterprise.setEconCategoryTypec(ss[i]); // 国民经济行业分类C型
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
if(null!=dto.getHylb()&&"1".equals(dto.getHylb())){
|
||||||
|
enterprise.setIndustryType("7"); // 监管行业
|
||||||
|
}else {
|
||||||
|
enterprise.setIndustryType("6"); // 监管行业
|
||||||
|
}
|
||||||
|
|
||||||
|
enterprise.setOpLocArea(dto.getQxmc()); // 经营地址-区
|
||||||
|
if (null!=dto.getJjlxxh()&&StringUtils.hasText(dto.getJjlxxh())) { // 国民经济类型
|
||||||
|
String economicType = dto.getJjlxxh();
|
||||||
|
switch (economicType) {
|
||||||
|
case "110" -> enterprise.setEconomicType("1");
|
||||||
|
case "120" -> enterprise.setEconomicType("2");
|
||||||
|
case "130" -> enterprise.setEconomicType("3");
|
||||||
|
case "140" -> enterprise.setEconomicType("4");
|
||||||
|
case "150" -> enterprise.setEconomicType("5");
|
||||||
|
case "160" -> enterprise.setEconomicType("6");
|
||||||
|
case "170" -> enterprise.setEconomicType("7");
|
||||||
|
case "190" -> enterprise.setEconomicType("8");
|
||||||
|
case "290" -> enterprise.setEconomicType("9");
|
||||||
|
case "310" -> enterprise.setEconomicType("10");
|
||||||
|
case "330" -> enterprise.setEconomicType("11");
|
||||||
|
case "159" -> enterprise.setEconomicType("12");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enterprise.setUnitScale(dto.getQygm()); // 企业规模
|
||||||
|
Optional.ofNullable(dto.getJd()).filter(StringUtils::hasText).ifPresent(enterprise::setLongitude); // 经度
|
||||||
|
Optional.ofNullable(dto.getWd()).filter(StringUtils::hasText).ifPresent(enterprise::setLatitude); // 纬度
|
||||||
|
|
||||||
|
|
||||||
|
enterprise.setRegistrationType(dto.getJjxz()); // 登记注册企业类别
|
||||||
|
enterprise.setEmployeeCount(dto.getZgzrs()); // 从业人员数量
|
||||||
|
enterprise.setIndustryExpandInfos(dto.toString()); // 工贸行业扩展信息
|
||||||
|
enterprise.setMainName(dto.getZyfzr()); // 主要负责人姓名
|
||||||
|
enterprise.setMainPhone(dto.getZyfzrlxdh()); // 主要负责人电话
|
||||||
|
|
||||||
|
try{
|
||||||
|
Optional.ofNullable(dto.getCjsj()).filter(StringUtils::hasText).ifPresent(cjsj->enterprise.setEntryTime(LocalDateTime.parse(cjsj.substring(0,19), DATE_TIME_FORMATTER))); // 录入时间
|
||||||
|
Optional.ofNullable(dto.getXgsj()).filter(StringUtils::hasText).ifPresent(xgsj->enterprise.setModifyTime(LocalDateTime.parse(xgsj.substring(0,19), DATE_TIME_FORMATTER)));// 修改时间
|
||||||
|
}catch (Exception e){
|
||||||
|
log.info("时间转换问题:{}",e);
|
||||||
|
}
|
||||||
|
enterprise.setPumpTime(LocalDateTime.now()); // 抽取时间
|
||||||
|
enterprise.setContactPerson(dto.getZyfzr()); // 单位联系人
|
||||||
|
enterprise.setContactPhone(dto.getZyfzrlxdh()); // 联系电话
|
||||||
|
enterprise.setStreet(dto.getXzjdmc()); // 所在街道
|
||||||
|
if ("0".equals(dto.getScjyztxh())) { // 运营状态
|
||||||
|
enterprise.setOperationStatus("正常");
|
||||||
|
} else {
|
||||||
|
enterprise.setOperationStatus("停业");
|
||||||
|
}
|
||||||
|
enterprises.add(enterprise);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
if (!enterprises.isEmpty()) {
|
||||||
|
transactionTemplate.executeWithoutResult((status) -> enterpriseRepo.saveAll(enterprises));
|
||||||
|
log.info("保存成功:{}条数据", enterprises.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else log.info("没有数据list");
|
||||||
|
} else {
|
||||||
|
log.info("刷新Token");
|
||||||
|
refreshToken();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.info("调用接口失败:{}",e);
|
||||||
|
}
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public boolean updateOrImportWaferEnterprise(int page) {
|
||||||
|
boolean flag = false;
|
||||||
|
try {
|
||||||
|
JSONObject jsonBody = new JSONObject();
|
||||||
|
JSONObject jsonPram = new JSONObject();
|
||||||
|
jsonBody.set("method", "GET");
|
||||||
|
jsonBody.set("jsonObject", jsonPram);
|
||||||
|
jsonBody.set("pageNum", page);
|
||||||
|
jsonBody.set("pageSize", 1000);
|
||||||
|
jsonBody.set("path", "/edataservice/api/whqyjbxx");
|
||||||
|
jsonBody.set("secret", "41982853a9e69e48c6eb73e1a80695ae58cb4fdc914137c55d6219ae4ea49579");
|
||||||
|
String body = HttpUtil.createPost("http://10.22.245.216:29999/jeecg-data-service/edataservice/api/")
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.body(jsonBody.toString())
|
||||||
|
.execute()
|
||||||
|
.body();
|
||||||
|
JsonNode jsonNode = objectMapper.readValue(body, JsonNode.class);
|
||||||
|
if (jsonNode.has("code") && 200 == jsonNode.get("code").asInt() && jsonNode.has("result")) {
|
||||||
|
JsonNode data = objectMapper.readValue(jsonNode.get("result").toString(), JsonNode.class);
|
||||||
|
|
||||||
|
if (null != data && data.has("records")) {
|
||||||
|
JsonNode arrNode = data.get("records");
|
||||||
|
|
||||||
|
if (arrNode.isArray()) {
|
||||||
|
long current = data.get("current").asLong();
|
||||||
|
long pages = data.get("pages").asLong();
|
||||||
|
if (current < pages) flag = true;
|
||||||
|
List<WaferEnterpriseDto> dtos = objectMapper.readValue(arrNode.toString(), new TypeReference<>() {});
|
||||||
|
|
||||||
|
Set<String> usccSet = dtos.stream().map(WaferEnterpriseDto::getTyshxydm).filter(StringUtils::hasText).collect(Collectors.toSet());
|
||||||
|
// 历史企业
|
||||||
|
List<Enterprise> enterpriseList = enterpriseRepo.findByUnifiedSocialCodeIn(usccSet);
|
||||||
|
List<Enterprise> enterprises = new ArrayList<>();
|
||||||
|
|
||||||
|
for (WaferEnterpriseDto dto : dtos) {
|
||||||
|
if (StringUtils.hasText(dto.getTyshxydm())) {
|
||||||
|
Enterprise oldLtd = enterpriseList.stream().filter(o -> o.getUnifiedSocialCode().equals(dto.getTyshxydm())).findFirst().orElse(null);
|
||||||
|
if (null != oldLtd) {
|
||||||
|
EnterpriseHistory history = new EnterpriseHistory();
|
||||||
|
BeanUtils.copyProperties(oldLtd, history);
|
||||||
|
history.setTheType("定时任务修改");
|
||||||
|
LocalDateTime now = LocalDateTime.now();
|
||||||
|
history.setHistoryTime(now);
|
||||||
|
enterpriseHistoryRepo.save(history);
|
||||||
|
|
||||||
|
oldLtd.setUnitName(dto.getQymc()); // 企业名称
|
||||||
|
oldLtd.setUnifiedSocialCode(dto.getTyshxydm()); // 统一社会信用代码
|
||||||
|
if ("opening".equals(dto.getYyzt())) {
|
||||||
|
oldLtd.setBusinessStatus("11"); // 营业状态
|
||||||
|
} else {
|
||||||
|
oldLtd.setBusinessStatus("13"); // 营业状态
|
||||||
|
}
|
||||||
|
Optional.ofNullable(dto.getQxdm()).filter(StringUtils::hasText).ifPresent(qxbm-> oldLtd.setAgency(agencyRepo.findLikeAgencyCode("%"+qxbm+"%",3).stream().findFirst().orElse(null)));
|
||||||
|
//oldLtd.setRegulatedIndustry(); // 国民经济行业分类
|
||||||
|
//oldLtd.setAreaComb(); // 注册地址(全)
|
||||||
|
oldLtd.setDetailedAddress(dto.getZcdz()); // 注册详细地址
|
||||||
|
//oldLtd.setOpLocAreaComb(); // 经营地址(全)
|
||||||
|
oldLtd.setOpLocAddress(dto.getJydz()); // 经营详细地址
|
||||||
|
|
||||||
|
if(null != dto.getJghylbxl()){
|
||||||
|
if(dto.getJghylbxl().contains("E040101")){
|
||||||
|
oldLtd.setIndustryType("2"); // 监管行业 危险化学品生产
|
||||||
|
}
|
||||||
|
else if(dto.getJghylbxl().contains("E040102")){
|
||||||
|
oldLtd.setIndustryType("3"); // 监管行业 危险化学品经营(仓储)
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
oldLtd.setIndustryType("4"); // 监管行业 危险化学品经营(无仓储)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
oldLtd.setLegalRepresentative(dto.getFddbr()); // 法定代表人姓名
|
||||||
|
//oldLtd.setLegalPhone(dto.getFddbrlxdh()); // 法人联系电话
|
||||||
|
//oldLtd.setLegalDuty(); // 法定代表人职位
|
||||||
|
//oldLtd.setOpScope(dto.getJyfw()); // 主营业务
|
||||||
|
//oldLtd.setAffiliation(); // 行政隶属关系
|
||||||
|
//oldLtd.setOilExtract(); // 是否石油开采
|
||||||
|
//oldLtd.setSafetyFocus(); // 是否安全生产监管重点企业
|
||||||
|
//oldLtd.setIsScaleEnterprise(); // 是否规模以上企业
|
||||||
|
//oldLtd.setSafetyLic(); // 是否有安全生产许可证
|
||||||
|
oldLtd.setProvince(dto.getSjdmmc()); // 注册地址-省
|
||||||
|
oldLtd.setCity(dto.getSjdm01mc()); // 注册地址-市
|
||||||
|
oldLtd.setCounty(dto.getXjdmmc()); // 注册地址-县/区
|
||||||
|
oldLtd.setAreaComb(dto.getSjdmmc()+"/"+dto.getSjdm01mc()+"/"+dto.getXjdmmc());
|
||||||
|
oldLtd.setEconCategory(dto.getMllb());
|
||||||
|
//国民经济行业分类代码《国民经济行业分类》(GB/T 4754—2017)
|
||||||
|
StringBuilder regulatedIndustryStr = new StringBuilder(dto.getMllb());
|
||||||
|
Optional.ofNullable(dto.getDllb()).filter(StringUtils::hasText).ifPresent(s-> {
|
||||||
|
oldLtd.setEconCategoryTypea(s.substring(1));
|
||||||
|
regulatedIndustryStr.append("/"+s);
|
||||||
|
});
|
||||||
|
Optional.ofNullable(dto.getZllb()).filter(StringUtils::hasText).ifPresent(s-> {
|
||||||
|
oldLtd.setEconCategoryTypeb(s.substring(1));
|
||||||
|
regulatedIndustryStr.append("/"+s);
|
||||||
|
});
|
||||||
|
Optional.ofNullable(dto.getXllb()).filter(StringUtils::hasText).ifPresent(s-> {
|
||||||
|
oldLtd.setEconCategoryTypec(s.substring(1));
|
||||||
|
regulatedIndustryStr.append("/"+s);
|
||||||
|
});
|
||||||
|
oldLtd.setRegulatedIndustry(regulatedIndustryStr.toString());
|
||||||
|
|
||||||
|
//oldLtd.setOpLocProvince(); // 经营地址-省
|
||||||
|
//oldLtd.setOpLocCity(); // 经营地址-市
|
||||||
|
//oldLtd.setOpLocArea(dto.getQxmc()); // 经营地址-区
|
||||||
|
//oldLtd.setBusinessRating(); // 企业分级
|
||||||
|
//oldLtd.setBusinessCategory(); // 企业分类
|
||||||
|
//oldLtd.setPostalCode(); // 邮政编码
|
||||||
|
|
||||||
|
//oldLtd.setLegalPersonIdType(); // 法定代表人证件类型
|
||||||
|
//oldLtd.setLegalPersonIdNumber(); // 法定代表人证件号码
|
||||||
|
//oldLtd.setIsInChemicalPark(); // 是否位于化工园区
|
||||||
|
//oldLtd.setExpiryDate(); // 营业执照有效期
|
||||||
|
oldLtd.setOrgCode(dto.getZzjgdm()); // 组织机构代码
|
||||||
|
oldLtd.setUnitScale(dto.getQygmmc()); // 企业规模
|
||||||
|
oldLtd.setEstablishmentDate(dto.getClrq()); // 成立日期
|
||||||
|
//oldLtd.setRegisteredCapital(); // 注册资本(万元)
|
||||||
|
oldLtd.setLongitude(dto.getJd()); // 经度
|
||||||
|
oldLtd.setLatitude(dto.getWd()); // 纬度
|
||||||
|
//oldLtd.setRegistrationType(dto.getJjxz()); // 登记注册企业类别
|
||||||
|
//oldLtd.setLicenseNumber(); // 许可证编号
|
||||||
|
//oldLtd.setSafetyLevel(); // 安全生产标准化等级
|
||||||
|
//oldLtd.setIssuingAuthority(); // 发证机关
|
||||||
|
//oldLtd.setEmployeeCount(dto.getZgzrs()); // 从业人员数量
|
||||||
|
//oldLtd.setIsTraining(); // 是否为培训机构
|
||||||
|
//oldLtd.setProductionManageInfoExp(); // 安全基础管理信息
|
||||||
|
//oldLtd.setProductionEquipmentExp(); // 生产设备设施信息
|
||||||
|
//oldLtd.setNocoalIndustryExpansion(); // 非煤行业扩展信息
|
||||||
|
oldLtd.setDangerFeatureInfo(dto.toString()); // 危化行业扩展信息
|
||||||
|
//oldLtd.setFireworksAddInfo(); // 烟花爆竹行业扩展信息
|
||||||
|
//oldLtd.setIndustryExpandInfos(dto.toString()); // 工贸行业扩展信息
|
||||||
|
//oldLtd.setMainName(dto.getLxr()); // 主要负责人姓名
|
||||||
|
//oldLtd.setMainPhone(dto.getLxdh()); // 主要负责人电话
|
||||||
|
//oldLtd.setMajorAccidentHazard(); // 重大事故隐患年份
|
||||||
|
//oldLtd.setMajorDanger(); // 是否有重大危险源
|
||||||
|
//oldLtd.setInterid(dto.getYwlsh()); // 第三方对接ID
|
||||||
|
//oldLtd.setEntryTime(dto.getCjsj()); // 录入时间
|
||||||
|
//oldLtd.setEntryUserName(); // 录入用户名
|
||||||
|
//oldLtd.setEntryNickName(); // 录入用户昵称
|
||||||
|
//oldLtd.setModifyTime(dto.getXgsj()); // 修改时间
|
||||||
|
//oldLtd.setModifyUserName(); // 修改用户名
|
||||||
|
//oldLtd.setModifyNickName(); // 修改用户昵称
|
||||||
|
//oldLtd.setDataSource(); // 数据来源
|
||||||
|
//oldLtd.setDelFlag(); // 是否删除
|
||||||
|
//oldLtd.setIsRemove(); // 是否移除计划清单
|
||||||
|
oldLtd.setPumpTime(now); // 抽取时间
|
||||||
|
//oldLtd.setShortName(); // 单位简称
|
||||||
|
oldLtd.setContactPerson(dto.getLxr()); // 单位联系人
|
||||||
|
oldLtd.setContactPhone(dto.getLxdh()); // 联系电话
|
||||||
|
oldLtd.setDynamicRiskLevel(dto.getDtfxdjmc()); // 动态风险等级
|
||||||
|
oldLtd.setBusinessScope(dto.getJyfw()); // 经营范围
|
||||||
|
//oldLtd.setTown(); // 所在乡镇
|
||||||
|
//oldLtd.setVillage(); // 所在村
|
||||||
|
oldLtd.setStreet(dto.getJdmc()); // 所在街道
|
||||||
|
//oldLtd.setRiskCategory(); // 风险类别
|
||||||
|
//oldLtd.setUnitType(); // 单位类型
|
||||||
|
// if ("0".equals(dto.getScjyztxh())) { // 运营状态
|
||||||
|
// oldLtd.setOperationStatus("正常");
|
||||||
|
// } else {
|
||||||
|
// oldLtd.setOperationStatus("停业");
|
||||||
|
// }
|
||||||
|
//oldLtd.setMunicipalRegulator(); // 市监管部门
|
||||||
|
//oldLtd.setDistrictRegulator(); // 区县监管部门
|
||||||
|
//oldLtd.setDistrictName(); // 区县名称
|
||||||
|
//oldLtd.setVideoAccess("0"); // 视频接入状态
|
||||||
|
//oldLtd.setPerceptionAccess("0"); // 感知接入状态
|
||||||
|
//oldLtd.setInfoAccess("0"); // 资料接入状态
|
||||||
|
//oldLtd.setPermitAccess("0"); // 许可接入状态
|
||||||
|
//oldLtd.setInsEnterprses(); // 巡查企业列表
|
||||||
|
//oldLtd.setIsWithin(); // 是否规上限上企业
|
||||||
|
//oldLtd.setGyqyfl(); // 工业企业分类
|
||||||
|
enterprises.add(oldLtd);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Enterprise enterprise = new Enterprise();
|
||||||
|
enterprise.setUnitName(dto.getQymc()); // 企业名称
|
||||||
|
enterprise.setUnifiedSocialCode(dto.getTyshxydm()); // 统一社会信用代码
|
||||||
|
|
||||||
|
enterprise.setUnitName(dto.getQymc()); // 企业名称
|
||||||
|
enterprise.setUnifiedSocialCode(dto.getTyshxydm()); // 统一社会信用代码
|
||||||
|
if ("opening".equals(dto.getYyzt())) {
|
||||||
|
enterprise.setBusinessStatus("11"); // 营业状态
|
||||||
|
} else {
|
||||||
|
enterprise.setBusinessStatus("13"); // 营业状态
|
||||||
|
}
|
||||||
|
Optional.ofNullable(dto.getQxdm()).filter(StringUtils::hasText).ifPresent(qxbm-> enterprise.setAgency(agencyRepo.findLikeAgencyCode("%"+qxbm+"%",3).stream().findFirst().orElse(null)));
|
||||||
|
enterprise.setDetailedAddress(dto.getZcdz()); // 注册详细地址
|
||||||
|
//oldLtd.setOpLocAreaComb(); // 经营地址(全)
|
||||||
|
enterprise.setOpLocAddress(dto.getJydz()); // 经营详细地址
|
||||||
|
if(null!=dto.getJghylbxl()){
|
||||||
|
if(dto.getJghylbxl().contains("E040101")){
|
||||||
|
enterprise.setIndustryType("2"); // 监管行业 危险化学品生产
|
||||||
|
}
|
||||||
|
else if(dto.getJghylbxl().contains("E040102")){
|
||||||
|
enterprise.setIndustryType("3"); // 监管行业 危险化学品经营(仓储)
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
enterprise.setIndustryType("4"); // 监管行业 危险化学品经营(无仓储)
|
||||||
|
}
|
||||||
|
|
||||||
|
enterprise.setLegalRepresentative(dto.getFddbr()); // 法定代表人姓名
|
||||||
|
enterprise.setDangerFeatureInfo(dto.toString()); // 危化行业扩展信息
|
||||||
|
enterprise.setProvince(dto.getSjdmmc()); // 注册地址-省
|
||||||
|
enterprise.setCity(dto.getSjdm01mc()); // 注册地址-市
|
||||||
|
enterprise.setCounty(dto.getXjdmmc()); // 注册地址-县/区
|
||||||
|
enterprise.setAreaComb(dto.getSjdmmc()+"/"+dto.getSjdm01mc()+"/"+dto.getXjdmmc());
|
||||||
|
enterprise.setEconCategory(dto.getMllb());
|
||||||
|
//国民经济行业分类代码《国民经济行业分类》(GB/T 4754—2017)
|
||||||
|
StringBuilder regulatedIndustryStr = new StringBuilder(dto.getMllb());
|
||||||
|
Optional.ofNullable(dto.getDllb()).filter(StringUtils::hasText).ifPresent(s-> {
|
||||||
|
enterprise.setEconCategoryTypea(s.substring(1));
|
||||||
|
regulatedIndustryStr.append("/"+s);
|
||||||
|
});
|
||||||
|
Optional.ofNullable(dto.getZllb()).filter(StringUtils::hasText).ifPresent(s-> {
|
||||||
|
enterprise.setEconCategoryTypeb(s.substring(1));
|
||||||
|
regulatedIndustryStr.append("/"+s);
|
||||||
|
});
|
||||||
|
Optional.ofNullable(dto.getXllb()).filter(StringUtils::hasText).ifPresent(s-> {
|
||||||
|
enterprise.setEconCategoryTypec(s.substring(1));
|
||||||
|
regulatedIndustryStr.append("/"+s);
|
||||||
|
});
|
||||||
|
enterprise.setRegulatedIndustry(regulatedIndustryStr.toString());
|
||||||
|
|
||||||
|
|
||||||
|
enterprise.setOrgCode(dto.getZzjgdm()); // 组织机构代码
|
||||||
|
enterprise.setUnitScale(dto.getQygmmc()); // 企业规模
|
||||||
|
enterprise.setEstablishmentDate(dto.getClrq()); // 成立日期
|
||||||
|
enterprise.setLongitude(dto.getJd()); // 经度
|
||||||
|
enterprise.setLatitude(dto.getWd()); // 纬度
|
||||||
|
|
||||||
|
|
||||||
|
enterprise.setIndustryExpandInfos(dto.toString()); // 工贸行业扩展信息
|
||||||
|
|
||||||
|
enterprise.setPumpTime(LocalDateTime.now()); // 抽取时间
|
||||||
|
|
||||||
|
enterprise.setContactPerson(dto.getLxr()); // 单位联系人
|
||||||
|
enterprise.setContactPhone(dto.getLxdh()); // 联系电话
|
||||||
|
enterprise.setDynamicRiskLevel(dto.getDtfxdjmc()); // 动态风险等级
|
||||||
|
enterprise.setBusinessScope(dto.getJyfw()); // 经营范围
|
||||||
|
|
||||||
|
enterprise.setStreet(dto.getJdmc()); // 所在街道
|
||||||
|
enterprises.add(enterprise);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (!enterprises.isEmpty()) {
|
||||||
|
transactionTemplate.executeWithoutResult((status) -> enterpriseRepo.saveAll(enterprises));
|
||||||
|
log.info("保存成功:{}条数据", enterprises.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else log.info("没有数据list");
|
||||||
|
} else {
|
||||||
|
log.info("刷新Token");
|
||||||
|
refreshToken();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.info("危化企业信息查询查询异常:" + e);
|
||||||
|
}
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,778 @@
|
||||||
|
package com.aisino.iles.lawenforcement.schedule.service;
|
||||||
|
|
||||||
|
import cn.hutool.http.HttpUtil;
|
||||||
|
import com.aisino.iles.lawenforcement.model.*;
|
||||||
|
import com.aisino.iles.lawenforcement.model.dto.EnterpriseInterfaceDto;
|
||||||
|
import com.aisino.iles.lawenforcement.repository.*;
|
||||||
|
import com.aisino.iles.lawenforcement.service.AuthService;
|
||||||
|
import com.aisino.iles.lawenforcement.service.DictInterfaceService;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.smartlx.sso.client.model.AccessToken;
|
||||||
|
import com.smartlx.sso.client.properties.SsoClientProperties;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 企业信息定时任务
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class EnterpriseScheduleService {
|
||||||
|
private final EnterpriseRepository enterpriseRepo;
|
||||||
|
private final EnterpriseHistoryRepository enterpriseHistoryRepo;
|
||||||
|
private final AdministrativeLicenseRepository administrativeLicenseRepo;
|
||||||
|
private final AccidentHazardRepository accidentHazardRepo;
|
||||||
|
private final DangerInfoRepository dangerInfoRepo;
|
||||||
|
private final AgencyRepository agencyRepo;
|
||||||
|
private final SsoClientProperties ssoClientProperties;
|
||||||
|
private final TransactionTemplate transactionTemplate;
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
private final AuthService authService;
|
||||||
|
private final String queryUrl;
|
||||||
|
private final String mobilePhone;
|
||||||
|
private String accessToken;
|
||||||
|
private String tokenType;
|
||||||
|
private String refreshToken;
|
||||||
|
private final String produceLicensePage;
|
||||||
|
private final String hazardPage;
|
||||||
|
private final String sourcesDangerPage;
|
||||||
|
private final DictInterfaceService dictService;
|
||||||
|
private final DateTimeFormatter yyyy = DateTimeFormatter.ofPattern("yyyy");
|
||||||
|
|
||||||
|
public EnterpriseScheduleService(EnterpriseRepository enterpriseRepo,
|
||||||
|
EnterpriseHistoryRepository enterpriseHistoryRepo,
|
||||||
|
AdministrativeLicenseRepository administrativeLicenseRepo,
|
||||||
|
AccidentHazardRepository accidentHazardRepo,
|
||||||
|
DangerInfoRepository dangerInfoRepo,
|
||||||
|
AgencyRepository agencyRepo,
|
||||||
|
@Value("${third-party.enterprise.query:}") String queryUrl,
|
||||||
|
@Value("${third-party.enterprise.yddh:}") String mobilePhone,
|
||||||
|
SsoClientProperties ssoClientProperties,
|
||||||
|
TransactionTemplate transactionTemplate,
|
||||||
|
ObjectMapper objectMapper,
|
||||||
|
AuthService authService,
|
||||||
|
@Value("${third-party.enterprise.produceLicensePage:}") String produceLicensePage,
|
||||||
|
@Value("${third-party.enterprise.hazardPage:}") String hazardPage,
|
||||||
|
@Value("${third-party.enterprise.sourcesDangerPage:}") String sourcesDangerPage,
|
||||||
|
DictInterfaceService dictService) {
|
||||||
|
this.enterpriseRepo = enterpriseRepo;
|
||||||
|
this.enterpriseHistoryRepo = enterpriseHistoryRepo;
|
||||||
|
this.administrativeLicenseRepo = administrativeLicenseRepo;
|
||||||
|
this.accidentHazardRepo = accidentHazardRepo;
|
||||||
|
this.dangerInfoRepo = dangerInfoRepo;
|
||||||
|
this.agencyRepo = agencyRepo;
|
||||||
|
this.queryUrl = queryUrl;
|
||||||
|
this.ssoClientProperties = ssoClientProperties;
|
||||||
|
this.transactionTemplate = transactionTemplate;
|
||||||
|
this.objectMapper = objectMapper;
|
||||||
|
this.mobilePhone = mobilePhone;
|
||||||
|
this.authService = authService;
|
||||||
|
this.produceLicensePage = produceLicensePage;
|
||||||
|
this.hazardPage = hazardPage;
|
||||||
|
this.sourcesDangerPage = sourcesDangerPage;
|
||||||
|
this.dictService = dictService;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工作台信息导入
|
||||||
|
* 每天10点执行一次
|
||||||
|
* (cron = "0 0 15 * * ?")
|
||||||
|
* (cron = "${scheduler.expression}")
|
||||||
|
* (fixedRate = 120000)
|
||||||
|
*/
|
||||||
|
@Scheduled(cron = "${scheduler.task.enterprise.cron.expression}")
|
||||||
|
public void scheduledEnterpriseTask() {
|
||||||
|
getToken();
|
||||||
|
dictService.getDictItem("YJ_CODE_9017", tokenType, accessToken);
|
||||||
|
// enterpriseTask();
|
||||||
|
administrativeLicenseTask();
|
||||||
|
accidentHazardTask();
|
||||||
|
dangerInfoTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导入企业信息
|
||||||
|
*/
|
||||||
|
private void enterpriseTask() {
|
||||||
|
log.info("开始导入企业信息...");
|
||||||
|
int page = 1;
|
||||||
|
boolean b = importEnterprise(page);
|
||||||
|
while (b) {
|
||||||
|
page++;
|
||||||
|
b = importEnterprise(page);
|
||||||
|
}
|
||||||
|
log.info("企业信息导入完成...");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新token
|
||||||
|
*/
|
||||||
|
private void refreshToken() {
|
||||||
|
try {
|
||||||
|
authService.refreshTokenBackend(accessToken, tokenType, refreshToken, mobilePhone);
|
||||||
|
// 刷新后重新获取token
|
||||||
|
getToken();
|
||||||
|
log.info("刷新token成功");
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("刷新token失败,尝试重新获取token", e);
|
||||||
|
getToken();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取token
|
||||||
|
*/
|
||||||
|
private void getToken() {
|
||||||
|
try {
|
||||||
|
AccessToken accessTokenObj = authService.getTokenBackend(mobilePhone);
|
||||||
|
if (accessTokenObj != null) {
|
||||||
|
accessToken = accessTokenObj.getAccess_token();
|
||||||
|
tokenType = accessTokenObj.getToken_type();
|
||||||
|
refreshToken = accessTokenObj.getRefresh_token();
|
||||||
|
log.info("获取token成功");
|
||||||
|
} else {
|
||||||
|
log.error("获取token失败,返回为null");
|
||||||
|
throw new RuntimeException("无法获取有效的访问令牌");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("获取token失败", e);
|
||||||
|
throw new RuntimeException("无法获取有效的访问令牌", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean importEnterprise(int page) {
|
||||||
|
boolean goon = false;
|
||||||
|
try {
|
||||||
|
String body = HttpUtil.createPost(queryUrl)
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.header("Authorization", tokenType + " " + accessToken)
|
||||||
|
.header("appId", ssoClientProperties.getClientId())
|
||||||
|
.body("{\"page\": " + page + ",\"limit\": 1000,\"entity\": {}}")
|
||||||
|
.execute()
|
||||||
|
.body();
|
||||||
|
log.info("企业信息查询结果:{}", body);
|
||||||
|
JsonNode jsonNode = objectMapper.readValue(body, JsonNode.class);
|
||||||
|
if (jsonNode.has("code") && 200 == jsonNode.get("code").asInt() && jsonNode.has("data")) {
|
||||||
|
JsonNode data = objectMapper.readValue(jsonNode.get("data").toString(), JsonNode.class);
|
||||||
|
if (null != data && data.has("list")) {
|
||||||
|
JsonNode arrNode = data.get("list");
|
||||||
|
if (arrNode.isArray()) {
|
||||||
|
long total = data.get("totalCount").asLong();
|
||||||
|
int limit = data.get("limit").asInt();
|
||||||
|
if (total > limit && arrNode.size() >= limit)
|
||||||
|
goon = true;
|
||||||
|
List<Enterprise> enterprises = new ArrayList<>();
|
||||||
|
List<EnterpriseInterfaceDto> dtos = objectMapper.readValue(arrNode.toString(), new TypeReference<>() {
|
||||||
|
});
|
||||||
|
Set<String> usccSet = dtos.stream().map(EnterpriseInterfaceDto::getTyshxydm).filter(StringUtils::hasText).collect(Collectors.toSet());
|
||||||
|
List<Enterprise> enterpriseList = enterpriseRepo.findByUnifiedSocialCodeIn(usccSet);
|
||||||
|
for (EnterpriseInterfaceDto dto : dtos) {
|
||||||
|
if (StringUtils.hasText(dto.getTyshxydm())) {
|
||||||
|
Enterprise oldLtd = enterpriseList.stream().filter(o -> o.getUnifiedSocialCode().equals(dto.getTyshxydm())).findFirst().orElse(null);
|
||||||
|
if (null == oldLtd || !"31".equals(oldLtd.getDataSource())) {
|
||||||
|
Enterprise enterprise = new Enterprise();
|
||||||
|
LocalDateTime now = LocalDateTime.now();
|
||||||
|
if (null != oldLtd) {
|
||||||
|
BeanUtils.copyProperties(oldLtd, enterprise);
|
||||||
|
EnterpriseHistory history = new EnterpriseHistory();
|
||||||
|
BeanUtils.copyProperties(enterprise, history);
|
||||||
|
history.setTheType("定时任务修改");
|
||||||
|
history.setHistoryTime(now);
|
||||||
|
enterpriseHistoryRepo.save(history);
|
||||||
|
} else {
|
||||||
|
enterprise.setIsWithin("0");
|
||||||
|
enterprise.setPumpTime(now);
|
||||||
|
enterprise.setBusinessCategory("1");
|
||||||
|
}
|
||||||
|
enterprise.setEntryUserName(dto.getCjrYhwybs());//创建人用户唯一标识
|
||||||
|
if (null != dto.getCjsj()) {
|
||||||
|
enterprise.setEntryTime(dto.getCjsj());//创建时间
|
||||||
|
enterprise.setModifyUserName(dto.getGxrYhwybs());//更新人用户唯一标识
|
||||||
|
if (null != dto.getGxsj()) enterprise.setModifyTime(dto.getGxsj());//更新时间
|
||||||
|
else enterprise.setModifyTime(dto.getCjsj());
|
||||||
|
} else {
|
||||||
|
enterprise.setEntryTime(now);//创建时间
|
||||||
|
enterprise.setModifyTime(now);
|
||||||
|
}
|
||||||
|
enterprise.setUnitName(dto.getQymc());//企业名称
|
||||||
|
enterprise.setUnifiedSocialCode(dto.getTyshxydm());//统一社会信用代码
|
||||||
|
enterprise.setShortName(dto.getQyjc());//企业简称
|
||||||
|
enterprise.setUnitScale(dto.getQygm());//企业规模代码
|
||||||
|
enterprise.setEmployeeCount(dto.getZgrs());//职工人数
|
||||||
|
enterprise.setDetailedAddress(dto.getZcdzXxdz());//注册地址详细地址
|
||||||
|
enterprise.setAreaComb(dto.getZcdzXzqhdm());//注册地址行政区划代码
|
||||||
|
enterprise.setOpLocAddress(dto.getScjydzXxdz());//生产经营地址详细地址
|
||||||
|
enterprise.setOpLocAreaComb(dto.getScjydzXzqhdm());//生产经营地址行政区划代码
|
||||||
|
enterprise.setOpScope(dto.getJyfw());//经营范围
|
||||||
|
Optional.ofNullable(dto.getYygldwZzjgdm()).filter(StringUtils::hasText).flatMap(agencyRepo::findByAgencyCode).ifPresent(enterprise::setAgency);//发证机关代码
|
||||||
|
if (StringUtils.hasText(dto.getGmjjhyfldm())) {//国民经济行业分类代码《国民经济行业分类》(GB/T 4754—2017)
|
||||||
|
String xxdm = dictService.getTopXxdm(dto.getGmjjhyfldm());
|
||||||
|
enterprise.setRegulatedIndustry(xxdm);
|
||||||
|
String[] ss = xxdm.split("/");
|
||||||
|
for (int i = 0; i < ss.length; i++) {
|
||||||
|
if (i == 0) enterprise.setEconCategory(ss[i]);
|
||||||
|
if (i == 1) enterprise.setEconCategoryTypea(ss[i]);
|
||||||
|
if (i == 2) enterprise.setEconCategoryTypeb(ss[i]);
|
||||||
|
if (i == 3) enterprise.setEconCategoryTypec(ss[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enterprise.setOrgCode(dto.getFzjgdm());//应急管理单位组织机构代码
|
||||||
|
enterprise.setLegalRepresentative(dto.getLxrxm());//企业联系人
|
||||||
|
Optional.ofNullable(dto.getScjydzJd()).filter(StringUtils::hasText).ifPresent(enterprise::setLongitude);//经营地址经度
|
||||||
|
Optional.ofNullable(dto.getScjydzWd()).filter(StringUtils::hasText).ifPresent(enterprise::setLatitude);//经营地址纬度
|
||||||
|
Optional.ofNullable(dto.getYyzt()).filter(StringUtils::hasText).ifPresent(o -> {
|
||||||
|
if ("1".equals(o)) enterprise.setBusinessStatus("11");
|
||||||
|
else enterprise.setBusinessStatus("13");
|
||||||
|
});//1-正常(存续、在营、开业、注册、设立);2-异常(未年报、未年检、证书逾期、未年度考核);3-吊销;4-注销/撤销;9-其他
|
||||||
|
String economicType = dto.getJjlxfldm();
|
||||||
|
if (StringUtils.hasText(economicType)) {//经济类型分类代码
|
||||||
|
switch (economicType) {
|
||||||
|
case "110" -> enterprise.setEconomicType("1");
|
||||||
|
case "120" -> enterprise.setEconomicType("2");
|
||||||
|
case "130" -> enterprise.setEconomicType("3");
|
||||||
|
case "140" -> enterprise.setEconomicType("4");
|
||||||
|
case "150" -> enterprise.setEconomicType("5");
|
||||||
|
case "160" -> enterprise.setEconomicType("6");
|
||||||
|
case "170" -> enterprise.setEconomicType("7");
|
||||||
|
case "190" -> enterprise.setEconomicType("8");
|
||||||
|
case "290" -> enterprise.setEconomicType("9");
|
||||||
|
case "310" -> enterprise.setEconomicType("10");
|
||||||
|
case "330" -> enterprise.setEconomicType("11");
|
||||||
|
case "159" -> enterprise.setEconomicType("12");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enterprise.setUnitCode(dto.getQybh());
|
||||||
|
enterprise.setMainName(dto.getQyfzrxm());
|
||||||
|
String qyLxdh = dto.getQyLxdh();
|
||||||
|
enterprise.setContactPhone(qyLxdh);
|
||||||
|
enterprise.setMainPhone(qyLxdh);
|
||||||
|
enterprise.setLegalPhone(qyLxdh);
|
||||||
|
enterprise.setContactPerson(dto.getLxrxm());
|
||||||
|
if (null != dto.getClrq())
|
||||||
|
enterprise.setEstablishmentDate(LocalDate.from(dto.getClrq()));//成立日期
|
||||||
|
if (null != dto.getZczb())
|
||||||
|
enterprise.setRegisteredCapital(BigDecimal.valueOf(dto.getZczb()));//注册资本
|
||||||
|
if (null != dto.getYyqx())
|
||||||
|
enterprise.setExpiryDate(LocalDate.from(dto.getYyqx()));//营业期限
|
||||||
|
//1-工贸企业 2-危化企业 3-矿山企业 4-建筑施工企业 5-民用爆炸物企业 6-食品药品企业 7-交通运输企业
|
||||||
|
//1-矿山 2-危险化学品生产 3-危险化学品经营(仓储) 4-危险化学品经营(无仓储) 5-加油站 6-工业企业 7-商贸企业 8-安全生产中介机构 9-安全生产检验检测机构 10-安全生产培训机构 99-其他
|
||||||
|
String gllx = dto.getGllx();//管理类型代码
|
||||||
|
Optional.ofNullable(gllx).ifPresentOrElse(o -> {
|
||||||
|
switch (o) {
|
||||||
|
case "1" -> enterprise.setIndustryType("6");
|
||||||
|
case "3" -> enterprise.setIndustryType("1");
|
||||||
|
case "2" -> enterprise.setIndustryType("2");
|
||||||
|
default -> enterprise.setIndustryType("99");
|
||||||
|
}
|
||||||
|
}, () -> enterprise.setIndustryType("99"));
|
||||||
|
if (enterprise.getUnitName().contains("加油站"))
|
||||||
|
enterprise.setIndustryType("5");
|
||||||
|
enterprise.setIsRemove((short) 0);
|
||||||
|
if ("0".equals(dto.getSjyxx()))
|
||||||
|
enterprise.setDelFlag((short) 1);
|
||||||
|
else enterprise.setDelFlag((short) 0);
|
||||||
|
if ("5".equals(enterprise.getIndustryType()))
|
||||||
|
enterprise.setBusinessCategory("2");
|
||||||
|
else enterprise.setBusinessCategory("1");
|
||||||
|
enterprise.setDataSource("3");
|
||||||
|
enterprise.setInterid(dto.getYwlsh());
|
||||||
|
enterprises.add(enterprise);
|
||||||
|
}
|
||||||
|
} else log.info("统一信用代码为空:{}", dto.getYwlsh());
|
||||||
|
}
|
||||||
|
int i = 0;
|
||||||
|
if (!enterprises.isEmpty()) {
|
||||||
|
i++;
|
||||||
|
transactionTemplate.executeWithoutResult((status) -> enterpriseRepo.saveAll(enterprises));
|
||||||
|
log.info("成功次数:{}", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else log.info("没有数据list");
|
||||||
|
} else {
|
||||||
|
log.info("刷新Token");
|
||||||
|
refreshToken();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.info("企业查询异常:" + e);
|
||||||
|
}
|
||||||
|
return goon;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 企业生产许可信息导入
|
||||||
|
*/
|
||||||
|
public void administrativeLicenseTask() {
|
||||||
|
log.info("开始企业生产许可信息导入...");
|
||||||
|
int page = 1;
|
||||||
|
boolean b = importAdministrativeLicense(page);
|
||||||
|
while (b) {
|
||||||
|
page++;
|
||||||
|
b = importAdministrativeLicense(page);
|
||||||
|
}
|
||||||
|
log.info("企业生产许可信息导入完成...");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean importAdministrativeLicense(int page) {
|
||||||
|
boolean goon = false;
|
||||||
|
try {
|
||||||
|
String body = HttpUtil.createPost(produceLicensePage)
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.header("Authorization", tokenType + " " + accessToken)
|
||||||
|
.header("appId", ssoClientProperties.getClientId())
|
||||||
|
.body("{\"page\": " + page + ",\"limit\": 1000,\"entity\": {}}")
|
||||||
|
.execute()
|
||||||
|
.body();
|
||||||
|
log.info("生产许可查询结果:{}", body);
|
||||||
|
JsonNode jsonNode = objectMapper.readValue(body, JsonNode.class);
|
||||||
|
if (jsonNode.has("code") && 200 == jsonNode.get("code").asInt() && jsonNode.has("data")) {
|
||||||
|
JsonNode data = objectMapper.readValue(jsonNode.get("data").toString(), JsonNode.class);
|
||||||
|
if (null != data && data.has("list")) {
|
||||||
|
JsonNode arrNode = data.get("list");
|
||||||
|
if (arrNode.isArray()) {
|
||||||
|
long total = data.get("totalCount").asLong();
|
||||||
|
int limit = data.get("limit").asInt();
|
||||||
|
if (total > limit && arrNode.size() >= limit)
|
||||||
|
goon = true;
|
||||||
|
List<AdministrativeLicense> licenses = new ArrayList<>();
|
||||||
|
List<AdministrativeLicenseInterfaceDto> dtos = objectMapper.readValue(arrNode.toString(), new TypeReference<>() {
|
||||||
|
});
|
||||||
|
for (AdministrativeLicenseInterfaceDto dto : dtos) {
|
||||||
|
AdministrativeLicense license = new AdministrativeLicense();
|
||||||
|
license.setLicenseNum(dto.getLicensenumber());//": "陕西危化经字【2021】012001",
|
||||||
|
license.setIssuingOffice(dto.getIssuingoffice());//": "西安市应急管理局",
|
||||||
|
if (null != dto.getValidfrom())
|
||||||
|
license.setValidFrom(LocalDate.from(dto.getValidfrom()));//": "2021-06-23 00:00:00",
|
||||||
|
if (null != dto.getValidend())
|
||||||
|
license.setValidFrom(LocalDate.from(dto.getValidend()));//": "2024-06-22 00:00:00",
|
||||||
|
license.setLicenseType(dto.getLicensetype());//": "510400P02",
|
||||||
|
enterpriseRepo.findByUnifiedSocialCode(dto.getUnitid())
|
||||||
|
.ifPresentOrElse(enterprise -> {
|
||||||
|
license.setEnterpriseId(enterprise.getEnterpriseId());
|
||||||
|
if (!StringUtils.hasText(dto.getQymc()))
|
||||||
|
license.setUnitName(enterprise.getUnitName());
|
||||||
|
},
|
||||||
|
() -> {
|
||||||
|
license.setEnterpriseId(dto.getUnitid());
|
||||||
|
license.setUnitName(dto.getQymc());
|
||||||
|
});
|
||||||
|
|
||||||
|
license.setInterid(dto.getId());//": "539392900627437727744",
|
||||||
|
license.setDataScope(dto.getDataScope());//": null,
|
||||||
|
license.setDwdmScope(dto.getDwdmScope());//": null,
|
||||||
|
license.setUsergw(dto.getUsergw());//": null,
|
||||||
|
license.setLicensename(dto.getLicensename());//": "危险化学品经营许可(有仓储)",
|
||||||
|
license.setResponsibleperson(dto.getResponsibleperson());//": null,
|
||||||
|
license.setLicensestatus(dto.getLicensestatus());//": "有效",
|
||||||
|
license.setChangerecord(dto.getChangerecord());//": null,
|
||||||
|
license.setDutydepartmentmanager(dto.getDutydepartmentmanager());//": null,
|
||||||
|
license.setDutypeoplemanager(dto.getDutypeoplemanager());//": null,
|
||||||
|
license.setApplydepartment(dto.getApplydepartment());//": null,
|
||||||
|
license.setReviewcomments(dto.getReviewcomments());//": null,
|
||||||
|
license.setReviewdepartment(dto.getReviewdepartment());//": null,
|
||||||
|
license.setReviewpeople(dto.getReviewpeople());//": null,
|
||||||
|
license.setRectificationnoncompliance(dto.getRectificationnoncompliance());//": null,
|
||||||
|
license.setCreatedby(dto.getCreatedby());//": "262",
|
||||||
|
license.setCreatedon(dto.getCreatedon());//": "2023-10-11 10:08:15",
|
||||||
|
license.setModifiedby(dto.getModifiedby());//": "262",
|
||||||
|
license.setModifiedon(dto.getModifiedon());//": "2023-10-11 10:08:15",
|
||||||
|
license.setDeletestatus(dto.getDeletestatus());//": 0,
|
||||||
|
license.setDataSource(dto.getSjly());//": "危化",
|
||||||
|
license.setPumpTime(LocalDateTime.now());
|
||||||
|
licenses.add(license);
|
||||||
|
}
|
||||||
|
int i = 0;
|
||||||
|
if (!licenses.isEmpty()) {
|
||||||
|
i++;
|
||||||
|
// transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||||
|
transactionTemplate.executeWithoutResult((status) -> administrativeLicenseRepo.saveAll(licenses));
|
||||||
|
log.info("企业生产许可成功次数:{}", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else log.info("企业生产许可没有数据list");
|
||||||
|
} else {
|
||||||
|
log.info("企业生产许可刷新Token");
|
||||||
|
refreshToken();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.info("企业生产许可查询异常:" + e);
|
||||||
|
}
|
||||||
|
return goon;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class AdministrativeLicenseInterfaceDto {
|
||||||
|
/**
|
||||||
|
* 适用部门(50)
|
||||||
|
*/
|
||||||
|
private String applydepartment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 变更记录(50)
|
||||||
|
*/
|
||||||
|
private String changerecord;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建人
|
||||||
|
*/
|
||||||
|
private String createdby;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime createdon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前用户等级 后台查看数据权限用
|
||||||
|
*/
|
||||||
|
private String dataScope;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除标记(默认为0; 0=未删除,1=已删除)
|
||||||
|
*/
|
||||||
|
private Integer deletestatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 归口管理责任部门(50)
|
||||||
|
*/
|
||||||
|
private String dutydepartmentmanager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 归口管理责任人(50)
|
||||||
|
*/
|
||||||
|
private String dutypeoplemanager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前用户单位 后台查看数据权限用
|
||||||
|
*/
|
||||||
|
private String dwdmScope;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID
|
||||||
|
*/
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发证机关
|
||||||
|
*/
|
||||||
|
private String issuingoffice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 许可证书名称
|
||||||
|
*/
|
||||||
|
private String licensename;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 许可证编号
|
||||||
|
*/
|
||||||
|
private String licensenumber;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 许可证状态
|
||||||
|
*/
|
||||||
|
private String licensestatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 许可类型approvalType
|
||||||
|
*/
|
||||||
|
private String licensetype;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改人
|
||||||
|
*/
|
||||||
|
private String modifiedby;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改时间
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime modifiedon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 企业名称
|
||||||
|
*/
|
||||||
|
private String qymc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 不符合项整改情况(500)
|
||||||
|
*/
|
||||||
|
private String rectificationnoncompliance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主要负责人
|
||||||
|
*/
|
||||||
|
private String responsibleperson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 符合性评审意见(500)
|
||||||
|
*/
|
||||||
|
private String reviewcomments;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 评审部门(50)
|
||||||
|
*/
|
||||||
|
private String reviewdepartment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 评审责任人(50)
|
||||||
|
*/
|
||||||
|
private String reviewpeople;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据来源 危化 工贸等
|
||||||
|
*/
|
||||||
|
private String sjly;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 企业id
|
||||||
|
*/
|
||||||
|
private String unitid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前用户岗位 后台查看数据权限用
|
||||||
|
*/
|
||||||
|
private String usergw;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 有效期至
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime validend;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 有效期自
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime validfrom;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重大事故隐患信息导入
|
||||||
|
*/
|
||||||
|
public void accidentHazardTask() {
|
||||||
|
log.info("开始重大事故隐患信息导入...");
|
||||||
|
int page = 1;
|
||||||
|
boolean b = importAccidentHazard(page);
|
||||||
|
while (b) {
|
||||||
|
page++;
|
||||||
|
b = importAccidentHazard(page);
|
||||||
|
}
|
||||||
|
log.info("企业重大事故隐患信息导入完成...");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean importAccidentHazard(int page) {
|
||||||
|
boolean goon = false;
|
||||||
|
try {
|
||||||
|
String body = HttpUtil.createPost(hazardPage)
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.header("Authorization", tokenType + " " + accessToken)
|
||||||
|
.header("appId", ssoClientProperties.getClientId())
|
||||||
|
.body("{\"page\": " + page + ",\"limit\": 1000,\"entity\": {}}")
|
||||||
|
.execute()
|
||||||
|
.body();
|
||||||
|
log.info("重大事故隐患查询结果:{}", body);
|
||||||
|
JsonNode jsonNode = objectMapper.readValue(body, JsonNode.class);
|
||||||
|
if (jsonNode.has("code") && 200 == jsonNode.get("code").asInt() && jsonNode.has("data")) {
|
||||||
|
JsonNode data = objectMapper.readValue(jsonNode.get("data").toString(), JsonNode.class);
|
||||||
|
if (null != data && data.has("list")) {
|
||||||
|
JsonNode arrNode = data.get("list");
|
||||||
|
if (arrNode.isArray()) {
|
||||||
|
long total = data.get("totalCount").asLong();
|
||||||
|
int limit = data.get("limit").asInt();
|
||||||
|
if (total > limit && arrNode.size() >= limit)
|
||||||
|
goon = true;
|
||||||
|
List<AccidentHazard> hazards = new ArrayList<>();
|
||||||
|
List<AccidentHazardDto> dtos = objectMapper.readValue(arrNode.toString(), new TypeReference<>() {
|
||||||
|
});
|
||||||
|
for (AccidentHazardDto dto : dtos) {
|
||||||
|
AccidentHazard hazard = new AccidentHazard();
|
||||||
|
BeanUtils.copyProperties(dto, hazard);
|
||||||
|
enterpriseRepo.findByUnifiedSocialCode(dto.getUnitid())
|
||||||
|
.ifPresentOrElse(enterprise -> {
|
||||||
|
hazard.setEnterpriseId(enterprise.getEnterpriseId());
|
||||||
|
if (null != hazard.getCreatedon()) {
|
||||||
|
String year = hazard.getCreatedon().format(yyyy);
|
||||||
|
if (StringUtils.hasText(enterprise.getMajorAccidentHazard())) {
|
||||||
|
Set<String> set = Arrays.stream(enterprise.getMajorAccidentHazard().split(",")).collect(Collectors.toSet());
|
||||||
|
if (!set.contains(year)) {
|
||||||
|
set.add(year);
|
||||||
|
String majorAccidentHazard = String.join(",", set);
|
||||||
|
EnterpriseHistory history = new EnterpriseHistory();
|
||||||
|
BeanUtils.copyProperties(enterprise, history);
|
||||||
|
LocalDateTime now = LocalDateTime.now();
|
||||||
|
history.setTheType("修改重大事故隐患年份");
|
||||||
|
history.setHistoryTime(now);
|
||||||
|
enterpriseHistoryRepo.save(history);
|
||||||
|
enterprise.setMajorAccidentHazard(majorAccidentHazard);
|
||||||
|
enterprise.setModifyTime(now);
|
||||||
|
enterpriseRepo.save(enterprise);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
enterprise.setMajorAccidentHazard(year);
|
||||||
|
}
|
||||||
|
if (!StringUtils.hasText(dto.getQymc()))
|
||||||
|
hazard.setUnitname(enterprise.getUnitName());
|
||||||
|
},
|
||||||
|
() -> {
|
||||||
|
hazard.setEnterpriseId(dto.getUnitid());
|
||||||
|
hazard.setUnitname(dto.getQymc());
|
||||||
|
});
|
||||||
|
|
||||||
|
hazard.setInterid(dto.getId());
|
||||||
|
hazard.setDataSource(dto.getSjly());
|
||||||
|
hazard.setPumpTime(LocalDateTime.now());
|
||||||
|
hazards.add(hazard);
|
||||||
|
}
|
||||||
|
int i = 0;
|
||||||
|
if (!hazards.isEmpty()) {
|
||||||
|
i++;
|
||||||
|
transactionTemplate.executeWithoutResult((status) -> accidentHazardRepo.saveAll(hazards));
|
||||||
|
log.info("重大事故隐患成功次数:{}", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else log.info("重大事故隐患没有数据list");
|
||||||
|
} else {
|
||||||
|
log.info("重大事故隐患刷新Token");
|
||||||
|
refreshToken();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.info("重大事故隐患查询异常:" + e);
|
||||||
|
}
|
||||||
|
return goon;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class AccidentHazardDto extends AccidentHazard {
|
||||||
|
/**
|
||||||
|
* 企业统一信用社代码
|
||||||
|
*/
|
||||||
|
private String unitid;
|
||||||
|
/**
|
||||||
|
* 企业名称
|
||||||
|
*/
|
||||||
|
private String qymc;
|
||||||
|
/**
|
||||||
|
* 数据来源 危化 工贸等
|
||||||
|
*/
|
||||||
|
private String sjly;
|
||||||
|
private String id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重大危险源信息导入
|
||||||
|
*/
|
||||||
|
public void dangerInfoTask() {
|
||||||
|
log.info("开始重大危险源信息导入...");
|
||||||
|
int page = 1;
|
||||||
|
boolean b = importDangerInfo(page);
|
||||||
|
while (b) {
|
||||||
|
page++;
|
||||||
|
b = importDangerInfo(page);
|
||||||
|
}
|
||||||
|
log.info("重大危险源信息导入完成...");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean importDangerInfo(int page) {
|
||||||
|
boolean goon = false;
|
||||||
|
try {
|
||||||
|
String body = HttpUtil.createPost(sourcesDangerPage)
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.header("Authorization", tokenType + " " + accessToken)
|
||||||
|
.header("appId", ssoClientProperties.getClientId())
|
||||||
|
.body("{\"page\": " + page + ",\"limit\": 1000,\"entity\": {}}")
|
||||||
|
.execute()
|
||||||
|
.body();
|
||||||
|
log.info("重大危险源查询结果:{}", body);
|
||||||
|
JsonNode jsonNode = objectMapper.readValue(body, JsonNode.class);
|
||||||
|
if (jsonNode.has("code") && 200 == jsonNode.get("code").asInt() && jsonNode.has("data")) {
|
||||||
|
JsonNode data = objectMapper.readValue(jsonNode.get("data").toString(), JsonNode.class);
|
||||||
|
if (null != data && data.has("list")) {
|
||||||
|
JsonNode arrNode = data.get("list");
|
||||||
|
if (arrNode.isArray()) {
|
||||||
|
long total = data.get("totalCount").asLong();
|
||||||
|
int limit = data.get("limit").asInt();
|
||||||
|
if (total > limit && arrNode.size() >= limit)
|
||||||
|
goon = true;
|
||||||
|
List<DangerInfo> dangerInfos = new ArrayList<>();
|
||||||
|
List<DangerInfoDto> dtos = objectMapper.readValue(arrNode.toString(), new TypeReference<>() {
|
||||||
|
});
|
||||||
|
for (DangerInfoDto dto : dtos) {
|
||||||
|
DangerInfo dangerInfo = new DangerInfo();
|
||||||
|
BeanUtils.copyProperties(dto, dangerInfo);
|
||||||
|
enterpriseRepo.findByUnifiedSocialCode(dto.getUnitid())
|
||||||
|
.ifPresentOrElse(enterprise -> {
|
||||||
|
dangerInfo.setEnterpriseId(enterprise.getEnterpriseId());
|
||||||
|
if (!StringUtils.hasText(dto.getQymc()))
|
||||||
|
dangerInfo.setUnitname(enterprise.getUnitName());
|
||||||
|
EnterpriseHistory history = new EnterpriseHistory();
|
||||||
|
BeanUtils.copyProperties(enterprise, history);
|
||||||
|
LocalDateTime now = LocalDateTime.now();
|
||||||
|
history.setTheType("修改危险源状态");
|
||||||
|
history.setHistoryTime(now);
|
||||||
|
enterpriseHistoryRepo.save(history);
|
||||||
|
enterprise.setMajorDanger("1");
|
||||||
|
enterprise.setModifyTime(now);
|
||||||
|
enterpriseRepo.save(enterprise);
|
||||||
|
},
|
||||||
|
() -> {
|
||||||
|
dangerInfo.setEnterpriseId(dto.getUnitid());
|
||||||
|
dangerInfo.setUnitname(dto.getQymc());
|
||||||
|
});
|
||||||
|
dangerInfo.setInterid(dto.getId());
|
||||||
|
dangerInfo.setDataSource(dto.getSjly());
|
||||||
|
dangerInfo.setPumpTime(LocalDateTime.now());
|
||||||
|
dangerInfos.add(dangerInfo);
|
||||||
|
}
|
||||||
|
int i = 0;
|
||||||
|
if (!dangerInfos.isEmpty()) {
|
||||||
|
i++;
|
||||||
|
transactionTemplate.executeWithoutResult((status) -> dangerInfoRepo.saveAll(dangerInfos));
|
||||||
|
log.info("重大危险源成功次数:{}", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else log.info("重大危险源没有数据list");
|
||||||
|
} else {
|
||||||
|
log.info("重大危险源刷新Token");
|
||||||
|
refreshToken();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.info("重大危险源查询异常:" + e);
|
||||||
|
}
|
||||||
|
return goon;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class DangerInfoDto extends DangerInfo {
|
||||||
|
/**
|
||||||
|
* 企业统一信用社代码
|
||||||
|
*/
|
||||||
|
private String unitid;
|
||||||
|
/**
|
||||||
|
* 企业名称
|
||||||
|
*/
|
||||||
|
private String qymc;
|
||||||
|
/**
|
||||||
|
* 数据来源 危化 工贸等
|
||||||
|
*/
|
||||||
|
private String sjly;
|
||||||
|
private String id;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,238 @@
|
||||||
|
package com.aisino.iles.lawenforcement.schedule.service;
|
||||||
|
|
||||||
|
import cn.hutool.core.codec.Base64;
|
||||||
|
import cn.hutool.crypto.digest.DigestUtil;
|
||||||
|
import cn.hutool.http.HttpRequest;
|
||||||
|
import cn.hutool.http.HttpResponse;
|
||||||
|
import cn.hutool.json.JSONArray;
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import com.aisino.iles.lawenforcement.model.EquipmentHistoryVideo;
|
||||||
|
import com.aisino.iles.lawenforcement.repository.EquipmentHistoryVideoRepository;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.net.HttpCookie;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执法装备历史视频信息同步调度服务
|
||||||
|
* <p>
|
||||||
|
* 通过定时任务从外部API同步装备历史视频信息到本地数据库
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class EquipmentHistoryVideoScheduleService {
|
||||||
|
|
||||||
|
@Value("${media.service.login.url:http://222.91.125.86:8090/rest/index/login/login}")
|
||||||
|
private String loginUrl;
|
||||||
|
@Value("${media.service.data.url:http://222.91.125.86:8090/rest/media/media/get}")
|
||||||
|
private String dataUrl;
|
||||||
|
@Value("${media.service.username:SLtest}")
|
||||||
|
private String username;
|
||||||
|
@Value("${media.service.password:Pe26957381}")
|
||||||
|
private String password;
|
||||||
|
@Value("${media.service.device.code:1001}")
|
||||||
|
private String deviceCode;
|
||||||
|
@Value("${media.service.page.size:100}")
|
||||||
|
private int pageSize;
|
||||||
|
@Value("${media.service.date.start:2000-01-01 00:00:00}")
|
||||||
|
private String defaultStartDate;
|
||||||
|
@Value("${media.service.date.end:2030-01-01 00:00:00}")
|
||||||
|
private String defaultEndDate;
|
||||||
|
|
||||||
|
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||||
|
private static final String SESSION_COOKIE_NAME = "PHPSESSID";
|
||||||
|
private static final int MAX_RETRIES = 3;
|
||||||
|
|
||||||
|
private final EquipmentHistoryVideoRepository equipmentHistoryVideoRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public EquipmentHistoryVideoScheduleService(EquipmentHistoryVideoRepository equipmentHistoryVideoRepository) {
|
||||||
|
this.equipmentHistoryVideoRepository = equipmentHistoryVideoRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Scheduled(cron = "0 * * * * ?")
|
||||||
|
public void scheduleTask() {
|
||||||
|
log.info("获取装备历史视频开始。。。。");
|
||||||
|
try {
|
||||||
|
HttpCookie sessionCookie = login();
|
||||||
|
if (sessionCookie != null) {
|
||||||
|
fetchAllMediaPages(sessionCookie);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("任务异常", e);
|
||||||
|
}
|
||||||
|
log.info("获取装备历史视频结束。。。。");
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpCookie login() {
|
||||||
|
String encryptedPassword = DigestUtil.md5Hex(password);
|
||||||
|
// 构造登录参数
|
||||||
|
JSONObject param = new JSONObject();
|
||||||
|
param.set("username", username);
|
||||||
|
param.set("password", encryptedPassword);
|
||||||
|
try {
|
||||||
|
// 编码处理
|
||||||
|
String jsonString = param.toString();
|
||||||
|
String urlEncodedString = URLEncoder.encode(jsonString, StandardCharsets.UTF_8.name());
|
||||||
|
String loginInfo = Base64.encode(urlEncodedString);
|
||||||
|
|
||||||
|
// 构造请求体
|
||||||
|
JSONObject requestBody = new JSONObject();
|
||||||
|
requestBody.set("login_info", loginInfo);
|
||||||
|
|
||||||
|
// 发送登录请求
|
||||||
|
HttpResponse response = HttpRequest.post(loginUrl)
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.body(requestBody.toString())
|
||||||
|
.execute();
|
||||||
|
if (response.getStatus() != 200) {
|
||||||
|
log.error("登录失败: {}", response.getStatus());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
HttpCookie sessionCookie = response.getCookie(SESSION_COOKIE_NAME);
|
||||||
|
if (sessionCookie == null) {
|
||||||
|
log.error("登录失败:PHPSESSID为空");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("登录成功");
|
||||||
|
return sessionCookie;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("登录失败:", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void fetchAllMediaPages(HttpCookie sessionCookie) {
|
||||||
|
int curPage = 1;
|
||||||
|
int retryCount = 0;
|
||||||
|
boolean hasMorePages = true;
|
||||||
|
|
||||||
|
while (hasMorePages && retryCount < MAX_RETRIES) {
|
||||||
|
try {
|
||||||
|
// 构造请求参数
|
||||||
|
JSONObject param = buildRequestParams(curPage);
|
||||||
|
|
||||||
|
// 发送请求
|
||||||
|
HttpResponse response = HttpRequest.post(dataUrl)
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.body(param.toString())
|
||||||
|
.cookie(sessionCookie)
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
// 检查响应状态
|
||||||
|
if (response.getStatus() != 200) {
|
||||||
|
log.error("请求失败: {}", response.getStatus());
|
||||||
|
throw new RuntimeException("API请求失败 " + response.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析响应
|
||||||
|
JSONObject result = JSONUtil.parseObj(response.body());
|
||||||
|
if (result.getInt("code") != 200) {
|
||||||
|
log.error("API数据接口请求失败 code: {}, message: {}", result.getInt("code"), result.getStr("message"));
|
||||||
|
throw new RuntimeException("API数据接口请求失败 code: " + result.getInt("code"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理数据
|
||||||
|
boolean pageProcessed = processPageData(result);
|
||||||
|
if (!pageProcessed) {
|
||||||
|
throw new RuntimeException("当前页数据处理失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否还有更多页
|
||||||
|
JSONObject pageInfo = result.getJSONObject("page");
|
||||||
|
int totalPages = pageInfo.getInt("page_nums");
|
||||||
|
curPage = pageInfo.getInt("cur_page") + 1;
|
||||||
|
hasMorePages = (curPage <= totalPages);
|
||||||
|
retryCount = 0; // 重置重试计数器
|
||||||
|
|
||||||
|
log.info("当前页 {}/{} 处理成功", curPage - 1, totalPages);
|
||||||
|
} catch (Exception e) {
|
||||||
|
retryCount++;
|
||||||
|
log.error("当前页 {} 处理失败,重试次数 {}/{}", curPage, retryCount, MAX_RETRIES, e);
|
||||||
|
|
||||||
|
if (retryCount >= MAX_RETRIES) {
|
||||||
|
log.error("当前页 {} 重试超过最大次数,终止任务", curPage);
|
||||||
|
throw new RuntimeException("分页请求失败,已达最大重试次数");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private JSONObject buildRequestParams(int curPage) {
|
||||||
|
JSONObject param = new JSONObject();
|
||||||
|
param.set("bh", deviceCode);
|
||||||
|
param.set("pssj_type", "3");
|
||||||
|
param.set("pssj_start", defaultStartDate);
|
||||||
|
param.set("pssj_end", defaultEndDate);
|
||||||
|
param.set("scsj_type", "3");
|
||||||
|
param.set("scsj_start", defaultStartDate);
|
||||||
|
param.set("scsj_end", defaultEndDate);
|
||||||
|
param.set("media_type", "1");
|
||||||
|
param.set("sjly", "1");
|
||||||
|
param.set("is_del", "0");
|
||||||
|
param.set("page_size", String.valueOf(pageSize));
|
||||||
|
param.set("cur_page", String.valueOf(curPage));
|
||||||
|
return param;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean processPageData(JSONObject result) {
|
||||||
|
JSONArray lines = result.getJSONObject("data").getJSONArray("lines");
|
||||||
|
if (lines == null || lines.isEmpty()) {
|
||||||
|
log.warn("当前页没有数据");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
List<EquipmentHistoryVideo> videos = new ArrayList<>();
|
||||||
|
for (Object item : lines) {
|
||||||
|
try {
|
||||||
|
JSONObject jsonObject = JSONUtil.parseObj(item);
|
||||||
|
String id = jsonObject.getStr("id");
|
||||||
|
boolean exists = equipmentHistoryVideoRepository.existsByLssjid(id);
|
||||||
|
if (!exists) {
|
||||||
|
EquipmentHistoryVideo video = new EquipmentHistoryVideo();
|
||||||
|
// 基本字段映射
|
||||||
|
video.setLssjid(id);
|
||||||
|
video.setZbmc(jsonObject.getStr("dname"));
|
||||||
|
video.setZbdm(jsonObject.getStr("hostbody"));
|
||||||
|
video.setZblxmc(jsonObject.getStr("sjly_name"));
|
||||||
|
video.setSpbfdz(jsonObject.getStr("play_url"));
|
||||||
|
video.setSpxzdz(jsonObject.getStr("download_url"));
|
||||||
|
// 日期字段特殊处理
|
||||||
|
if (jsonObject.getStr("createdate") != null) {
|
||||||
|
video.setCjsj(LocalDateTime.parse(jsonObject.getStr("createdate"), DATE_TIME_FORMATTER));
|
||||||
|
}
|
||||||
|
videos.add(video);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("当前数据解析失败: {}", item, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!videos.isEmpty()) {
|
||||||
|
try {
|
||||||
|
equipmentHistoryVideoRepository.saveAll(videos);
|
||||||
|
log.info("当前页数据保存成功", videos.size());
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("当前页数据保存失败:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,400 @@
|
||||||
|
package com.aisino.iles.lawenforcement.schedule.service;
|
||||||
|
|
||||||
|
import com.aisino.iles.common.util.StringUtils;
|
||||||
|
import com.aisino.iles.lawenforcement.config.ThirdPartyProperties;
|
||||||
|
import com.aisino.iles.lawenforcement.model.Agency;
|
||||||
|
import com.aisino.iles.lawenforcement.model.Officer;
|
||||||
|
import com.aisino.iles.lawenforcement.repository.AgencyRepository;
|
||||||
|
import com.aisino.iles.lawenforcement.repository.OfficerRepository;
|
||||||
|
import com.aisino.iles.lawenforcement.service.AuthService;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonAlias;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.smartlx.sso.client.model.AccessToken;
|
||||||
|
import com.smartlx.sso.client.properties.SsoClientProperties;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import lombok.ToString;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpEntity;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.client.HttpClientErrorException;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执法人员信息同步调度服务
|
||||||
|
*
|
||||||
|
* 通过定时任务从外部API同步执法人员信息到本地数据库
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class OfficerScheduleService {
|
||||||
|
|
||||||
|
private final OfficerRepository officerRepository;
|
||||||
|
private final AgencyRepository agencyRepository;
|
||||||
|
private final AuthService authService;
|
||||||
|
private final RestTemplate restTemplate;
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
private final ThirdPartyProperties thirdPartyProperties;
|
||||||
|
private final SsoClientProperties ssoClientProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OfficerScheduleService constructor.
|
||||||
|
*
|
||||||
|
* @param officerRepository the officer repository
|
||||||
|
* @param agencyRepository the agency repository
|
||||||
|
* @param authService the auth service
|
||||||
|
* @param restTemplate the rest template
|
||||||
|
* @param objectMapper the object mapper
|
||||||
|
* @param thirdPartyProperties the third party properties
|
||||||
|
* @param ssoClientProperties the sso client properties
|
||||||
|
*/
|
||||||
|
@Autowired
|
||||||
|
public OfficerScheduleService(OfficerRepository officerRepository, AgencyRepository agencyRepository, AuthService authService, RestTemplate restTemplate, ObjectMapper objectMapper, ThirdPartyProperties thirdPartyProperties, SsoClientProperties ssoClientProperties) {
|
||||||
|
this.officerRepository = officerRepository;
|
||||||
|
this.agencyRepository = agencyRepository;
|
||||||
|
this.authService = authService;
|
||||||
|
this.restTemplate = restTemplate;
|
||||||
|
this.objectMapper = objectMapper;
|
||||||
|
this.thirdPartyProperties = thirdPartyProperties;
|
||||||
|
this.ssoClientProperties = ssoClientProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定时任务,每天凌晨2点执行
|
||||||
|
*/
|
||||||
|
/// @Scheduled(cron = "${scheduler.task.officer.cron.expression:0 0 2 * * ?}")
|
||||||
|
@Scheduled(fixedRate = 3600000, initialDelay = 5000)
|
||||||
|
public void scheduleTask() {
|
||||||
|
log.info("开始执行执法人员信息同步任务...");
|
||||||
|
|
||||||
|
if (StringUtils.isEmpty(thirdPartyProperties.getPerson().getQuery())) {
|
||||||
|
log.error("执法人员API URL (third-party.person.query) 未配置。");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (StringUtils.isEmpty(thirdPartyProperties.getEnterprise().getYddh())) {
|
||||||
|
log.error("执法人员API令牌IDNO (third-party.enterprise.idno) 未配置。");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (thirdPartyProperties.getPerson().getRoles() == null || thirdPartyProperties.getPerson().getRoles().isEmpty()) {
|
||||||
|
log.error("执法人员角色列表 (third-party.person.roles) 未配置。");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
List<ApiOfficer> allApiOfficers = new ArrayList<>();
|
||||||
|
|
||||||
|
// 遍历所有角色进行查询
|
||||||
|
for (String role : thirdPartyProperties.getPerson().getRoles()) {
|
||||||
|
log.info("正在查询角色: {}", role);
|
||||||
|
// 构建查询条件
|
||||||
|
Map<String, Object> requestBody = new HashMap<>();
|
||||||
|
Map<String, String> entity = new HashMap<>();
|
||||||
|
entity.put("jsdm", role); // 使用当前角色
|
||||||
|
requestBody.put("entity", entity);
|
||||||
|
|
||||||
|
log.info("准备从API获取执法人员数据. URL: {}, Role: {}", thirdPartyProperties.getPerson().getQuery(), role);
|
||||||
|
|
||||||
|
int currentPage = 1;
|
||||||
|
int totalPages = 1;
|
||||||
|
final int pageSize = 100; // 每页大小
|
||||||
|
|
||||||
|
do {
|
||||||
|
requestBody.put("page", currentPage);
|
||||||
|
requestBody.put("limit", pageSize);
|
||||||
|
|
||||||
|
String responseBody = fetchDataFromApi(requestBody, thirdPartyProperties.getPerson().getQuery());
|
||||||
|
|
||||||
|
if (responseBody != null) {
|
||||||
|
ApiResponse apiResponse = objectMapper.readValue(responseBody, ApiResponse.class);
|
||||||
|
|
||||||
|
if (apiResponse.isSuccess() && apiResponse.getData() != null && apiResponse.getData().getRecords() != null) {
|
||||||
|
allApiOfficers.addAll(apiResponse.getData().getRecords());
|
||||||
|
totalPages = apiResponse.getData().getPages();
|
||||||
|
log.info("成功获取第 {}/{} 页数据,记录数: {}", currentPage, totalPages, apiResponse.getData().getRecords().size());
|
||||||
|
} else {
|
||||||
|
log.error("API响应失败或数据为空. 角色: {}, 响应: {}", role, responseBody);
|
||||||
|
break; // 如果某页失败,则停止该角色的后续分页
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.error("从API获取数据失败. 角色: {}, 页码: {}", role, currentPage);
|
||||||
|
break; // 如果获取失败,则停止该角色的后续分页
|
||||||
|
}
|
||||||
|
currentPage++;
|
||||||
|
} while (currentPage <= totalPages);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allApiOfficers.isEmpty()) {
|
||||||
|
log.info("未从API获取到任何执法人员数据。");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Officer> officersToSave = processApiOfficers(allApiOfficers);
|
||||||
|
officerRepository.saveAll(officersToSave);
|
||||||
|
log.info("成功同步 {} 名执法人员信息。", officersToSave.size());
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("同步执法人员信息时发生未知异常", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从第三方API获取数据
|
||||||
|
*
|
||||||
|
* @param requestBody 请求体
|
||||||
|
* @param url 请求URL
|
||||||
|
* @return 响应体
|
||||||
|
*/
|
||||||
|
@SneakyThrows
|
||||||
|
private String fetchDataFromApi(Map<String, Object> requestBody, String url) {
|
||||||
|
int maxRetries = 2; // 允许一次初始尝试和一次重试
|
||||||
|
|
||||||
|
for (int attempt = 1; attempt <= maxRetries; attempt++) {
|
||||||
|
AccessToken accessToken = authService.getTokenBackend(thirdPartyProperties.getEnterprise().getYddh());
|
||||||
|
if (accessToken == null || accessToken.getAccess_token() == null) {
|
||||||
|
log.error("获取访问令牌失败 (尝试 {}/{}),URL: {}. 请检查AuthService配置和令牌提供者。", attempt, maxRetries, url);
|
||||||
|
throw new RuntimeException("获取API调用的访问令牌失败。");
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setBearerAuth(accessToken.getAccess_token());
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
|
||||||
|
try {
|
||||||
|
String requestBodyJson = objectMapper.writeValueAsString(requestBody);
|
||||||
|
HttpEntity<String> entity = new HttpEntity<>(requestBodyJson, headers);
|
||||||
|
|
||||||
|
log.debug("向API发送请求. URL: {}, Body: {}", url, requestBodyJson);
|
||||||
|
ResponseEntity<String> response = restTemplate.postForEntity(url, entity, String.class);
|
||||||
|
|
||||||
|
if (response.getStatusCode().is2xxSuccessful()) {
|
||||||
|
return response.getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理401以外的非成功状态码
|
||||||
|
log.error("API请求失败 (尝试 {}/{}),URL: {}, 状态码: {}, 响应: {}",
|
||||||
|
attempt, maxRetries, url, response.getStatusCode(), response.getBody());
|
||||||
|
return null; // 对于其他客户端或服务器错误,直接返回null
|
||||||
|
|
||||||
|
} catch (HttpClientErrorException.Unauthorized e) {
|
||||||
|
log.warn("API请求未授权 (401) (尝试 {}/{}),URL: {}. 令牌可能已过期。",
|
||||||
|
attempt, maxRetries, url);
|
||||||
|
if (attempt < maxRetries) {
|
||||||
|
try {
|
||||||
|
authService.refreshTokenBackend(accessToken.getAccess_token(), accessToken.getToken_type(), accessToken.getRefresh_token(), thirdPartyProperties.getEnterprise().getYddh());
|
||||||
|
log.info("请求刷新令牌成功。下一次尝试将使用新令牌。");
|
||||||
|
} catch (Exception refreshException) {
|
||||||
|
log.error("请求刷新令牌期间发生异常: {}. 中止对URL: {} 的重试。",
|
||||||
|
refreshException.getMessage(), url, refreshException);
|
||||||
|
return null; // 刷新失败,不再重试
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.error("刷新令牌后重试仍然失败 (尝试 {}/{}),URL: {}", attempt, maxRetries, url);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("调用API时发生异常 (尝试 {}/{}),URL: {}", attempt, maxRetries, url, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null; // 所有尝试失败后返回null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理从API获取的人员信息
|
||||||
|
*
|
||||||
|
* @param apiOfficers API返回的人员列表
|
||||||
|
* @return 处理后的Officer对象列表,准备保存到数据库
|
||||||
|
*/
|
||||||
|
private List<Officer> processApiOfficers(List<ApiOfficer> apiOfficers) {
|
||||||
|
log.info("开始处理 {} 条API执法人员数据...", apiOfficers.size());
|
||||||
|
|
||||||
|
// 去重,以人员唯一标识为准,后出现的会覆盖先出现的
|
||||||
|
Map<String, ApiOfficer> distinctApiOfficersMap = apiOfficers.stream()
|
||||||
|
.filter(officer -> StringUtils.isNotEmpty(officer.getYhwybs()))
|
||||||
|
.collect(Collectors.toMap(ApiOfficer::getYhwybs, p -> p, (existing, replacement) -> replacement));
|
||||||
|
|
||||||
|
List<ApiOfficer> distinctApiOfficers = new ArrayList<>(distinctApiOfficersMap.values());
|
||||||
|
|
||||||
|
log.info("去重后还有 {} 条API执法人员数据", distinctApiOfficers.size());
|
||||||
|
|
||||||
|
// 预先加载所有机构以提高性能
|
||||||
|
List<Agency> allAgencies = agencyRepository.findAll();
|
||||||
|
Map<String, Agency> agencyCodeMap = allAgencies.stream()
|
||||||
|
.filter(agency -> StringUtils.isNotEmpty(agency.getAgencyCode()))
|
||||||
|
.collect(Collectors.toMap(agency -> StringUtils.trimEven0(agency.getAgencyCode()), agency -> agency, (a1, a2) -> a1));
|
||||||
|
log.info("已加载 {} 个机构用于匹配", agencyCodeMap.size());
|
||||||
|
|
||||||
|
List<Officer> officersToSave = new ArrayList<>();
|
||||||
|
|
||||||
|
for (ApiOfficer apiOfficer : distinctApiOfficers) {
|
||||||
|
// 仅处理有姓名的人员
|
||||||
|
if (StringUtils.isEmpty(apiOfficer.getXm())) {
|
||||||
|
log.warn("API返回的执法人员数据缺少 xm (姓名),跳过此条记录: {}", apiOfficer);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 优先通过人员唯一标识查找,不存在则创建新记录
|
||||||
|
Optional<Officer> existingOfficer = officerRepository.findByCertificateNo(apiOfficer.getYhwybs());
|
||||||
|
Officer officer = existingOfficer.orElse(new Officer());
|
||||||
|
|
||||||
|
// 设置基本信息
|
||||||
|
officer.setOfficerName(apiOfficer.getXm());
|
||||||
|
officer.setCertificateNo(apiOfficer.getYhwybs()); // 使用唯一标识作为证号
|
||||||
|
officer.setRole(apiOfficer.getJsdm());
|
||||||
|
officer.setRoleName(apiOfficer.getJsmc());
|
||||||
|
|
||||||
|
// 转换机构代码并查找对应机构
|
||||||
|
String apiOfficerAgencyCode = apiOfficer.getGajgjgdm();
|
||||||
|
Agency matchedAgency = findMatchingAgency(apiOfficerAgencyCode, agencyCodeMap);
|
||||||
|
|
||||||
|
if (matchedAgency != null) {
|
||||||
|
officer.setAgencyId(matchedAgency.getAgencyId());
|
||||||
|
log.debug("为执法人员 {} 找到匹配机构: {}({})",
|
||||||
|
apiOfficer.getXm(), matchedAgency.getAgencyName(), matchedAgency.getAgencyCode());
|
||||||
|
} else {
|
||||||
|
log.warn("无法为执法人员 {} 找到匹配的机构,原机构代码: {}",
|
||||||
|
apiOfficer.getXm(), apiOfficerAgencyCode);
|
||||||
|
// 跳过无法匹配机构的人员
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
officersToSave.add(officer);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("成功处理 {} 条执法人员数据", officersToSave.size());
|
||||||
|
return officersToSave;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从最大机构级别开始逐级递减匹配机构
|
||||||
|
*
|
||||||
|
* @param officerAgencyCode 执法人员所属的机构代码
|
||||||
|
* @param agencyCodeMap 所有本地机构的映射(键为去掉末尾偶数0后的机构代码)
|
||||||
|
* @return 匹配到的机构,如果没有匹配则返回null
|
||||||
|
*/
|
||||||
|
private Agency findMatchingAgency(String officerAgencyCode, Map<String, Agency> agencyCodeMap) {
|
||||||
|
if (officerAgencyCode == null || officerAgencyCode.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 去掉执法人员机构代码末尾的偶数个0
|
||||||
|
String trimmedOfficerCode = StringUtils.trimEven0(officerAgencyCode);
|
||||||
|
|
||||||
|
// 1. 先尝试完全匹配
|
||||||
|
Agency directMatch = agencyCodeMap.get(trimmedOfficerCode);
|
||||||
|
if (directMatch != null) {
|
||||||
|
log.debug("执法人员机构代码 {} 直接匹配到机构 {}", officerAgencyCode, directMatch.getAgencyName());
|
||||||
|
return directMatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 如果没有完全匹配,从最长的机构代码开始尝试前缀匹配
|
||||||
|
// 按机构代码长度排序(从长到短,代表从较低级别到较高级别机构)
|
||||||
|
List<String> sortedAgencyCodes = agencyCodeMap.keySet().stream()
|
||||||
|
.sorted((a, b) -> Integer.compare(b.length(), a.length()))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
// 只考虑级别2及以上的机构(一般来说代码长度较短)
|
||||||
|
for (String agencyCode : sortedAgencyCodes) {
|
||||||
|
// 检查该机构代码是否是执法人员机构代码的前缀
|
||||||
|
if (trimmedOfficerCode.startsWith(agencyCode)) {
|
||||||
|
Agency matchedAgency = agencyCodeMap.get(agencyCode);
|
||||||
|
log.debug("执法人员机构代码 {} 通过前缀匹配到机构 {} ({})",
|
||||||
|
officerAgencyCode, matchedAgency.getAgencyName(), agencyCode);
|
||||||
|
return matchedAgency;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 反向尝试:看执法人员的机构代码是否是某个本地机构的前缀
|
||||||
|
// 注:这种情况比较少见,执法人员可能来自更高级别的机构
|
||||||
|
for (String agencyCode : agencyCodeMap.keySet()) {
|
||||||
|
if (agencyCode.startsWith(trimmedOfficerCode)) {
|
||||||
|
Agency matchedAgency = agencyCodeMap.get(agencyCode);
|
||||||
|
log.debug("本地机构 {} ({}) 的代码以执法人员机构代码 {} 为前缀",
|
||||||
|
matchedAgency.getAgencyName(), agencyCode, officerAgencyCode);
|
||||||
|
return matchedAgency;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API响应结构定义
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private static class ApiResponse {
|
||||||
|
private String code;
|
||||||
|
private boolean success;
|
||||||
|
private ApiData data;
|
||||||
|
private String msg;
|
||||||
|
|
||||||
|
public boolean isSuccess() {
|
||||||
|
return "200".equals(code) && success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API数据结构定义
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private static class ApiData {
|
||||||
|
private int offset;
|
||||||
|
private int limit;
|
||||||
|
@JsonAlias("totalCount")
|
||||||
|
private String totalCountStr;
|
||||||
|
@JsonAlias("list")
|
||||||
|
private List<ApiOfficer> records;
|
||||||
|
|
||||||
|
public int getTotalPage() {
|
||||||
|
if (limit <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return (int) Math.ceil((double) getTotalCount() / limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTotalCount() {
|
||||||
|
try {
|
||||||
|
return Integer.parseInt(totalCountStr);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
log.warn("无法解析 totalCount: '{}'", totalCountStr, e);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPages() {
|
||||||
|
return getTotalPage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API人员信息结构定义
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString
|
||||||
|
private static class ApiOfficer {
|
||||||
|
// 人员唯一标识
|
||||||
|
private String yhwybs;
|
||||||
|
|
||||||
|
// 姓名
|
||||||
|
private String xm;
|
||||||
|
|
||||||
|
// 机构代码
|
||||||
|
private String gajgjgdm;
|
||||||
|
|
||||||
|
// 角色代码
|
||||||
|
private String jsdm;
|
||||||
|
|
||||||
|
// 角色名称
|
||||||
|
private String jsmc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,258 @@
|
||||||
|
package com.aisino.iles.lawenforcement.schedule.service;
|
||||||
|
|
||||||
|
import cn.hutool.http.HttpUtil;
|
||||||
|
import com.aisino.iles.common.util.BeanUtils;
|
||||||
|
import com.aisino.iles.common.util.Md5Utils;
|
||||||
|
import com.aisino.iles.lawenforcement.model.Materials;
|
||||||
|
import com.aisino.iles.lawenforcement.model.ReportCheck;
|
||||||
|
import com.aisino.iles.lawenforcement.repository.MaterialsRepository;
|
||||||
|
import com.aisino.iles.lawenforcement.repository.ReportCheckRepository;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 举报核查定时任务
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class ReportCheckScheduleService {
|
||||||
|
private final String queryUrl;
|
||||||
|
private final String singleUrl;
|
||||||
|
private final String sign;
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
private final ReportCheckRepository reportCheckRepo;
|
||||||
|
private final MaterialsRepository materialsRepo;
|
||||||
|
|
||||||
|
public ReportCheckScheduleService(@Value("${third-party.report_check.query:}") String queryUrl,
|
||||||
|
@Value("${third-party.report_check.single:}") String singleUrl,
|
||||||
|
@Value("${third-party.report_check.sign:}") String sign,
|
||||||
|
ObjectMapper objectMapper,
|
||||||
|
ReportCheckRepository reportCheckRepo,
|
||||||
|
MaterialsRepository materialsRepo) {
|
||||||
|
this.queryUrl = queryUrl;
|
||||||
|
this.singleUrl = singleUrl;
|
||||||
|
this.sign = sign;
|
||||||
|
this.objectMapper = objectMapper;
|
||||||
|
this.reportCheckRepo = reportCheckRepo;
|
||||||
|
this.materialsRepo = materialsRepo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 12350投诉举报信息导入
|
||||||
|
* 每隔一小时执行一次
|
||||||
|
*/
|
||||||
|
@Scheduled(fixedDelay = 120000)
|
||||||
|
@Transactional
|
||||||
|
public void scheduledTask() {
|
||||||
|
log.info("开始导入举报核查信息...");
|
||||||
|
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||||
|
String create_time = null;
|
||||||
|
LocalDateTime maxAcceptTime = reportCheckRepo.getMaxAcceptTime();
|
||||||
|
if (null != maxAcceptTime) {
|
||||||
|
create_time = "[\"" + maxAcceptTime.format(df) + "\",\"" + LocalDateTime.now().format(df) + "\"]";
|
||||||
|
}
|
||||||
|
extracted(create_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void extracted(String create_time) {
|
||||||
|
try {
|
||||||
|
int page = 1, pagesize = 99999;
|
||||||
|
log.info("条件={}", "{\"page\": " + page + ",\"pagesize\": " + pagesize + ",\"create_time\": " + create_time + "}");
|
||||||
|
String body = HttpUtil.createPost(queryUrl)
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.header("Sign", Md5Utils.getMd5Str(sign))
|
||||||
|
.body("{\"page\": " + page + ",\"pagesize\": " + pagesize + ",\"create_time\": " + create_time + "}")
|
||||||
|
.execute()
|
||||||
|
.body();
|
||||||
|
log.info("信息查询结果:{}", body);
|
||||||
|
JsonNode jsonNode = objectMapper.readValue(body, JsonNode.class);
|
||||||
|
if (jsonNode.has("code") && 1 == jsonNode.get("code").asInt() && jsonNode.has("data")) {
|
||||||
|
JsonNode data = objectMapper.readValue(jsonNode.get("data").toString(), JsonNode.class);
|
||||||
|
if (null != data && data.has("result")) {
|
||||||
|
JsonNode arrNode = data.get("result");
|
||||||
|
if (arrNode.isArray()) {
|
||||||
|
for (JsonNode node : arrNode) {
|
||||||
|
ReportCheckInterfaceDto dto = objectMapper.readValue(node.toString(), ReportCheckInterfaceDto.class);
|
||||||
|
ReportCheck reportCheck = new ReportCheck();
|
||||||
|
LocalDateTime now = LocalDateTime.now();
|
||||||
|
reportCheckRepo.findByPumpId(dto.getId()).ifPresent(o -> {
|
||||||
|
BeanUtils.copyProperties(o, reportCheck);
|
||||||
|
List<String> ids = materialsRepo.findByLinkId(o.getPcid()).stream().map(Materials::getMaterialsId).collect(Collectors.toList());
|
||||||
|
materialsRepo.deleteAllById(ids);
|
||||||
|
reportCheck.setUpdateTime(now);
|
||||||
|
});
|
||||||
|
reportCheck.setPumpId(dto.getId());//数据id
|
||||||
|
// (dto.getWork_order_number());//工单编号
|
||||||
|
// (dto.getWork_order_level());//工单等级
|
||||||
|
reportCheck.setAcceptTime(dto.getCreate_time());//受理时间
|
||||||
|
reportCheck.setReportCanal(dto.getComplaint_resource_one());//一级举报渠道-举报渠道
|
||||||
|
reportCheck.setCanalCategory(dto.getComplaint_resource_two());//二级举报渠道-渠道分类
|
||||||
|
reportCheck.setReportCategory(dto.getComplaint_kind_one());//一级投诉类别-投诉类别
|
||||||
|
reportCheck.setCategorization(dto.getComplaint_kind_two());//二级投诉类别-类别分类
|
||||||
|
reportCheck.setReporterName(dto.getComplainant_name());//姓名
|
||||||
|
reportCheck.setReporterPhone(dto.getComplaint_phone());//联系方式
|
||||||
|
if (StringUtils.hasText(dto.getComplaint_phone()) && dto.getComplaint_phone().contains("**"))
|
||||||
|
reportCheck.setIsAnon("1");
|
||||||
|
reportCheck.setReporterSex(dto.getComplainant_sex());//性别
|
||||||
|
reportCheck.setComplainTime(dto.getComplaint_time());//投诉时间
|
||||||
|
reportCheck.setBriefFact(dto.getReport_situation());//举报情况
|
||||||
|
reportCheck.setIndustryType(dto.getTrade());//所属行业
|
||||||
|
reportCheck.setReportLocal(dto.getLocation_data());//举报问题所在地
|
||||||
|
String detailBody = HttpUtil.createPost(singleUrl)
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.header("sign", Md5Utils.getMd5Str(sign))
|
||||||
|
.body("{\"id\": \"" + dto.getId() + "\"}")
|
||||||
|
.execute()
|
||||||
|
.body();
|
||||||
|
JsonNode detailNode = objectMapper.readValue(detailBody, JsonNode.class);
|
||||||
|
if (detailNode.has("code") && 1 == detailNode.get("code").asInt() && detailNode.has("data")) {
|
||||||
|
ReportCheckInterfaceDto detailDto = objectMapper.readValue(detailNode.get("data").toString(), ReportCheckInterfaceDto.class);
|
||||||
|
reportCheck.setRemark(detailDto.getRemark());//备注
|
||||||
|
reportCheck.setTransferDistrict(detailDto.getTransfer_district());//转办区县
|
||||||
|
reportCheck.setResTime(detailDto.getReply_time());//区县回复时间
|
||||||
|
reportCheck.setReplyContent(detailDto.getReply_content());//回复内容
|
||||||
|
// reportCheck.setComplainAcceptStatus(detailDto.getComplaint_status());//受理状态
|
||||||
|
reportCheck.setDataSource("2");
|
||||||
|
ReportCheck save = reportCheckRepo.save(reportCheck);
|
||||||
|
if (null != detailDto.getAttach() && !detailDto.getAttach().isEmpty()) {
|
||||||
|
detailDto.getAttach().forEach(attachDto -> {
|
||||||
|
Materials materials = new Materials();
|
||||||
|
materials.setLrsj(now);
|
||||||
|
String name = attachDto.getName();
|
||||||
|
materials.setFileType(StringUtils.hasText(name) ? name.split("\\.")[1] : null);
|
||||||
|
materials.setName(name);
|
||||||
|
materials.setSavePath(attachDto.getUrl());
|
||||||
|
materials.setIsOriginal("2");
|
||||||
|
materials.setMaterialsTypeCode("1");
|
||||||
|
materials.setMaterialsTypeName("举报核查材料");
|
||||||
|
materials.setLinkId(save.getPcid());
|
||||||
|
materialsRepo.save(materials);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else log.info("没有数据list");
|
||||||
|
} else log.info("没有数据");
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.info("举报核查获取异常:" + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class ReportCheckInterfaceDto {
|
||||||
|
/**
|
||||||
|
* 数据id
|
||||||
|
*/
|
||||||
|
private String id;
|
||||||
|
/**
|
||||||
|
* 工单编号
|
||||||
|
*/
|
||||||
|
private String work_order_number;
|
||||||
|
/**
|
||||||
|
* 工单等级
|
||||||
|
*/
|
||||||
|
private String work_order_level;
|
||||||
|
/**
|
||||||
|
* 受理时间
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime create_time;
|
||||||
|
/**
|
||||||
|
* 一级举报渠道
|
||||||
|
*/
|
||||||
|
private String complaint_resource_one;
|
||||||
|
/**
|
||||||
|
* 二级举报渠道
|
||||||
|
*/
|
||||||
|
private String complaint_resource_two;
|
||||||
|
/**
|
||||||
|
* 一级投诉类别
|
||||||
|
*/
|
||||||
|
private String complaint_kind_one;
|
||||||
|
/**
|
||||||
|
* 二级投诉类别
|
||||||
|
*/
|
||||||
|
private String complaint_kind_two;
|
||||||
|
/**
|
||||||
|
* 姓名
|
||||||
|
*/
|
||||||
|
private String complainant_name;
|
||||||
|
/**
|
||||||
|
* 联系方式
|
||||||
|
*/
|
||||||
|
private String complaint_phone;
|
||||||
|
/**
|
||||||
|
* 性别
|
||||||
|
*/
|
||||||
|
private String complainant_sex;
|
||||||
|
/**
|
||||||
|
* 投诉时间
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime complaint_time;
|
||||||
|
/**
|
||||||
|
* 举报情况
|
||||||
|
*/
|
||||||
|
private String report_situation;
|
||||||
|
/**
|
||||||
|
* 所属行业
|
||||||
|
*/
|
||||||
|
private String trade;
|
||||||
|
/**
|
||||||
|
* 举报问题所在地
|
||||||
|
*/
|
||||||
|
private String location_data;
|
||||||
|
/* ************************详情字段***********************************/
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
private String remark;
|
||||||
|
/**
|
||||||
|
* 转办区县
|
||||||
|
*/
|
||||||
|
private String transfer_district;
|
||||||
|
/**
|
||||||
|
* 区县回复时间
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime reply_time;
|
||||||
|
/**
|
||||||
|
* 相关材料
|
||||||
|
*/
|
||||||
|
private List<AttachDto> attach;
|
||||||
|
/**
|
||||||
|
* 回复内容
|
||||||
|
*/
|
||||||
|
private String reply_content;
|
||||||
|
/**
|
||||||
|
* 受理状态 1不予受理 2受理中 3 已受理
|
||||||
|
*/
|
||||||
|
private String complaint_status;
|
||||||
|
/**
|
||||||
|
* 受理状态
|
||||||
|
*/
|
||||||
|
private String complaint_status_text;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class AttachDto {
|
||||||
|
private String name;
|
||||||
|
private String uid;
|
||||||
|
private String url;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue