【新增】mysql,win文件读取文件设置考点后端接口,题型增加判分规则

This commit is contained in:
YOHO\20373
2025-05-18 00:00:49 +08:00
parent 1dcff7cc07
commit d8ada119ca
36 changed files with 788 additions and 176 deletions

View File

@@ -0,0 +1,67 @@
package pc.exam.pp.module.judgement.controller.admin.getpoints;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import pc.exam.pp.framework.common.pojo.CommonResult;
import pc.exam.pp.module.exam.dal.dataobject.ExamQuestionAnswer;
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;
import java.io.IOException;
import java.util.List;
@RestController
@RequestMapping("/exam/getPoints")
public class GetPointsController {
@Autowired
private ExamGetPointsService examGetPointsService;
/**
* 得出文件操作考点
* @return 得分
*/
@PostMapping("/get_filePoint")
public CommonResult get_file_point(@RequestBody PointsVo pointsVo) throws IOException {
return CommonResult.success(examGetPointsService.get_file_point(pointsVo));
}
/**
* 得出MYSQL操作考点
* @return 得分
*/
@PostMapping("/get_mysql_point")
public CommonResult get_mysql_point(@RequestBody PointsVo pointsVo) throws IOException {
return CommonResult.success(examGetPointsService.get_mysql_point(pointsVo));
}
/**
* 新增MYSQL操作考点
* @return 得分
*/
@PostMapping("/set_mysql_point")
public CommonResult set_mysql_point(@RequestBody Points points) {
return CommonResult.success(examGetPointsService.set_mysql_point(points));
}
/**
* 更新MYSQL操作考点
* @return 得分
*/
@PostMapping("/update_mysql_point")
public CommonResult update_mysql_point(@RequestBody Points points) {
return CommonResult.success(examGetPointsService.update_mysql_point(points));
}
@GetMapping("/get_Point_id/{quId}")
public CommonResult getPointById(@PathVariable("quId") String quId) {
return CommonResult.success(examGetPointsService.getPointById(quId));
}
/**
* 得出浏览器操作考点
* @return 得分
*/
@PostMapping("/get_browser_point")
//todo 老师自己设置,不读文件
public CommonResult get_browser_point(@RequestBody List<ExamQuestionAnswer> examQuestionAnswers) throws IOException {
return CommonResult.success(examGetPointsService.get_browser_point());
}
}

View File

@@ -0,0 +1,16 @@
package pc.exam.pp.module.judgement.controller.admin.getpoints.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import pc.exam.pp.module.exam.dal.dataobject.ExamQuestionAnswer;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Points {
private String quId;
private List<ExamQuestionAnswer> questionAnswerList;
}

View File

@@ -0,0 +1,14 @@
package pc.exam.pp.module.judgement.controller.admin.getpoints.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PointsVo {
private String shucaiPath;
private String answerPath;
}

View File

