feat: 资源学习情况导出-作业信息导出接口补全附件和zip导出

This commit is contained in:
miaowenbo
2025-11-27 15:21:41 +08:00
parent 25ed807efd
commit d9cbc9a24d

View File

@@ -12,6 +12,7 @@ import com.xboe.constants.CacheName;
import com.xboe.core.CurrentUser;
import com.xboe.core.JsonResponse;
import com.xboe.core.api.ApiBaseController;
import com.xboe.core.upload.XFileUploader;
import com.xboe.data.outside.IOutSideDataService;
import com.xboe.module.course.entity.*;
import com.xboe.module.course.service.ICourseContentService;
@@ -42,8 +43,7 @@ import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
@@ -52,6 +52,8 @@ import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* 课程学习的内容
@@ -111,6 +113,9 @@ public class StudyCourseApi extends ApiBaseController{
@Resource
private IOrganizationService organizationService;
@Resource
private XFileUploader fileUploader;
/**
* 用于避免JPA查询后修改entity实体字段自动更新到数据库
*/
@@ -1407,7 +1412,10 @@ public class StudyCourseApi extends ApiBaseController{
}
OutputStream outputStream = null;
try {
outputStream = response.getOutputStream();
// 创建临时文件用于存储Excel
File tempExcelFile = File.createTempFile("HomeWorkRecord", ".xlsx");
String tempExcelPath = tempExcelFile.getAbsolutePath();
LinkedHashMap<String, String> exportMap = new LinkedHashMap<>();
// 1.拼接固定表头(课程名称、资源名称、姓名、工号、部门、作业状态、作业成绩、完成时间)
exportMap.put("课程名称", "课程名称");
@@ -1418,6 +1426,7 @@ public class StudyCourseApi extends ApiBaseController{
exportMap.put("作业状态", "作业状态");
exportMap.put("作业成绩", "作业成绩");
exportMap.put("完成时间", "完成时间");
// 2.整理导出数据
// 查询课程名称
StudyCourse studyCourse = new StudyCourse();
studyCourse.setCourseId(courseId);
@@ -1439,7 +1448,6 @@ public class StudyCourseApi extends ApiBaseController{
}
}
}
// 查询特定作业信息
List<StudyHomeWork> studyHomeWorks = studyHomeWorkService.getByCourseIdAndContentId(courseId, contentId);
// 通过studyHomeWorks中的人员id集合(去重),调用用户中心接口获取人员信息,填充部门字段
@@ -1471,7 +1479,7 @@ public class StudyCourseApi extends ApiBaseController{
}
}
}
// 将作业信息与用户信息拼接为map
// 3.将作业信息与用户信息拼接为map
String finalContentName = contentName;
List<Map<String, Object>> dataList = studyHomeWorks.stream().map(hw -> {
Map<String, Object> map = new HashMap<>();
@@ -1500,11 +1508,86 @@ public class StudyCourseApi extends ApiBaseController{
map.put("完成时间", hw.getEndTime());
return map;
}).collect(Collectors.toList());
// 设置响应头信息
response.setContentType("application/octet-stream");
response.setHeader("Content-disposition", "attachment;filename=HomeWorkRecord.xlsx");
// 调用动态列excel导出接口
ExportsExcelSenderUtil.exportDynamic(exportMap, dataList, outputStream, "yyyy-MM-dd HH:mm:ss");
// 先将Excel数据写入临时文件
try (FileOutputStream excelOutputStream = new FileOutputStream(tempExcelFile)) {
ExportsExcelSenderUtil.exportDynamic(exportMap, dataList, excelOutputStream, "yyyy-MM-dd HH:mm:ss");
}
// 4.整理作业的附件信息备用
// 获取附件信息集合
Map<String, String> homeworkFiles = new HashMap<>();
String savePath = fileUploader.getSavePath();
for (StudyHomeWork studyHomeWork : studyHomeWorks) {
String filePath = studyHomeWork.getFilePath();
if (StringUtils.isNotBlank(filePath)) {
String fullPath = savePath + filePath;
log.info("【资源学习情况导出-作业信息】下载附件路径:{}", fullPath);
File file = new File(fullPath);
if (file.exists()) {
// 使用文件名作为zip中的条目名
String fileName = file.getName();
// 避免文件名冲突,如果已存在则添加序号
String zipEntryName = fileName;
int counter = 1;
while (homeworkFiles.containsKey(zipEntryName)) {
int dotIndex = fileName.lastIndexOf('.');
if (dotIndex > 0) {
zipEntryName = fileName.substring(0, dotIndex) + "_" + counter + fileName.substring(dotIndex);
} else {
zipEntryName = fileName + "_" + counter;
}
counter++;
}
homeworkFiles.put(zipEntryName, fullPath);
}
}
}
// 5.设置响应头信息为zip文件
response.setContentType("application/zip");
response.setHeader("Content-disposition", "attachment;filename=HomeWorkRecord.zip");
outputStream = response.getOutputStream();
// 6.把输出的附件和导出的excel文件拼接为一个zip导出
try (ZipOutputStream zos = new ZipOutputStream(outputStream)) {
// 添加Excel文件到zip
byte[] buffer = new byte[1024];
// 添加Excel文件
File excelFile = new File(tempExcelPath);
if (excelFile.exists()) {
FileInputStream fis = new FileInputStream(excelFile);
ZipEntry zipEntry = new ZipEntry("HomeWorkRecord.xlsx");
zos.putNextEntry(zipEntry);
int length;
while ((length = fis.read(buffer)) > 0) {
zos.write(buffer, 0, length);
}
zos.closeEntry();
fis.close();
}
// 添加作业附件文件
// 25.11.27标记:和技术沟通后,按业务此处调用频率不会过高,因此暂不采用多线程下载方案
// 为了防止命名冲突附件放在zip的/附件目录下
// zip规范要求使用 正斜杠/作为路径分隔符不要用File.separator在windows上是\会导致zip解压异常
String zipFilePath = "附件/";
for (Map.Entry<String, String> entry : homeworkFiles.entrySet()) {
String zipEntryName = zipFilePath + entry.getKey();
String filePath = entry.getValue();
File file = new File(filePath);
if (file.exists()) {
FileInputStream fis = new FileInputStream(file);
ZipEntry zipEntry = new ZipEntry(zipEntryName);
zos.putNextEntry(zipEntry);
int len;
while ((len = fis.read(buffer)) > 0) {
zos.write(buffer, 0, len);
}
zos.closeEntry();
fis.close();
}
}
}
// 删除临时Excel文件
if (tempExcelFile.exists()) {
tempExcelFile.delete();
}
} catch (Exception e) {
log.error("【资源学习情况导出-作业信息】导出资源学习情况错误:{}", e.getMessage());
} finally {