This commit is contained in:
zwt13703 2026-03-14 15:07:24 +08:00
parent 8d02b59bab
commit 65c1809e95
3 changed files with 599 additions and 531 deletions

View File

@ -8,9 +8,8 @@ spring.boot.admin.client:
metadata: metadata:
username: ${spring.boot.admin.client.username} username: ${spring.boot.admin.client.username}
userpassword: ${spring.boot.admin.client.password} userpassword: ${spring.boot.admin.client.password}
username: @monitor.username@ username: ruoyi
password: @monitor.password@ password: 123456
--- # snail-job 配置 --- # snail-job 配置
snail-job: snail-job:
enabled: ${SNAIL_JOB_ENABLED:false} enabled: ${SNAIL_JOB_ENABLED:false}
@ -27,7 +26,6 @@ snail-job:
port: 2${server.port} port: 2${server.port}
# 客户端ip指定 # 客户端ip指定
host: host:
--- # 数据源配置 --- # 数据源配置
spring: spring:
datasource: datasource:
@ -91,7 +89,6 @@ spring:
maxLifetime: 1800000 maxLifetime: 1800000
# 多久检查一次连接的活性 # 多久检查一次连接的活性
keepaliveTime: 30000 keepaliveTime: 30000
--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉) --- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉)
spring.data: spring.data:
redis: redis:
@ -138,7 +135,6 @@ mail:
port: 465 port: 465
# 是否需要用户名密码验证 # 是否需要用户名密码验证
auth: true auth: true
--- # 艺术院校导入配置 --- # 艺术院校导入配置
art: art:
import: import:
@ -158,7 +154,6 @@ art:
timeout: 0 timeout: 0
# Socket连接超时值单位毫秒缺省值不超时 # Socket连接超时值单位毫秒缺省值不超时
connectionTimeout: 0 connectionTimeout: 0
--- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商 --- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商
# https://sms4j.com/doc3/ 差异配置文档地址 支持单厂商多配置,可以配置多个同时使用 # https://sms4j.com/doc3/ 差异配置文档地址 支持单厂商多配置,可以配置多个同时使用
sms: sms:
@ -191,7 +186,6 @@ sms:
signature: 您的短信签名 signature: 您的短信签名
sdk-app-id: 您的sdkAppId sdk-app-id: 您的sdkAppId
--- # 三方授权 --- # 三方授权
justauth: justauth:
# 前端外网访问地址 # 前端外网访问地址

View File

@ -8,9 +8,8 @@ spring.boot.admin.client:
metadata: metadata:
username: ${spring.boot.admin.client.username} username: ${spring.boot.admin.client.username}
userpassword: ${spring.boot.admin.client.password} userpassword: ${spring.boot.admin.client.password}
username: @monitor.username@ username: ruoyi
password: @monitor.password@ password: 123456
--- # snail-job 配置 --- # snail-job 配置
snail-job: snail-job:
enabled: ${SNAIL_JOB_ENABLED:false} enabled: ${SNAIL_JOB_ENABLED:false}
@ -27,7 +26,6 @@ snail-job:
port: 2${server.port} port: 2${server.port}
# 客户端ip指定 # 客户端ip指定
host: host:
--- # 数据源配置 --- # 数据源配置
spring: spring:
datasource: datasource:
@ -91,7 +89,6 @@ spring:
maxLifetime: 1800000 maxLifetime: 1800000
# 多久检查一次连接的活性 # 多久检查一次连接的活性
keepaliveTime: 30000 keepaliveTime: 30000
--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉) --- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉)
spring.data: spring.data:
redis: redis:
@ -138,7 +135,6 @@ mail:
port: 465 port: 465
# 是否需要用户名密码验证 # 是否需要用户名密码验证
auth: true auth: true
--- # 艺术院校导入配置 --- # 艺术院校导入配置
art: art:
import: import:
@ -158,7 +154,6 @@ art:
timeout: 0 timeout: 0
# Socket连接超时值单位毫秒缺省值不超时 # Socket连接超时值单位毫秒缺省值不超时
connectionTimeout: 0 connectionTimeout: 0
--- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商 --- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商
# https://sms4j.com/doc3/ 差异配置文档地址 支持单厂商多配置,可以配置多个同时使用 # https://sms4j.com/doc3/ 差异配置文档地址 支持单厂商多配置,可以配置多个同时使用
sms: sms:
@ -191,7 +186,6 @@ sms:
signature: 您的短信签名 signature: 您的短信签名
sdk-app-id: 您的sdkAppId sdk-app-id: 您的sdkAppId
--- # 三方授权 --- # 三方授权
justauth: justauth:
# 前端外网访问地址 # 前端外网访问地址