@@ -1,8 +1,10 @@
package pc.exam.pp.module.judgement.controller.service.browser;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import pc.exam.pp.module.exam.dal.dataobject.ExamQuestion;
import pc.exam.pp.module.exam.dal.dataobject.ExamQuestionAnswer;
import pc.exam.pp.module.exam.dal.mysql.question.ExamQuestionAnswerMapper;
import pc.exam.pp.module.judgement.controller.utils.brower.BookmarkChecker;
import pc.exam.pp.module.judgement.controller.utils.brower.BookmarkDeleter;
import pc.exam.pp.module.exam.utils.file.GetDifferencesBetweenFolders;
@@ -15,10 +17,13 @@ import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
public class BrowserServericeImpl implements IBrowserServerice {
static String answerLogPath ; // 文件路径
@Resource
private ExamQuestionAnswerMapper examQuestionAnswerMapper;
//考生试题文件夹
// static final String BASE_DIR = "D:/exam/4/";
//谷歌浏览器
@@ -31,16 +36,19 @@ public class BrowserServericeImpl implements IBrowserServerice {
//Net得分点 文件类型 文件名 考点权值
// 添加到文件夹 1
// 添加到收藏夹 2
List<ExamQuestionAnswer> answerList=new ArrayList<>();
answerList.add(new ExamQuestionAnswer("","","","","1", "人民大学", "1", "1"));
answerList.add(new ExamQuestionAnswer("","","","","1", "校情", "1", "2"));
answerList.add(new ExamQuestionAnswer("","","","","1", "机构", "1", "3"));
// List<ExamQuestionAnswer> answerList=new ArrayList<>();
// answerList.add(new ExamQuestionAnswer("","","","","人民大学", "添加到文件夹 ", "1", "1"));
// answerList.add(new ExamQuestionAnswer("","","","","校情", "添加到文件夹", "1", "2"));
// answerList.add(new ExamQuestionAnswer("","","","","机构", "添加到文件夹", "1", "3"));
List<ExamQuestionAnswer> answerList = examQuestionAnswerMapper.selectExamQuestionAnswerByQuId(question.getQuId());
//判断如果类型为1为添加到文件夹的html后缀加 .html
for (ExamQuestionAnswer answer : answerList) {
if ("1".equals(answer.getContent())) {
String fileName = answer.getContentIn();
if ("添加到文件夹".equals(answer.getContentIn())) {
String fileName = answer.getContent();
if (!fileName.endsWith(".html")) {
answer.setContentIn(fileName + ".html");
answer.setContent(fileName + ".html");
}
}
}
@@ -70,16 +78,20 @@ public class BrowserServericeImpl implements IBrowserServerice {
for (ExamQuestionAnswer examQuestionAnswer : answerList) {
int currentScore = Integer.parseInt(examQuestionAnswer.getScoreRate()); // 当前得分
if ( examQuestionAnswer.getContent().equals("2")){
String bookmarkNameToDelete = examQuestionAnswer.getContentIn();
if ( "添加到收藏夹".equals(examQuestionAnswer.getContentIn())){
String bookmarkNameToDelete = examQuestionAnswer.getContent();
//检查收藏夹是否有书签
if (BookmarkChecker.bookmarkExists(chromeBookmarkPath, bookmarkNameToDelete)) {
//如果有 +权值
boolean isCorrect = BookmarkChecker.bookmarkExists(chromeBookmarkPath, bookmarkNameToDelete);
if (isCorrect) {
//如果有 +权值
studentScore += currentScore;
System.out.println("📌 发现书签,准备删除...");
appendToFile(answerLogPath,"考点"+bookmarkNameToDelete + " -> 得分权值:" + currentScore+"-> 是否得分:"+isCorrect+"");
//删除此书签
BookmarkDeleter.deleteBookmarkByName(chromeBookmarkPath, bookmarkNameToDelete);
}
else {
appendToFile(answerLogPath,"考点"+bookmarkNameToDelete + " -> 得分权值:" + currentScore+"-> 是否得分:"+isCorrect+"");
}
}
}
@@ -100,7 +112,8 @@ public class BrowserServericeImpl implements IBrowserServerice {
static Integer compareStuAndTestFiles(List<ExamQuestionAnswer> answerList, Map<String, String> stuFiles) {
int totalScore = 0; // 记录总得分
for (ExamQuestionAnswer answer : answerList) {
String filePath = answer.getContentIn(); // 试题文件路径
if ("添加到文件夹".equals(answer.getContentIn())) {
String filePath = answer.getContent(); // 试题文件路径
int currentScore = Integer.parseInt(answer.getScoreRate()); // 当前得分
boolean isCorrect = false;
// 如果学生提交中存在该文件,则得分
@@ -109,12 +122,13 @@ public class BrowserServericeImpl implements IBrowserServerice {
if (isCorrect) {
totalScore += currentScore;
appendToFile(answerLogPath,"考点"+answer.getContentIn() + " -> 得分权值:" + answer.getScoreRate()+"-> 是否得分:"+isCorrect+"");
appendToFile(answerLogPath,"考点"+answer.getContent() + " -> 得分权值:" + answer.getScoreRate()+"-> 是否得分:"+isCorrect+"");
}else {
appendToFile(answerLogPath,"考点"+answer.getContentIn() + " -> 得分权值:" + answer.getScoreRate()+"-> 是否得分:"+isCorrect+"");
appendToFile(answerLogPath,"考点"+answer.getContent() + " -> 得分权值:" + answer.getScoreRate()+"-> 是否得分:"+isCorrect+"");
}
}
}
//返回累加的得分点
return totalScore;

View File

@@ -1,8 +1,10 @@
package pc.exam.pp.module.judgement.controller.service.file;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import pc.exam.pp.module.exam.dal.dataobject.ExamQuestion;
import pc.exam.pp.module.exam.dal.dataobject.ExamQuestionAnswer;
import pc.exam.pp.module.exam.dal.mysql.question.ExamQuestionAnswerMapper;
import pc.exam.pp.module.exam.utils.file.GetDifferencesBetweenFolders;
import java.io.BufferedWriter;
@@ -18,20 +20,22 @@ import java.util.Map;
@Service
public class FileServericeImpl implements IFileServerice {
static final String BASE_DIR = "D:/exam/3/";
static String answerLogPath ; // 文件路径
@Resource
private ExamQuestionAnswerMapper examQuestionAnswerMapper;
@Override
public double run_file_point(double score,File file, ExamQuestion question) throws IOException {
//todo 得到学生的考题答案
List<ExamQuestionAnswer> answerList=new ArrayList<>();
answerList.add(new ExamQuestionAnswer("","","","","HGACYL\\RLQM.MEM", "考察删除", "1", "1"));
answerList.add(new ExamQuestionAnswer("","","","","TING\\XYU\\AUTOE.BAT", "考察删除", "1", "2"));
answerList.add(new ExamQuestionAnswer("","","","","AHEWL\\KMENS", "考察名称", "1", "3"));
answerList.add(new ExamQuestionAnswer("","","","","EDZK\\RONGHE.COM", "考察名称", "1", "4"));
answerList.add(new ExamQuestionAnswer("","","","","HGACYL\\PLAY.MEM", "考察名称", "1", "5"));
answerList.add(new ExamQuestionAnswer("","","","","WUE\\PB6.txt", "考察名称", "1", "6"));
List<ExamQuestionAnswer> answerList = examQuestionAnswerMapper.selectExamQuestionAnswerByQuId(question.getQuId());
//todo 得到学生的考题答案
// List<ExamQuestionAnswer> answerList=new ArrayList<>();
// answerList.add(new ExamQuestionAnswer("","","","","HGACYL\\RLQM.MEM", "考察删除", "1", "1"));
// answerList.add(new ExamQuestionAnswer("","","","","TING\\XYU\\AUTOE.BAT", "考察删除", "1", "2"));
// answerList.add(new ExamQuestionAnswer("","","","","AHEWL\\KMENS", "考察名称", "1", "3"));
// answerList.add(new ExamQuestionAnswer("","","","","EDZK\\RONGHE.COM", "考察名称", "1", "4"));
// answerList.add(new ExamQuestionAnswer("","","","","HGACYL\\PLAY.MEM", "考察名称", "1", "5"));
// answerList.add(new ExamQuestionAnswer("","","","","WUE\\PB6.txt", "考察名称", "1", "6"));
File stuPath = file;

View File

@@ -0,0 +1,25 @@
package pc.exam.pp.module.judgement.controller.service.getpoints;
import pc.exam.pp.module.exam.dal.dataobject.ExamQuestionAnswer;
import pc.exam.pp.module.judgement.controller.admin.getpoints.vo.Points;
import pc.exam.pp.module.judgement.controller.admin.getpoints.vo.PointsVo;
import java.io.IOException;
import java.util.List;
public interface ExamGetPointsService {
List<ExamQuestionAnswer> get_file_point(PointsVo pointsVo) throws IOException;
List<String> get_mysql_point(PointsVo pointsVo) throws IOException;
List<ExamQuestionAnswer> get_browser_point();
boolean set_mysql_point(Points points);
boolean update_mysql_point(Points points);
List<ExamQuestionAnswer> getPointById(String quId);
}

View File

@@ -0,0 +1,274 @@
package pc.exam.pp.module.judgement.controller.service.getpoints;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import pc.exam.pp.module.exam.dal.dataobject.ExamMysqlKeyword;
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;
import pc.exam.pp.module.exam.dal.mysql.question.ExamQuestionMapper;
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.Points;
import pc.exam.pp.module.judgement.controller.admin.getpoints.vo.PointsVo;
import pc.exam.pp.module.judgement.controller.utils.zip.ZipUtil;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.MalformedInputException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
@Service
@Slf4j
public class ExamGetPointsServiceImpl implements ExamGetPointsService{
@Resource
ConfigService configService;
@Resource
MysqlKeywordMapper mysqlKeywordMapper;
@Resource
private ExamQuestionAnswerMapper examQuestionAnswerMapper;
@Override
public List<ExamQuestionAnswer> get_file_point(PointsVo pointsVo) throws IOException {
// 获取平台文件参数
ConfigDO config = configService.getConfigByKey("file_down_path");
String sthPath = ZipUtil.downloadStudentFile(pointsVo.getShucaiPath(), config.getValue());
String answerPath = ZipUtil.downloadStudentFile(pointsVo.getAnswerPath(), config.getValue());
File zip_file_sth = new File(sthPath);
File zip_file_answer= new File(answerPath);
//获取到得是zip文件需要解压
String stuFilePath = ZipUtil.unzipToNamedFolder(sthPath);
String answerFilePath = ZipUtil.unzipToNamedFolder(answerPath);
//解压之后得文件获取文件夹和文件
File folderStu = new File(stuFilePath);
File folderAnswer = new File(stuFilePath);
List<ExamQuestionAnswer> answerList = new ArrayList<>();
AtomicInteger sortCounter = new AtomicInteger(1); // 计数器
// 获取 shucai 和 win 文件夹的差异
Map<String, String> differences = GetDifferencesBetweenFolders.getDifferencesBetweenFolders(stuFilePath, answerFilePath);
List<ExamQuestionAnswer> formattedDifferences = differences.entrySet().stream()
.map(entry -> {
String key = entry.getKey();
String value = entry.getValue();
ExamQuestionAnswer answer = new ExamQuestionAnswer();
answer.setContent(key); // 设置文件路径
answer.setScoreRate("1");
//这里设置answer的排序按照循环次数来
answer.setSort(String.valueOf(sortCounter.getAndIncrement())); // 按顺序设置排序值
if (value.startsWith("仅存在于 "+stuFilePath)) {
answer.setContentIn("考察删除");
} else if (value.startsWith("仅存在于 "+answerFilePath)) {
answer.setContentIn("考察名称");
} else if (value.startsWith("属性不同")) {
answer.setContentIn("考察属性");
// answer.setContent(key + " -> " + value.split(" vs ")[1]); // 设置属性信息
}
return answer;
})
.sorted(Comparator.comparingInt(answer -> Integer.parseInt(answer.getSort()))) // 按 sort 排序
.collect(Collectors.toList());
answerList.addAll(formattedDifferences);
// zip_file_sth.delete();
// zip_file_answer.delete();
// folderStu.delete();
// folderAnswer.delete();
return answerList;
}
@Override
public List<String> get_mysql_point(PointsVo pointsVo) throws IOException {
String answerPath = pointsVo.getAnswerPath();
// 获取平台文件参数
ConfigDO config = configService.getConfigByKey("file_down_path");
String sthPath = ZipUtil.downloadStudentFile(pointsVo.getAnswerPath(), config.getValue());
System.out.println(sthPath);
List<String> sqlStatements = readSQLFromFile(sthPath);
return sqlStatements;
}
private static List<String> readSQLFromFile(String filePath) throws IOException {
List<String> lines = readFileAutoCharset(filePath);
List<String> sqlList = parseSql(lines);
for (String sql : sqlList) {
System.out.println(sql);
System.out.println("-------");
}
return sqlList;
}
// 自动识别 UTF-8 or GBK
private static List<String> readFileAutoCharset(String filePath) throws IOException {
try {
// 优先尝试 UTF-8
return Files.readAllLines(Paths.get(filePath), Charset.forName("UTF-8"));
} catch (MalformedInputException e) {
// 如果UTF-8失败再尝试GBK
System.out.println("文件不是UTF-8编码尝试使用GBK编码读取...");
return Files.readAllLines(Paths.get(filePath), Charset.forName("GBK"));
}
}
// 解析SQL去掉注释只保留SQL语句
private static List<String> parseSql(List<String> lines) {
List<String> sqlList = new ArrayList<>();
StringBuilder currentSql = new StringBuilder();
for (String line : lines) {
line = line.trim();
if (line.startsWith("--")) {
// 遇到新的注释(比如 -- 1.先把之前的SQL收进去
if (currentSql.length() > 0) {
sqlList.add(currentSql.toString().trim());
currentSql.setLength(0);
}
continue; // 注释行不用管
}
// 累加 SQL 内容
currentSql.append(line).append("\n");
}
if (currentSql.length() > 0) {
sqlList.add(currentSql.toString().trim());
}
return sqlList;
}
@Override
public List<ExamQuestionAnswer> get_browser_point() {
return null;
}
@Override
public boolean set_mysql_point(Points points) {
try {
List<ExamQuestionAnswer> questionAnswerList = points.getQuestionAnswerList();
if (CollectionUtils.isEmpty(questionAnswerList)) {
return true;
}
List<ExamMysqlKeyword> allKeywords = new ArrayList<>();
for (ExamQuestionAnswer examQuestionAnswer : questionAnswerList) {
String answerId = IdUtils.simpleUUID();
examQuestionAnswer.setAnswerId(answerId);
examQuestionAnswer.setQuId(points.getQuId());
List<ExamMysqlKeyword> keywordList = examQuestionAnswer.getExamMysqlKeywordList();
if (!CollectionUtils.isEmpty(keywordList)) {
for (ExamMysqlKeyword keyword : keywordList) {
keyword.setAnswerId(answerId);
keyword.setKeywordId(IdUtils.simpleUUID());
}
allKeywords.addAll(keywordList);
}
}
if (!CollectionUtils.isEmpty(allKeywords)) {
mysqlKeywordMapper.insertOrUpdate(allKeywords);
}
examQuestionAnswerMapper.insertOrUpdate(questionAnswerList);
return true;
} catch (Exception e) {
log.error("保存考试点信息失败", e);
return false;
}
}
@Override
public boolean update_mysql_point(Points points) {
try {
String quId = points.getQuId();
List<ExamQuestionAnswer> questionAnswerList = points.getQuestionAnswerList();
// 查询旧 answerId
List<String> oldAnswerIds = examQuestionAnswerMapper.selectExamQuestionAnswerIdByQuId(quId);
// 删除旧关键字
if (!CollectionUtils.isEmpty(oldAnswerIds)) {
for (String aid : oldAnswerIds) {
mysqlKeywordMapper.deleteByAnswerId(aid);
}
}
// 删除旧答案
examQuestionAnswerMapper.deleteExamQuestionAnswerByQuesId(quId);
// 如果没有新数据就返回
if (CollectionUtils.isEmpty(questionAnswerList)) {
return true;
}
// 新的 keyword 收集
List<ExamMysqlKeyword> newKeywordList = new ArrayList<>();
for (ExamQuestionAnswer answer : questionAnswerList) {
String answerId = IdUtils.simpleUUID();
answer.setAnswerId(answerId);
answer.setQuId(quId); // 以防前端未传
List<ExamMysqlKeyword> keywordList = answer.getExamMysqlKeywordList();
if (!CollectionUtils.isEmpty(keywordList)) {
for (ExamMysqlKeyword keyword : keywordList) {
keyword.setAnswerId(answerId);
keyword.setKeywordId(IdUtils.simpleUUID());
}
newKeywordList.addAll(keywordList);
}
}
// 插入新答案和关键词
examQuestionAnswerMapper.insertOrUpdate(questionAnswerList);
if (!CollectionUtils.isEmpty(newKeywordList)) {
mysqlKeywordMapper.insertOrUpdate(newKeywordList);
}
return true;
} catch (Exception e) {
log.error("更新考试点信息失败", e);
return false;
}
}
@Override
public List<ExamQuestionAnswer> getPointById(String quId) {
List<ExamQuestionAnswer> examQuestionAnswers = examQuestionAnswerMapper.selectExamQuestionAnswerByQuId(quId);
if (!CollectionUtils.isEmpty(examQuestionAnswers)) {
for (ExamQuestionAnswer examQuestionAnswer : examQuestionAnswers) {
String answerId = examQuestionAnswer.getAnswerId();
List<ExamMysqlKeyword> newKeywordList = mysqlKeywordMapper.selectList(
new QueryWrapper<ExamMysqlKeyword>().eq("answer_id", answerId)
);
examQuestionAnswer.setExamMysqlKeywordList(newKeywordList);
}
}
return examQuestionAnswers;
}
}

View File

@@ -0,0 +1,117 @@
package pc.exam.pp.module.judgement.controller.utils.zip;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.DosFileAttributeView;
import java.util.Enumeration;
public class ZipUtil {
public static String unzipToNamedFolder(String zipFilePath) {
File zipFile = new File(zipFilePath);
if (!zipFile.exists() || !zipFile.getName().toLowerCase().endsWith(".zip")) {
System.err.println("❌ 无效 zip 文件: " + zipFilePath);
return null;
}
String fileNameNoExt = zipFile.getName().replaceAll("(?i)\\.zip$", "");
File extractDir = new File(zipFile.getParentFile(), fileNameNoExt);
if (!extractDir.exists()) extractDir.mkdirs();
// 指定编码GBK 用于支持中文文件名UTF-8 用于通用 ZIP
try (ZipFile zf = new ZipFile(zipFile, "GBK")) {
Enumeration<ZipArchiveEntry> entries = zf.getEntries();
while (entries.hasMoreElements()) {
ZipArchiveEntry entry = entries.nextElement();
File outFile = new File(extractDir, entry.getName());
// 防止 Zip 穿越攻击
if (!outFile.getCanonicalPath().startsWith(extractDir.getCanonicalPath())) {
throw new IOException("非法路径: " + entry.getName());
}
if (entry.isDirectory()) {
outFile.mkdirs();
} else {
File parent = outFile.getParentFile();
if (!parent.exists()) parent.mkdirs();
try (InputStream is = zf.getInputStream(entry);
OutputStream os = new FileOutputStream(outFile)) {
byte[] buffer = new byte[4096];
int len;
while ((len = is.read(buffer)) > 0) {
os.write(buffer, 0, len);
}
}
}
// 读取 Zip 中的外部文件属性低16位DOS属性
int externalAttrs = (int) (entry.getExternalAttributes() & 0xFFFF);
// DOS隐藏属性是第二位(0x02)
boolean hidden = (externalAttrs & 0x02) != 0;
// DOS只读属性是第一位(0x01)
boolean readOnly = (externalAttrs & 0x01) != 0;
Path outPath = outFile.toPath();
DosFileAttributeView view = Files.getFileAttributeView(outPath, DosFileAttributeView.class);
if (view != null) {
try {
// 设置隐藏属性
view.setHidden(hidden);
// 设置只读属性需要用Files.setAttribute
Files.setAttribute(outPath, "dos:readonly", readOnly);
} catch (IOException e) {
System.err.println("设置文件属性失败: " + e.getMessage());
}
}
}
System.out.println("✅ 解压完成,目录:" + extractDir.getAbsolutePath());
return extractDir.getAbsolutePath();
} catch (IOException e) {
System.err.println("❌ 解压失败: " + e.getMessage());
return null;
}
}
public static 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;
}
}
}