【新增】PS考点设置后端
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
package pc.exam.pp.module.judgement.controller.admin.Ps;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import pc.exam.pp.module.judgement.controller.service.mysql.IMysqlServerice;
|
||||
import pc.exam.pp.module.judgement.controller.service.ps.IPsService;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/tool/Ps")
|
||||
public class PsController {
|
||||
|
||||
@Autowired
|
||||
private IPsService psService;
|
||||
|
||||
|
||||
}
|
@@ -7,6 +7,7 @@ import org.springframework.web.bind.annotation.*;
|
||||
import pc.exam.pp.framework.common.pojo.CommonResult;
|
||||
import pc.exam.pp.framework.tenant.core.aop.TenantIgnore;
|
||||
import pc.exam.pp.module.exam.dal.dataobject.ExamQuestionAnswer;
|
||||
import pc.exam.pp.module.judgement.controller.admin.getpoints.dto.PsAnswerSubmitDTO;
|
||||
import pc.exam.pp.module.judgement.controller.admin.getpoints.vo.Points;
|
||||
import pc.exam.pp.module.judgement.controller.admin.getpoints.vo.PointsVo;
|
||||
import pc.exam.pp.module.judgement.controller.service.getpoints.ExamGetPointsService;
|
||||
@@ -76,4 +77,41 @@ public class GetPointsController {
|
||||
public CommonResult get_browser_point(@RequestBody Points points) {
|
||||
return CommonResult.success(examGetPointsService.get_browser_point(points));
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件得出PS操作考点
|
||||
* @return 得分
|
||||
*/
|
||||
@Operation(summary = "文件得出PS操作考点")
|
||||
@PostMapping("/get_ps_point")
|
||||
@TenantIgnore
|
||||
public CommonResult get_ps_point(@RequestBody PointsVo pointsVo) throws IOException {
|
||||
try {
|
||||
return CommonResult.success(examGetPointsService.get_ps_point(pointsVo));
|
||||
|
||||
} catch (RuntimeException e) {
|
||||
return CommonResult.error(987312, e.getMessage());
|
||||
} catch (InterruptedException e) {
|
||||
return CommonResult.error(987312, e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* 设置PS操作考点
|
||||
* @return 得分
|
||||
*/
|
||||
@Operation(summary = "文件设置PS操作考点")
|
||||
@PostMapping("/set_ps_point")
|
||||
@TenantIgnore
|
||||
public void set_ps_point(@RequestBody PsAnswerSubmitDTO psAnswerSubmitDTO) {
|
||||
examGetPointsService.set_ps_point(psAnswerSubmitDTO);
|
||||
}
|
||||
@Operation(summary = "获取PS操作考点")
|
||||
@GetMapping("/getPsPointById/{quId}")
|
||||
@TenantIgnore
|
||||
public CommonResult getPsPointById(@PathVariable("quId") String quId) {
|
||||
return CommonResult.success(examGetPointsService.getPsPointById(quId));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,20 @@
|
||||
package pc.exam.pp.module.judgement.controller.admin.getpoints.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class PsAnswerNode {
|
||||
private String key;
|
||||
|
||||
private String value;
|
||||
|
||||
private Integer rate;
|
||||
|
||||
private List<PsAnswerNode> children;
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
package pc.exam.pp.module.judgement.controller.admin.getpoints.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class PsAnswerSubmitDTO {
|
||||
private String quId;
|
||||
private List<PsAnswerNode> questionAnswerList;
|
||||
private String type;
|
||||
}
|
||||
|
@@ -0,0 +1,17 @@
|
||||
package pc.exam.pp.module.judgement.controller.admin.getpoints.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
import pc.exam.pp.module.judgement.controller.admin.getpoints.vo.PsVo;
|
||||
|
||||
import java.util.List;
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class PsViewDto {
|
||||
private List<PsVo> pointList;
|
||||
|
||||
private List<PsVo> answerList;
|
||||
}
|
@@ -8,7 +8,9 @@ import lombok.NoArgsConstructor;
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class PointsVo {
|
||||
//原始文件路径
|
||||
private String shucaiPath;
|
||||
//答案文件路径
|
||||
private String answerPath;
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,18 @@
|
||||
package pc.exam.pp.module.judgement.controller.admin.getpoints.vo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class PsVo {
|
||||
|
||||
private String key;
|
||||
|
||||
private String value;
|
||||
|
||||
private List<PsVo> children;
|
||||
}
|
@@ -1,6 +1,9 @@
|
||||
package pc.exam.pp.module.judgement.controller.service.getpoints;
|
||||
|
||||
import pc.exam.pp.module.exam.dal.dataobject.ExamPsKeyword;
|
||||
import pc.exam.pp.module.exam.dal.dataobject.ExamQuestionAnswer;
|
||||
import pc.exam.pp.module.judgement.controller.admin.getpoints.dto.PsAnswerSubmitDTO;
|
||||
import pc.exam.pp.module.judgement.controller.admin.getpoints.dto.PsViewDto;
|
||||
import pc.exam.pp.module.judgement.controller.admin.getpoints.vo.FilePointsVo;
|
||||
import pc.exam.pp.module.judgement.controller.admin.getpoints.vo.Points;
|
||||
import pc.exam.pp.module.judgement.controller.admin.getpoints.vo.PointsVo;
|
||||
@@ -23,4 +26,10 @@ public interface ExamGetPointsService {
|
||||
boolean update_mysql_point(Points points);
|
||||
|
||||
List<ExamQuestionAnswer> getPointById(String quId);
|
||||
|
||||
PsViewDto get_ps_point(PointsVo pointsVo) throws RuntimeException, IOException, InterruptedException;
|
||||
|
||||
void set_ps_point(PsAnswerSubmitDTO psAnswerSubmitDTO);
|
||||
|
||||
PsViewDto getPsPointById(String quId);
|
||||
}
|
||||
|
@@ -1,12 +1,17 @@
|
||||
package pc.exam.pp.module.judgement.controller.service.getpoints;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.xingyuv.jushauth.utils.UuidUtils;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.ibatis.executor.BatchResult;
|
||||
import org.springframework.stereotype.Service;
|
||||
import pc.exam.pp.module.exam.controller.admin.exception.PsException;
|
||||
import pc.exam.pp.module.exam.dal.dataobject.ExamMysqlKeyword;
|
||||
import pc.exam.pp.module.exam.dal.dataobject.ExamPsKeyword;
|
||||
import pc.exam.pp.module.exam.dal.dataobject.ExamQuestionAnswer;
|
||||
import pc.exam.pp.module.exam.dal.mysql.mysqlkeyword.MysqlKeywordMapper;
|
||||
import pc.exam.pp.module.exam.dal.mysql.question.ExamQuestionAnswerMapper;
|
||||
@@ -15,17 +20,22 @@ import pc.exam.pp.module.exam.utils.file.GetDifferencesBetweenFolders;
|
||||
import pc.exam.pp.module.exam.utils.uuid.IdUtils;
|
||||
import pc.exam.pp.module.infra.dal.dataobject.config.ConfigDO;
|
||||
import pc.exam.pp.module.infra.service.config.ConfigService;
|
||||
import pc.exam.pp.module.judgement.controller.admin.getpoints.vo.FileNode;
|
||||
import pc.exam.pp.module.judgement.controller.admin.getpoints.vo.FilePointsVo;
|
||||
import pc.exam.pp.module.judgement.controller.admin.getpoints.vo.Points;
|
||||
import pc.exam.pp.module.judgement.controller.admin.getpoints.vo.PointsVo;
|
||||
import pc.exam.pp.module.judgement.controller.admin.getpoints.dto.PsAnswerNode;
|
||||
import pc.exam.pp.module.judgement.controller.admin.getpoints.dto.PsAnswerSubmitDTO;
|
||||
import pc.exam.pp.module.judgement.controller.admin.getpoints.dto.PsViewDto;
|
||||
import pc.exam.pp.module.judgement.controller.admin.getpoints.vo.*;
|
||||
import pc.exam.pp.module.judgement.controller.service.ps.IPsService;
|
||||
import pc.exam.pp.module.judgement.controller.utils.ps.PsUtil;
|
||||
import pc.exam.pp.module.judgement.controller.utils.zip.ZipUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.MalformedInputException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
@@ -43,7 +53,8 @@ public class ExamGetPointsServiceImpl implements ExamGetPointsService{
|
||||
MysqlKeywordMapper mysqlKeywordMapper;
|
||||
@Resource
|
||||
private ExamQuestionAnswerMapper examQuestionAnswerMapper;
|
||||
|
||||
@Resource
|
||||
private IPsService psService;
|
||||
|
||||
@Override
|
||||
public FilePointsVo get_file_point(PointsVo pointsVo) throws IOException {
|
||||
@@ -375,5 +386,322 @@ public class ExamGetPointsServiceImpl implements ExamGetPointsService{
|
||||
return examQuestionAnswers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsViewDto get_ps_point(PointsVo pointsVo) throws RuntimeException {
|
||||
String timestamp = String.valueOf(System.currentTimeMillis());
|
||||
String baseDir = "ps\\" + timestamp;
|
||||
|
||||
// 下载学生文件和答案文件
|
||||
String sthPath = downloadStudentFile(pointsVo.getShucaiPath(), baseDir);
|
||||
String answerPath = downloadStudentFile(pointsVo.getAnswerPath(), baseDir);
|
||||
|
||||
System.out.println("学生PSD路径: " + sthPath);
|
||||
System.out.println("答案PSD路径: " + answerPath);
|
||||
|
||||
String sthJsonPath = sthPath.replaceAll("(?i)\\.psd$", ".json");
|
||||
String answerJsonPath = answerPath.replaceAll("(?i)\\.psd$", ".json");
|
||||
|
||||
String photoshopExe = PsUtil.findPhotoshopExe();
|
||||
if (photoshopExe == null) {
|
||||
throw new PsException("请先在本机安装PS软件!");
|
||||
}
|
||||
|
||||
String homeDir = System.getProperty("user.dir");
|
||||
String jsxTemplatePath = homeDir + "\\ps\\checkPSD.jsx"; // 模板路径
|
||||
|
||||
try {
|
||||
// 执行学生和答案PSD文件
|
||||
runTwoPsdsInOneScript(sthPath, answerPath, jsxTemplatePath, photoshopExe);
|
||||
System.out.println("Photoshop脚本执行完毕");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("执行 Photoshop 脚本失败: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
// 读取两个 JSON 文件
|
||||
try {
|
||||
String sthJsonStr = Files.readString(Paths.get(sthJsonPath), StandardCharsets.UTF_8);
|
||||
String answerJsonStr = Files.readString(Paths.get(answerJsonPath), StandardCharsets.UTF_8);
|
||||
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
Map<String,Object> jsonStuMap = mapper.readValue(sthJsonStr, new TypeReference<Map<String,Object>>() {});
|
||||
List<PsVo> stulist = new ArrayList<>();
|
||||
for (Map.Entry<String, Object> entry : jsonStuMap.entrySet()) {
|
||||
stulist.add(mapToPsVo(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
Map<String,Object> jsonAnswerMap = mapper.readValue(answerJsonStr, new TypeReference<Map<String,Object>>() {});
|
||||
List<PsVo> answerlist = new ArrayList<>();
|
||||
for (Map.Entry<String, Object> entry : jsonAnswerMap.entrySet()) {
|
||||
answerlist.add(mapToPsVo(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
|
||||
|
||||
System.out.println("✅ 学生PSD数据: " + stulist);
|
||||
System.out.println("✅ 答案PSD数据: " + answerlist);
|
||||
PsViewDto psViewDto=new PsViewDto();
|
||||
|
||||
List<PsVo> pointList = findExtraOrDifferentInAnswer(stulist, answerlist);
|
||||
System.out.println("答案相对考生多出来的节点集合: " + pointList);
|
||||
|
||||
psViewDto.setPointList(pointList);
|
||||
psViewDto.setAnswerList(answerlist);
|
||||
|
||||
return psViewDto;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace(); // 打印异常堆栈
|
||||
throw new PsException("读取 JSON 文件失败!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set_ps_point(PsAnswerSubmitDTO psAnswerSubmitDTO) {
|
||||
List<ExamPsKeyword> stuList = new ArrayList<>();
|
||||
String quId = String.valueOf(psAnswerSubmitDTO.getQuId());
|
||||
|
||||
// 开始递归转换 学生考点
|
||||
for (PsAnswerNode node : psAnswerSubmitDTO.getQuestionAnswerList()) {
|
||||
convertNodeToKeyword(node, "0", quId, stuList);
|
||||
}
|
||||
//给List统一设置type
|
||||
String type = psAnswerSubmitDTO.getType();
|
||||
for (ExamPsKeyword keyword : stuList) {
|
||||
keyword.setType(type);
|
||||
}
|
||||
stuList.forEach(System.out::println);
|
||||
//先根据删除试题id删除
|
||||
psService.deletedKeywordById(quId);
|
||||
//再更新
|
||||
psService.insertPsKeywordList(stuList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsViewDto getPsPointById(String quId) {
|
||||
PsViewDto psViewDto=new PsViewDto();
|
||||
List<PsVo> pointList=psService.selectPsPointByType(quId,"1");
|
||||
List<PsVo> answerList=psService.selectPsPointByType(quId,"2");
|
||||
psViewDto.setAnswerList(answerList);
|
||||
psViewDto.setPointList(pointList);
|
||||
return psViewDto;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 递归转换方法
|
||||
private void convertNodeToKeyword(PsAnswerNode node, String parentId, String quId, List<ExamPsKeyword> resultList) {
|
||||
// 生成唯一 ID(用 UUID 或其它方式)
|
||||
String id = IdUtils.simpleUUID();
|
||||
|
||||
ExamPsKeyword keyword = new ExamPsKeyword();
|
||||
keyword.setId(id);
|
||||
keyword.setQuId(quId);
|
||||
keyword.setParentId(parentId);
|
||||
keyword.setKeyName(node.getKey());
|
||||
keyword.setKeyValue(node.getValue());
|
||||
keyword.setRate(node.getRate() == null ? null : node.getRate().toString());
|
||||
resultList.add(keyword);
|
||||
|
||||
// 递归子节点
|
||||
if (node.getChildren() != null) {
|
||||
for (PsAnswerNode child : node.getChildren()) {
|
||||
convertNodeToKeyword(child, id, quId, resultList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public List<PsVo> findExtraOrDifferentInAnswer(List<PsVo> stuList, List<PsVo> answerList) {
|
||||
if (answerList == null) return Collections.emptyList();
|
||||
if (stuList == null) stuList = Collections.emptyList();
|
||||
|
||||
// 把学生列表转为 key->PsVo 映射
|
||||
Map<String, PsVo> stuMap = stuList.stream()
|
||||
.collect(Collectors.toMap(PsVo::getKey, p -> p, (a, b) -> a));
|
||||
|
||||
List<PsVo> extraList = new ArrayList<>();
|
||||
|
||||
for (PsVo ansNode : answerList) {
|
||||
PsVo stuNode = stuMap.get(ansNode.getKey());
|
||||
|
||||
if (stuNode == null) {
|
||||
// 学生没有该键,整项加入
|
||||
extraList.add(ansNode);
|
||||
} else {
|
||||
boolean valueDifferent = !Objects.equals(ansNode.getValue(), stuNode.getValue());
|
||||
|
||||
// 递归对比子节点
|
||||
List<PsVo> ansChildren = ansNode.getChildren() != null ? ansNode.getChildren() : Collections.emptyList();
|
||||
List<PsVo> stuChildren = stuNode.getChildren() != null ? stuNode.getChildren() : Collections.emptyList();
|
||||
List<PsVo> childDiffs = findExtraOrDifferentInAnswer(stuChildren, ansChildren);
|
||||
|
||||
if (valueDifferent || !childDiffs.isEmpty()) {
|
||||
PsVo diffNode = new PsVo();
|
||||
diffNode.setKey(ansNode.getKey());
|
||||
diffNode.setValue(valueDifferent ? ansNode.getValue() : null);
|
||||
diffNode.setChildren(childDiffs.isEmpty() ? null : childDiffs);
|
||||
extraList.add(diffNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return extraList;
|
||||
}
|
||||
|
||||
|
||||
public PsVo mapToPsVo(String key, Object value) {
|
||||
PsVo vo = new PsVo();
|
||||
vo.setKey(key);
|
||||
|
||||
if (value instanceof Map) {
|
||||
Map<String, Object> map = (Map<String, Object>) value;
|
||||
List<PsVo> children = new ArrayList<>();
|
||||
for (Map.Entry<String, Object> entry : map.entrySet()) {
|
||||
children.add(mapToPsVo(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
vo.setChildren(children);
|
||||
vo.setValue(null);
|
||||
|
||||
} else if (value instanceof List) {
|
||||
List<?> list = (List<?>) value;
|
||||
List<PsVo> children = new ArrayList<>();
|
||||
|
||||
for (Object item : list) {
|
||||
if (item instanceof Map) {
|
||||
Map<String, Object> mapItem = (Map<String, Object>) item;
|
||||
// 获取图层名作为 key
|
||||
String layerName = (String) mapItem.get("图层名");
|
||||
if (layerName == null) {
|
||||
// 如果没有图层名,直接用空字符串
|
||||
layerName = "";
|
||||
}
|
||||
PsVo childVo = new PsVo();
|
||||
childVo.setKey(layerName);
|
||||
|
||||
// 除了图层名外的字段作为 children
|
||||
List<PsVo> grandChildren = new ArrayList<>();
|
||||
for (Map.Entry<String, Object> e : mapItem.entrySet()) {
|
||||
if (!"图层名".equals(e.getKey())) {
|
||||
grandChildren.add(mapToPsVo(e.getKey(), e.getValue()));
|
||||
}
|
||||
}
|
||||
childVo.setChildren(grandChildren);
|
||||
childVo.setValue(null);
|
||||
|
||||
children.add(childVo);
|
||||
} else {
|
||||
// 如果不是 Map 类型,按原逻辑处理
|
||||
children.add(mapToPsVo(null, item));
|
||||
}
|
||||
}
|
||||
vo.setChildren(children);
|
||||
vo.setValue(null);
|
||||
|
||||
} else {
|
||||
// 基础类型
|
||||
vo.setValue(value == null ? null : value.toString());
|
||||
vo.setChildren(null);
|
||||
}
|
||||
return vo;
|
||||
}
|
||||
|
||||
private void runTwoPsdsInOneScript(String psdPath1, String psdPath2, String jsxTemplatePath, String photoshopExe)
|
||||
throws IOException, InterruptedException {
|
||||
|
||||
File psdFile1 = new File(psdPath1);
|
||||
String baseDir = psdFile1.getParent();
|
||||
String jsxTargetPath = baseDir + File.separator + "run_both_" + System.currentTimeMillis() + ".jsx";
|
||||
|
||||
String jsxTemplate = Files.readString(Paths.get(jsxTemplatePath), StandardCharsets.UTF_8);
|
||||
|
||||
String safePath1 = psdPath1.replace("\\", "\\\\").replace("'", "\\'");
|
||||
String safePath2 = psdPath2.replace("\\", "\\\\").replace("'", "\\'");
|
||||
String jsxContent = jsxTemplate
|
||||
.replace("${inputPath1}", safePath1)
|
||||
.replace("${inputPath2}", safePath2);
|
||||
|
||||
Files.writeString(Paths.get(jsxTargetPath), jsxContent, StandardCharsets.UTF_8);
|
||||
|
||||
String command = String.format("\"%s\" -r \"%s\"", photoshopExe, jsxTargetPath);
|
||||
System.out.println("运行 Photoshop 脚本: " + command);
|
||||
|
||||
Process process = Runtime.getRuntime().exec(command);
|
||||
|
||||
// 异步打印输出日志
|
||||
new Thread(() -> {
|
||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
System.out.println("[PS OUT] " + line);
|
||||
}
|
||||
} catch (IOException ignored) {}
|
||||
}).start();
|
||||
|
||||
new Thread(() -> {
|
||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
System.err.println("[PS ERR] " + line);
|
||||
}
|
||||
} catch (IOException ignored) {}
|
||||
}).start();
|
||||
|
||||
// 不使用 waitFor 阻塞,改成轮询判断两个 JSON 文件是否生成
|
||||
String jsonPath1 = psdPath1.replaceAll("(?i)\\.psd$", ".json");
|
||||
String jsonPath2 = psdPath2.replaceAll("(?i)\\.psd$", ".json");
|
||||
|
||||
int maxWaitSeconds = 60; // 最多等待 60秒,根据实际调整
|
||||
int waited = 0;
|
||||
while (!(Files.exists(Paths.get(jsonPath1)) && Files.exists(Paths.get(jsonPath2)))) {
|
||||
Thread.sleep(1000); // 每秒检查一次
|
||||
waited++;
|
||||
if (waited > maxWaitSeconds) {
|
||||
// 超时,结束进程并抛异常
|
||||
process.destroyForcibly();
|
||||
throw new RuntimeException("等待 Photoshop 生成 JSON 文件超时");
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("检测到 JSON 文件生成,关闭 Photoshop 进程...");
|
||||
|
||||
// 手动杀死 Photoshop 进程,确保释放资源
|
||||
Process killProcess = Runtime.getRuntime().exec("taskkill /IM Photoshop.exe /F");
|
||||
killProcess.waitFor();
|
||||
|
||||
System.out.println("Photoshop 进程已关闭");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public String downloadStudentFile(String fileUrl, String filePath) {
|
||||
try {
|
||||
URL url = new URL(fileUrl);
|
||||
URLConnection connection = url.openConnection();
|
||||
|
||||
String fileName = new File(url.getPath()).getName();
|
||||
File dir = new File(filePath);
|
||||
if (!dir.exists()) dir.mkdirs();
|
||||
|
||||
File saveFile = new File(dir, fileName);
|
||||
|
||||
try (InputStream in = connection.getInputStream();
|
||||
FileOutputStream out = new FileOutputStream(saveFile)) {
|
||||
|
||||
byte[] buffer = new byte[4096];
|
||||
int bytesRead;
|
||||
while ((bytesRead = in.read(buffer)) != -1) {
|
||||
out.write(buffer, 0, bytesRead);
|
||||
}
|
||||
|
||||
System.out.println("✅ 下载成功: " + saveFile.getAbsolutePath());
|
||||
return saveFile.getAbsolutePath();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.err.println("❌ 下载失败: " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,18 @@
|
||||
package pc.exam.pp.module.judgement.controller.service.ps;
|
||||
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.springframework.stereotype.Service;
|
||||
import pc.exam.pp.module.exam.dal.dataobject.ExamPsKeyword;
|
||||
import pc.exam.pp.module.judgement.controller.admin.getpoints.vo.PsVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IPsService {
|
||||
void deletedKeywordById(String quId);
|
||||
|
||||
void insertPsKeywordList(List<ExamPsKeyword> resultList);
|
||||
|
||||
|
||||
List<PsVo> selectPsPointByType(String quId, String type);
|
||||
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
package pc.exam.pp.module.judgement.controller.service.ps;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import pc.exam.pp.module.exam.dal.dataobject.ExamPsKeyword;
|
||||
import pc.exam.pp.module.judgement.controller.admin.getpoints.vo.PsVo;
|
||||
import pc.exam.pp.module.judgement.dal.mysql.ps.PsMapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class PsServiceImpl implements IPsService {
|
||||
@Resource
|
||||
PsMapper psMapper;
|
||||
@Override
|
||||
public void deletedKeywordById(String quId) {
|
||||
psMapper.deleteByQuId(quId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertPsKeywordList(List<ExamPsKeyword> resultList) {
|
||||
psMapper.insertBatch(resultList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PsVo> selectPsPointByType(String quId, String type) {
|
||||
return psMapper.selectPsPointByType(quId,type);
|
||||
}
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
package pc.exam.pp.module.judgement.controller.utils.ps;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
public class PsUtil {
|
||||
|
||||
|
||||
|
||||
// 查询注册表路径,返回command字符串(即exe路径+参数)
|
||||
private static String queryReg(String regPath) throws IOException, InterruptedException {
|
||||
Process process = Runtime.getRuntime().exec("reg query \"" + regPath + "\" /ve");
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "GBK")); // 注册表输出一般GBK编码
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
line = line.trim();
|
||||
if (line.startsWith("(默认)")) {
|
||||
String[] parts = line.split(" ");
|
||||
if (parts.length >= 3) {
|
||||
return parts[parts.length - 1].replace("\"", "").trim(); // 去掉双引号
|
||||
}
|
||||
}
|
||||
}
|
||||
process.waitFor();
|
||||
return null;
|
||||
}
|
||||
|
||||
// 尝试读取多个注册表路径获取 Photoshop 路径
|
||||
public static String findPhotoshopExe() {
|
||||
String[] regPaths = {
|
||||
"HKLM\\SOFTWARE\\Classes\\Applications\\Photoshop.exe\\shell\\edit\\command",
|
||||
"HKLM\\SOFTWARE\\WOW6432Node\\Classes\\Applications\\Photoshop.exe\\shell\\edit\\command"
|
||||
};
|
||||
|
||||
for (String path : regPaths) {
|
||||
try {
|
||||
String exePath = queryReg(path);
|
||||
if (exePath != null && !exePath.isEmpty()) {
|
||||
// 通常 exe 路径后面会跟参数 %1,只取 exe 路径部分
|
||||
int idx = exePath.toLowerCase().indexOf("photoshop.exe");
|
||||
if (idx != -1) {
|
||||
exePath = exePath.substring(0, idx + "photoshop.exe".length());
|
||||
}
|
||||
return exePath;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 忽略异常,继续尝试其他路径
|
||||
}
|
||||
}
|
||||
return null; // 没找到
|
||||
}
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
package pc.exam.pp.module.judgement.dal.mysql.ps;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import pc.exam.pp.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import pc.exam.pp.module.exam.dal.dataobject.ExamPsKeyword;
|
||||
import pc.exam.pp.module.judgement.controller.admin.getpoints.vo.PsVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Mapper
|
||||
public interface PsMapper extends BaseMapperX<ExamPsKeyword> {
|
||||
|
||||
void deleteByQuId(String quId);
|
||||
|
||||
|
||||
List<PsVo> selectPsPointByType(@Param("quId") String quId
|
||||
,@Param("type") String type);
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="pc.exam.pp.module.judgement.dal.mysql.ps.PsMapper">
|
||||
|
||||
|
||||
<resultMap type="ExamPsKeyword" id="ExamPsKeywordResult">
|
||||
<id property="id" column="id" jdbcType="VARCHAR"/>
|
||||
<result property="quId" column="qu_id" jdbcType="VARCHAR"/>
|
||||
<result property="parentId" column="parent_id" jdbcType="VARCHAR"/>
|
||||
<result property="keyName" column="key_name" jdbcType="VARCHAR"/>
|
||||
<result property="keyValue" column="key_value" jdbcType="VARCHAR"/>
|
||||
<result property="rate" column="rate" jdbcType="VARCHAR"/>
|
||||
<result property="type" column="type" jdbcType="VARCHAR"/>
|
||||
</resultMap>
|
||||
|
||||
|
||||
|
||||
|
||||
<delete id="deleteByQuId">
|
||||
delete from exam_ps_keyword where qu_id =#{quId}
|
||||
</delete>
|
||||
<select id="selectPsPointByType" resultMap="ExamPsKeywordResult">
|
||||
select id,qu_id,parent_id,key_name,key_value,rate,type from exam_ps_keyword where qu_id=#{quId}
|
||||
and type=#{type}
|
||||
|
||||
</select>
|
||||
|
||||
|
||||
</mapper>
|
Reference in New Issue
Block a user