View File

@ -2,24 +2,6 @@ package org.dromara.art.controller;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import lombok.RequiredArgsConstructor;
import org.dromara.art.domain.bo.*;
import org.dromara.art.domain.vo.ArtSchoolImportDetailVo;
import org.dromara.art.domain.vo.ArtSchoolJsonImportPreviewVo;
import org.dromara.art.domain.vo.ArtSchoolVo;
import org.dromara.art.service.IArtSchoolDetailService;
import org.dromara.art.service.IArtSchoolService;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.core.domain.R;
import org.dromara.common.web.core.BaseController;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.nio.file.Files; import java.nio.file.Files;
@ -29,6 +11,23 @@ import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Stream; import java.util.stream.Stream;
import lombok.RequiredArgsConstructor;
import org.dromara.art.domain.bo.*;
import org.dromara.art.domain.vo.ArtSchoolImportDetailVo;
import org.dromara.art.domain.vo.ArtSchoolJsonImportPreviewVo;
import org.dromara.art.domain.vo.ArtSchoolVo;
import org.dromara.art.service.IArtSchoolDetailService;
import org.dromara.art.service.IArtSchoolService;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.web.core.BaseController;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@Validated @Validated
@RequiredArgsConstructor @RequiredArgsConstructor
@ -38,12 +37,16 @@ public class ArtTestController extends BaseController {
private final IArtSchoolService artSchoolService; private final IArtSchoolService artSchoolService;
private final IArtSchoolDetailService artSchoolDetailService; private final IArtSchoolDetailService artSchoolDetailService;
@Value("${art.import.schoolJsonDir:}") @Value("${art.import.schoolJsonDir:}")
private String schoolJsonDir; private String schoolJsonDir;
@GetMapping("/importSchoolByJson") @GetMapping("/importSchoolByJson")
public R<ArtSchoolJsonImportPreviewVo> importSchoolByJson(@RequestParam(defaultValue = "20") Integer previewSize) { public R<ArtSchoolJsonImportPreviewVo> importSchoolByJson(
int safePreviewSize = previewSize == null ? 20 : Math.min(Math.max(previewSize, 1), 200); @RequestParam(defaultValue = "20") Integer previewSize
) {
int safePreviewSize =
previewSize == null ? 20 : Math.min(Math.max(previewSize, 1), 200);
Path sourceDir; Path sourceDir;
if (StringUtils.isNotBlank(schoolJsonDir)) { if (StringUtils.isNotBlank(schoolJsonDir)) {
sourceDir = Path.of(schoolJsonDir.trim()); sourceDir = Path.of(schoolJsonDir.trim());
@ -77,38 +80,68 @@ public class ArtTestController extends BaseController {
for (Path file : fileList) { for (Path file : fileList) {
String fileName = file.getFileName().toString(); String fileName = file.getFileName().toString();
System.out.println("处理文件:" + fileName);
JsonNode root; JsonNode root;
try { try {
root = JsonUtils.getObjectMapper().readTree(file.toFile()); root = JsonUtils.getObjectMapper().readTree(file.toFile());
} catch (Exception e) { } catch (Exception e) {
readFailCount++; readFailCount++;
appendDetail(details, safePreviewSize, null, null, "FAILED", fileName + " 读取失败: " + e.getMessage()); appendDetail(
details,
safePreviewSize,
null,
null,
"FAILED",
fileName + " 读取失败: " + e.getMessage()
);
continue; continue;
} }
List<JsonNode> schoolNodes = extractSchoolNodes(root); List<JsonNode> schoolNodes = extractSchoolNodes(root);
if (CollUtil.isEmpty(schoolNodes)) { if (CollUtil.isEmpty(schoolNodes)) {
invalidCount++; invalidCount++;
appendDetail(details, safePreviewSize, null, null, "INVALID", fileName + " 缺少有效学校对象"); appendDetail(
details,
safePreviewSize,
null,
null,
"INVALID",
fileName + " 缺少有效学校对象"
);
continue; continue;
} }
for (int i = 0; i < schoolNodes.size(); i++) { for (int i = 0; i < schoolNodes.size(); i++) {
JsonNode schoolNode = schoolNodes.get(i); JsonNode schoolNode = schoolNodes.get(i);
String sourceTag = schoolNodes.size() == 1 ? fileName : (fileName + "#" + i); String sourceTag =
schoolNodes.size() == 1 ? fileName : (fileName + "#" + i);
Integer univId = asInteger(schoolNode.get("univId")); Integer univId = asInteger(schoolNode.get("univId"));
String mainName = asText(schoolNode.get("univName")); String mainName = asText(schoolNode.get("univName"));
if (univId == null || StringUtils.isBlank(mainName)) { if (univId == null || StringUtils.isBlank(mainName)) {
invalidCount++; invalidCount++;
appendDetail(details, safePreviewSize, null, mainName, "INVALID", sourceTag + " 缺少必填字段: univId/univName"); appendDetail(
details,
safePreviewSize,
null,
mainName,
"INVALID",
sourceTag + " 缺少必填字段: univId/univName"
);
continue; continue;
} }
String mainCode = String.valueOf(univId); String mainCode = String.valueOf(univId);
if (!fileUnivIdSet.add(univId) || !fileMainCodeSet.add(mainCode)) { if (!fileUnivIdSet.add(univId) || !fileMainCodeSet.add(mainCode)) {
duplicateInFileCount++; duplicateInFileCount++;
appendDetail(details, safePreviewSize, mainCode, mainName, "DUPLICATE_FILE", sourceTag + " 文件内重复univId/mainCode"); appendDetail(
details,
safePreviewSize,
mainCode,
mainName,
"DUPLICATE_FILE",
sourceTag + " 文件内重复univId/mainCode"
);
continue; continue;
} }
@ -118,9 +151,22 @@ public class ArtTestController extends BaseController {
continue; continue;
}*/ }*/
ArtSchoolSubmitBo submitBo = buildSubmitBo(schoolNode, sourceTag, univId, mainCode, mainName); ArtSchoolSubmitBo submitBo = buildSubmitBo(
schoolNode,
sourceTag,
univId,
mainCode,
mainName
);
readyCount++; readyCount++;
appendDetail(details, safePreviewSize, mainCode, mainName, "READY", sourceTag + " 已完成结构映射,待入库"); appendDetail(
details,
safePreviewSize,
mainCode,
mainName,
"READY",
sourceTag + " 已完成结构映射,待入库"
);
if (submitPreviewList.size() < safePreviewSize) { if (submitPreviewList.size() < safePreviewSize) {
submitPreviewList.add(toPreviewSubmitBo(submitBo)); submitPreviewList.add(toPreviewSubmitBo(submitBo));
@ -137,7 +183,9 @@ public class ArtTestController extends BaseController {
List<ArtSchoolVo> artSchoolVos = artSchoolService.queryList(artSchoolBo); List<ArtSchoolVo> artSchoolVos = artSchoolService.queryList(artSchoolBo);
if (!artSchoolVos.isEmpty()) { if (!artSchoolVos.isEmpty()) {
// 修改 // 修改
artSchoolSubmitBo.getSchool().setSchoolId(artSchoolVos.get(0).getSchoolId()); artSchoolSubmitBo
.getSchool()
.setSchoolId(artSchoolVos.get(0).getSchoolId());
artSchoolService.updateWithDetailByBo(artSchoolSubmitBo); artSchoolService.updateWithDetailByBo(artSchoolSubmitBo);
} else { } else {
artSchoolService.insertWithDetailByBo(artSchoolSubmitBo); artSchoolService.insertWithDetailByBo(artSchoolSubmitBo);
@ -150,7 +198,9 @@ public class ArtTestController extends BaseController {
previewVo.setReadFailCount(readFailCount); previewVo.setReadFailCount(readFailCount);
previewVo.setDetails(details); previewVo.setDetails(details);
previewVo.setSubmitPreviewList(submitPreviewList); previewVo.setSubmitPreviewList(submitPreviewList);
previewVo.setServiceCallHint("已预留调用: artSchoolService.insertWithDetailByBo(submitBo)"); previewVo.setServiceCallHint(
"已预留调用: artSchoolService.insertWithDetailByBo(submitBo)"
);
return R.ok(previewVo); return R.ok(previewVo);
} }
@ -196,7 +246,13 @@ public class ArtTestController extends BaseController {
return CollUtil.isNotEmpty(artSchoolDetailService.queryList(detailBo)); return CollUtil.isNotEmpty(artSchoolDetailService.queryList(detailBo));
} }
private ArtSchoolSubmitBo buildSubmitBo(JsonNode node, String sourceTag, Integer univId, String mainCode, String mainName) { private ArtSchoolSubmitBo buildSubmitBo(
JsonNode node,
String sourceTag,
Integer univId,
String mainCode,
String mainName
) {
ArtSchoolBo school = new ArtSchoolBo(); ArtSchoolBo school = new ArtSchoolBo();
school.setMainCode(mainCode); school.setMainCode(mainCode);
school.setMainName(mainName); school.setMainName(mainName);
@ -227,8 +283,12 @@ public class ArtTestController extends BaseController {
detail.setIs985(normalizeFlag(asInteger(node.get("is985")))); detail.setIs985(normalizeFlag(asInteger(node.get("is985"))));
detail.setIs211(normalizeFlag(asInteger(node.get("is211")))); detail.setIs211(normalizeFlag(asInteger(node.get("is211"))));
detail.setIsDoubleFirstClass(normalizeFlag(asInteger(node.get("isFirstClass")))); detail.setIsDoubleFirstClass(
detail.setIsKeyUniversity(normalizeFlag(asInteger(node.get("isFirstLevel")))); normalizeFlag(asInteger(node.get("isFirstClass")))
);
detail.setIsKeyUniversity(
normalizeFlag(asInteger(node.get("isFirstLevel")))
);
detail.setIsPublic(normalizeFlag(asInteger(node.get("isPublic")))); detail.setIsPublic(normalizeFlag(asInteger(node.get("isPublic"))));
detail.setMasterProportionRate(asDecimal(node.get("masterProportion"))); // 考研率 detail.setMasterProportionRate(asDecimal(node.get("masterProportion"))); // 考研率
@ -238,7 +298,9 @@ public class ArtTestController extends BaseController {
detail.setHasJunior(normalizeFlag(asInteger(node.get("hasJunior")))); // 是否有专科 detail.setHasJunior(normalizeFlag(asInteger(node.get("hasJunior")))); // 是否有专科
detail.setHasMaster(normalizeFlag(asInteger(node.get("hasMaster")))); // 是否有研究生 detail.setHasMaster(normalizeFlag(asInteger(node.get("hasMaster")))); // 是否有研究生
detail.setIsDoubleHighPlan(normalizeFlag(asInteger(node.get("isDoubleHighPlan")))); // 是否双高计划专科用 detail.setIsDoubleHighPlan(
normalizeFlag(asInteger(node.get("isDoubleHighPlan")))
); // 是否双高计划专科用
detail.setIsStrongPlan(normalizeFlag(asInteger(node.get("isStrongPlan")))); // 是否强基计划 detail.setIsStrongPlan(normalizeFlag(asInteger(node.get("isStrongPlan")))); // 是否强基计划
detail.setTwsdlRank(normalizeFlag(asInteger(node.get("twsdl")))); detail.setTwsdlRank(normalizeFlag(asInteger(node.get("twsdl"))));
detail.setXyhRank(normalizeFlag(asInteger(node.get("xyh")))); detail.setXyhRank(normalizeFlag(asInteger(node.get("xyh"))));
@ -280,7 +342,9 @@ public class ArtTestController extends BaseController {
detail.setSubjectReviewsJson(toJsonString(node.get("subjectReviews"))); detail.setSubjectReviewsJson(toJsonString(node.get("subjectReviews")));
detail.setResearchJson(toJsonString(node.get("researchJson"))); detail.setResearchJson(toJsonString(node.get("researchJson")));
detail.setUnivMajorsJson(toJsonString(node.get("univMajors"))); detail.setUnivMajorsJson(toJsonString(node.get("univMajors")));
detail.setUnivPostgraduateJson(toJsonString(node.get("univPostgraduateList"))); detail.setUnivPostgraduateJson(
toJsonString(node.get("univPostgraduateList"))
);
detail.setUnivId(univId); detail.setUnivId(univId);
//detail.setRemark("source=" + sourceTag); //detail.setRemark("source=" + sourceTag);
@ -300,7 +364,9 @@ public class ArtTestController extends BaseController {
if (college.has("majorList")) { if (college.has("majorList")) {
for (JsonNode major : college.get("majorList")) { for (JsonNode major : college.get("majorList")) {
artSchoolMajorBo = new ArtSchoolMajorBo(); artSchoolMajorBo = new ArtSchoolMajorBo();
artSchoolMajorBo.setEducationLevel("(本)".equals(asText(major.get("majorLevel"))) ? "1" : "0"); artSchoolMajorBo.setEducationLevel(
"(本)".equals(asText(major.get("majorLevel"))) ? "1" : "0"
);
artSchoolMajorBo.setMajorName(asText(major.get("majorName"))); artSchoolMajorBo.setMajorName(asText(major.get("majorName")));
artSchoolMajorBo.setMajor51sdxId(asText(major.get("majorId"))); artSchoolMajorBo.setMajor51sdxId(asText(major.get("majorId")));
schoolMajorBoList.add(artSchoolMajorBo); schoolMajorBoList.add(artSchoolMajorBo);
@ -310,8 +376,6 @@ public class ArtTestController extends BaseController {
schoolCollegeBoList.add(schoolCollegeBo); schoolCollegeBoList.add(schoolCollegeBo);
} }
// 其余结构化内容已映射到详情 JSON 字段 // 其余结构化内容已映射到详情 JSON 字段
ArtSchoolSubmitBo submitBo = new ArtSchoolSubmitBo(); ArtSchoolSubmitBo submitBo = new ArtSchoolSubmitBo();
@ -409,12 +473,16 @@ public class ArtTestController extends BaseController {
if (guojiatese != null) { if (guojiatese != null) {
return guojiatese; return guojiatese;
} }
return asInteger(node.path("researchJson").path("base").get("重点专业数量")); return asInteger(
node.path("researchJson").path("base").get("重点专业数量")
);
} }
private BigDecimal resolveEmploymentRate(JsonNode node) { private BigDecimal resolveEmploymentRate(JsonNode node) {
BigDecimal employmentRate = asDecimal(node.get("jiuyelu")); BigDecimal employmentRate = asDecimal(node.get("jiuyelu"));
return employmentRate == null ? null : employmentRate.setScale(2, RoundingMode.HALF_UP); return employmentRate == null
? null
: employmentRate.setScale(2, RoundingMode.HALF_UP);
} }
private BigDecimal resolveSatisfactionRate(JsonNode node) { private BigDecimal resolveSatisfactionRate(JsonNode node) {
@ -423,7 +491,9 @@ public class ArtTestController extends BaseController {
return null; return null;
} }
if (score.compareTo(new BigDecimal("5")) <= 0) { if (score.compareTo(new BigDecimal("5")) <= 0) {
return score.multiply(new BigDecimal("20")).setScale(2, RoundingMode.HALF_UP); return score
.multiply(new BigDecimal("20"))
.setScale(2, RoundingMode.HALF_UP);
} }
return score.setScale(2, RoundingMode.HALF_UP); return score.setScale(2, RoundingMode.HALF_UP);
} }
@ -432,7 +502,9 @@ public class ArtTestController extends BaseController {
if (femaleRatio == null) { if (femaleRatio == null) {
return null; return null;
} }
return new BigDecimal("100").subtract(femaleRatio).setScale(2, RoundingMode.HALF_UP); return new BigDecimal("100")
.subtract(femaleRatio)
.setScale(2, RoundingMode.HALF_UP);
} }
private String resolveEducationLevel(JsonNode node) { private String resolveEducationLevel(JsonNode node) {
@ -510,7 +582,9 @@ public class ArtTestController extends BaseController {
if (node == null || node.isNull()) { if (node == null || node.isNull()) {
return null; return null;
} }
String text = node.isNumber() ? node.numberValue().toString() : asText(node); String text = node.isNumber()
? node.numberValue().toString()
: asText(node);
if (StringUtils.isBlank(text)) { if (StringUtils.isBlank(text)) {
return null; return null;
} }
@ -529,7 +603,14 @@ public class ArtTestController extends BaseController {
return JsonUtils.toJsonString(node); return JsonUtils.toJsonString(node);
} }
private void appendDetail(List<ArtSchoolImportDetailVo> details, int maxSize, String mainCode, String mainName, String status, String message) { private void appendDetail(
List<ArtSchoolImportDetailVo> details,
int maxSize,
String mainCode,
String mainName,
String status,
String message
) {
if (details.size() >= maxSize) { if (details.size() >= maxSize) {
return; return;
} }
@ -540,5 +621,4 @@ public class ArtTestController extends BaseController {
detailVo.setMessage(message); detailVo.setMessage(message);
details.add(detailVo); details.add(detailVo);
} }
} }