|
@@ -23,6 +23,7 @@ import com.jeeplus.modules.act.service.ActTaskService;
|
|
|
import com.jeeplus.modules.act.utils.ActUtils;
|
|
import com.jeeplus.modules.act.utils.ActUtils;
|
|
|
import com.jeeplus.modules.projectmaterialstorage.entity.ProjectMaterialStorage;
|
|
import com.jeeplus.modules.projectmaterialstorage.entity.ProjectMaterialStorage;
|
|
|
import com.jeeplus.modules.projectmaterialstorage.entity.ProjectMaterialStorageImport;
|
|
import com.jeeplus.modules.projectmaterialstorage.entity.ProjectMaterialStorageImport;
|
|
|
|
|
+import com.jeeplus.modules.projectrecord.entity.AdminProjectReportedImport;
|
|
|
import com.jeeplus.modules.projectrecord.entity.ProjectRecords;
|
|
import com.jeeplus.modules.projectrecord.entity.ProjectRecords;
|
|
|
import com.jeeplus.modules.projectrecord.enums.ProjectStatusEnum;
|
|
import com.jeeplus.modules.projectrecord.enums.ProjectStatusEnum;
|
|
|
import com.jeeplus.modules.projectrecord.service.ProjectRecordsService;
|
|
import com.jeeplus.modules.projectrecord.service.ProjectRecordsService;
|
|
@@ -68,8 +69,7 @@ import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
|
|
import javax.servlet.http.HttpServletRequest;
|
|
import javax.servlet.http.HttpServletRequest;
|
|
|
import javax.servlet.http.HttpServletResponse;
|
|
import javax.servlet.http.HttpServletResponse;
|
|
|
import javax.validation.ConstraintViolationException;
|
|
import javax.validation.ConstraintViolationException;
|
|
|
-import java.io.IOException;
|
|
|
|
|
-import java.io.UnsupportedEncodingException;
|
|
|
|
|
|
|
+import java.io.*;
|
|
|
import java.lang.reflect.InvocationTargetException;
|
|
import java.lang.reflect.InvocationTargetException;
|
|
|
import java.math.BigDecimal;
|
|
import java.math.BigDecimal;
|
|
|
import java.net.URLDecoder;
|
|
import java.net.URLDecoder;
|
|
@@ -1640,26 +1640,48 @@ public class WorkInvoiceAllController extends BaseController {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 导入Excel数据
|
|
|
|
|
-
|
|
|
|
|
|
|
+ * 下载导入项目数据模板
|
|
|
|
|
+ * @param response
|
|
|
|
|
+ * @param redirectAttributes
|
|
|
|
|
+ * @return
|
|
|
*/
|
|
*/
|
|
|
- //@RequiresPermissions("workinvoice:workInvoice:importReceiptDataFile")
|
|
|
|
|
|
|
+ @RequiresPermissions("project:adminProjectReportedImport:import")
|
|
|
|
|
+ @RequestMapping(value = "import/invoiceBatchTemplate")
|
|
|
|
|
+ public String invoiceBatchTemplate(HttpServletResponse response, RedirectAttributes redirectAttributes) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ String fileName = "管理员上报导入模板.xlsx";
|
|
|
|
|
+ List<AdminProjectReportedImport> list = Lists.newArrayList();
|
|
|
|
|
+ new ExportExcel("项目上报数据", AdminProjectReportedImport.class, 1).setDataList(list).write(response, fileName).dispose();
|
|
|
|
|
+ return null;
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ addMessage(redirectAttributes, "导入模板下载失败!失败信息:"+e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+ return "redirect:"+ Global.getAdminPath()+"/project/adminProjectReportedImport/?repage";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ // 移除原有返回String的逻辑,改为返回JSON
|
|
|
|
|
+//@RequiresPermissions("workinvoice:workInvoice:importReceiptDataFile")
|
|
|
@RequestMapping(value = "importReceiptDataFile", method=RequestMethod.POST)
|
|
@RequestMapping(value = "importReceiptDataFile", method=RequestMethod.POST)
|
|
|
- public String importReceiptDataFile(MultipartFile file, RedirectAttributes redirectAttributes, HttpServletResponse response) {// 初始化返回结果Map
|
|
|
|
|
- //对相对有效的数据进行处理
|
|
|
|
|
- //有效的数据
|
|
|
|
|
|
|
+ @ResponseBody // 关键:返回JSON而非视图/重定向
|
|
|
|
|
+ public Map<String, Object> importReceiptDataFile(MultipartFile file, HttpServletResponse response) {
|
|
|
|
|
+ // 初始化返回结果
|
|
|
|
|
+ Map<String, Object> result = new HashMap<>();
|
|
|
|
|
+ result.put("success", false); // 默认失败
|
|
|
|
|
+ result.put("msg", "");
|
|
|
|
|
+ result.put("excelFileName", null); // Excel文件名
|
|
|
|
|
+
|
|
|
List<WorkInvoiceReceiptInfo> effectiveList = Lists.newArrayList();
|
|
List<WorkInvoiceReceiptInfo> effectiveList = Lists.newArrayList();
|
|
|
- //错误的数据
|
|
|
|
|
List<WorkInvoiceReceiptInfo> errorList = Lists.newArrayList();
|
|
List<WorkInvoiceReceiptInfo> errorList = Lists.newArrayList();
|
|
|
|
|
+ String excelFileName = null;
|
|
|
|
|
|
|
|
try {
|
|
try {
|
|
|
StringBuilder failureMsg = new StringBuilder();
|
|
StringBuilder failureMsg = new StringBuilder();
|
|
|
ImportExcel ei = new ImportExcel(file, 1, 0);
|
|
ImportExcel ei = new ImportExcel(file, 1, 0);
|
|
|
List<WorkInvoiceReceiptInfo> list = ei.getDataList(WorkInvoiceReceiptInfo.class);
|
|
List<WorkInvoiceReceiptInfo> list = ei.getDataList(WorkInvoiceReceiptInfo.class);
|
|
|
|
|
|
|
|
- //此处需要修改为迭代器形式
|
|
|
|
|
|
|
+ // 【原有逻辑完全不变】迭代器过滤错误数据
|
|
|
Iterator<WorkInvoiceReceiptInfo> iterator = list.iterator();
|
|
Iterator<WorkInvoiceReceiptInfo> iterator = list.iterator();
|
|
|
while (iterator.hasNext()){
|
|
while (iterator.hasNext()){
|
|
|
WorkInvoiceReceiptInfo workInvoiceReceiptInfo = iterator.next();
|
|
WorkInvoiceReceiptInfo workInvoiceReceiptInfo = iterator.next();
|
|
@@ -1678,59 +1700,54 @@ public class WorkInvoiceAllController extends BaseController {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- //对有效的数据进行去重处理
|
|
|
|
|
|
|
+ // 【原有逻辑完全不变】有效数据去重
|
|
|
for (WorkInvoiceReceiptInfo info : effectiveList) {
|
|
for (WorkInvoiceReceiptInfo info : effectiveList) {
|
|
|
- // 处理可能的null值,转为空字符串
|
|
|
|
|
String invoiceName = (info.getInvoiceNumber() != null) ? info.getInvoiceNumber() : "";
|
|
String invoiceName = (info.getInvoiceNumber() != null) ? info.getInvoiceNumber() : "";
|
|
|
String buyerName = (info.getBuyerName() != null) ? info.getBuyerName() : "";
|
|
String buyerName = (info.getBuyerName() != null) ? info.getBuyerName() : "";
|
|
|
String money = (info.getMoney() != null) ? info.getMoney().toString() : "";
|
|
String money = (info.getMoney() != null) ? info.getMoney().toString() : "";
|
|
|
- // 以逗号分隔组合
|
|
|
|
|
String resultStr = invoiceName + "," + buyerName + "," + money;
|
|
String resultStr = invoiceName + "," + buyerName + "," + money;
|
|
|
info.setDistinctStr(resultStr);
|
|
info.setDistinctStr(resultStr);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-
|
|
|
|
|
Map<String,List<WorkInvoiceReceiptInfo>> map = invoiceService.distinctProjectMaterialStorage(effectiveList);
|
|
Map<String,List<WorkInvoiceReceiptInfo>> map = invoiceService.distinctProjectMaterialStorage(effectiveList);
|
|
|
|
|
|
|
|
-
|
|
|
|
|
- //有效数据
|
|
|
|
|
|
|
+ // 【原有逻辑完全不变】各类错误数据标记
|
|
|
List<WorkInvoiceReceiptInfo> uniqueList = map.get("uniqueList");
|
|
List<WorkInvoiceReceiptInfo> uniqueList = map.get("uniqueList");
|
|
|
- //重复数据
|
|
|
|
|
List<WorkInvoiceReceiptInfo> duplicateList = map.get("duplicateList");
|
|
List<WorkInvoiceReceiptInfo> duplicateList = map.get("duplicateList");
|
|
|
for (WorkInvoiceReceiptInfo info : duplicateList) {
|
|
for (WorkInvoiceReceiptInfo info : duplicateList) {
|
|
|
info.setErrorMessage("重复数据,添加失败");
|
|
info.setErrorMessage("重复数据,添加失败");
|
|
|
}
|
|
}
|
|
|
- //已经有收款信息的数据
|
|
|
|
|
List<WorkInvoiceReceiptInfo> alreadyExistList = map.get("alreadyExistList");
|
|
List<WorkInvoiceReceiptInfo> alreadyExistList = map.get("alreadyExistList");
|
|
|
for (WorkInvoiceReceiptInfo info : alreadyExistList) {
|
|
for (WorkInvoiceReceiptInfo info : alreadyExistList) {
|
|
|
info.setErrorMessage("该发票已存在收款信息,添加失败");
|
|
info.setErrorMessage("该发票已存在收款信息,添加失败");
|
|
|
}
|
|
}
|
|
|
- //数据表中不存在的的数据 invoiceDetail 表中不存在,也就是说 没有开票信息
|
|
|
|
|
List<WorkInvoiceReceiptInfo> inexistenceList = map.get("inexistenceList");
|
|
List<WorkInvoiceReceiptInfo> inexistenceList = map.get("inexistenceList");
|
|
|
for (WorkInvoiceReceiptInfo info : inexistenceList) {
|
|
for (WorkInvoiceReceiptInfo info : inexistenceList) {
|
|
|
info.setErrorMessage("系统中不存在该发票信息,添加失败");
|
|
info.setErrorMessage("系统中不存在该发票信息,添加失败");
|
|
|
}
|
|
}
|
|
|
- //数据表中金额大于开票价的的数据
|
|
|
|
|
List<WorkInvoiceReceiptInfo> moneyMismatchingList = map.get("moneyMismatchingList");
|
|
List<WorkInvoiceReceiptInfo> moneyMismatchingList = map.get("moneyMismatchingList");
|
|
|
for (WorkInvoiceReceiptInfo info : moneyMismatchingList) {
|
|
for (WorkInvoiceReceiptInfo info : moneyMismatchingList) {
|
|
|
info.setErrorMessage("发票金额大于系统开票金额,添加失败");
|
|
info.setErrorMessage("发票金额大于系统开票金额,添加失败");
|
|
|
}
|
|
}
|
|
|
- //如果导入的数据量大于有效的数据量,说明导入的数据存在重复、错误等问题,直接抛出
|
|
|
|
|
- if(list.size() >uniqueList.size()){
|
|
|
|
|
- // 6. 核心:生成结果Excel文件(分2个Sheet),并通过浏览器下载
|
|
|
|
|
- generateImportResultExcel(uniqueList, errorList, duplicateList, alreadyExistList, inexistenceList, moneyMismatchingList,list, response);
|
|
|
|
|
- addMessage(redirectAttributes, "导入数据存在问题,详情请查看返回的文档信息。");
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 【核心逻辑不变】生成Excel文件到指定文件夹
|
|
|
|
|
+ if(list.size() > uniqueList.size()){
|
|
|
|
|
+ excelFileName = generateImportResultExcel(uniqueList, errorList, duplicateList, alreadyExistList,
|
|
|
|
|
+ inexistenceList, moneyMismatchingList, list);
|
|
|
|
|
+ result.put("msg", "导入数据存在问题,可下载文档查看详情。");
|
|
|
|
|
+ result.put("excelFileName", excelFileName); // 返回Excel文件名
|
|
|
}else{
|
|
}else{
|
|
|
- addMessage(redirectAttributes, "已成功导入 "+list.size()+" 条发票收款记录"+failureMsg);
|
|
|
|
|
|
|
+ result.put("msg", "已成功导入 "+list.size()+" 条发票收款记录"+failureMsg);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ result.put("success", true); // 业务处理成功(即使有Excel,也是处理完成)
|
|
|
|
|
+
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
- addMessage(redirectAttributes, "导入发票收款记录失败!失败信息:"+e.getMessage());
|
|
|
|
|
|
|
+ result.put("msg", "导入发票收款记录失败!失败信息:"+e.getMessage());
|
|
|
logger.error("Exception e:"+e);
|
|
logger.error("Exception e:"+e);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- return "redirect:"+Global.getAdminPath()+"/workinvoiceAll/workInvoiceAll/?repage";
|
|
|
|
|
-
|
|
|
|
|
|
|
+ return result; // 返回JSON结果给AJAX
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -1744,19 +1761,38 @@ public class WorkInvoiceAllController extends BaseController {
|
|
|
* @param metadataList 导入原数据
|
|
* @param metadataList 导入原数据
|
|
|
* @param response 响应对象,用于输出下载流
|
|
* @param response 响应对象,用于输出下载流
|
|
|
*/
|
|
*/
|
|
|
- private void generateImportResultExcel(List<WorkInvoiceReceiptInfo> uniqueList,
|
|
|
|
|
- List<WorkInvoiceReceiptInfo> errorList,
|
|
|
|
|
- List<WorkInvoiceReceiptInfo> duplicateList,
|
|
|
|
|
- List<WorkInvoiceReceiptInfo> alreadyExistList,
|
|
|
|
|
- List<WorkInvoiceReceiptInfo> inexistenceList,
|
|
|
|
|
- List<WorkInvoiceReceiptInfo> moneyMismatchingList,
|
|
|
|
|
- List<WorkInvoiceReceiptInfo> metadataList,
|
|
|
|
|
- HttpServletResponse response) throws Exception {
|
|
|
|
|
-
|
|
|
|
|
- // 1. 创建多页签导出工具实例
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 改造后:生成Excel到指定文件夹,返回唯一文件名(不再直接输出到response)
|
|
|
|
|
+ */
|
|
|
|
|
+ private String generateImportResultExcel(List<WorkInvoiceReceiptInfo> uniqueList,
|
|
|
|
|
+ List<WorkInvoiceReceiptInfo> errorList,
|
|
|
|
|
+ List<WorkInvoiceReceiptInfo> duplicateList,
|
|
|
|
|
+ List<WorkInvoiceReceiptInfo> alreadyExistList,
|
|
|
|
|
+ List<WorkInvoiceReceiptInfo> inexistenceList,
|
|
|
|
|
+ List<WorkInvoiceReceiptInfo> moneyMismatchingList,
|
|
|
|
|
+ List<WorkInvoiceReceiptInfo> metadataList) throws Exception {
|
|
|
|
|
+
|
|
|
|
|
+ String path = null;
|
|
|
|
|
+ if (System.getProperty("os.name").toLowerCase().contains("win")) {
|
|
|
|
|
+ path = "D:/attachment-file/invoiceBatch/";
|
|
|
|
|
+ } else {
|
|
|
|
|
+ path = "/attachment-file/invoiceBatch/";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 1. 创建存储文件夹(不存在则自动创建)
|
|
|
|
|
+ File saveDir = new File(path);
|
|
|
|
|
+ if (!saveDir.exists()) {
|
|
|
|
|
+ saveDir.mkdirs();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 生成唯一文件名(避免覆盖)
|
|
|
|
|
+ String fileName = "发票收款导入数据汇总_" + UserUtils.getUser().getId() + ".xlsx";
|
|
|
|
|
+ String fullFilePath = path + fileName;
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 创建多页签导出工具实例(原有逻辑不变)
|
|
|
ExportMultipleTabsExcel exporter = new ExportMultipleTabsExcel();
|
|
ExportMultipleTabsExcel exporter = new ExportMultipleTabsExcel();
|
|
|
|
|
|
|
|
- // 处理可能的空列表,避免导出工具报错
|
|
|
|
|
|
|
+ // 4. 处理空列表(原有逻辑不变)
|
|
|
uniqueList = uniqueList == null ? Collections.emptyList() : uniqueList;
|
|
uniqueList = uniqueList == null ? Collections.emptyList() : uniqueList;
|
|
|
errorList = errorList == null ? Collections.emptyList() : errorList;
|
|
errorList = errorList == null ? Collections.emptyList() : errorList;
|
|
|
duplicateList = duplicateList == null ? Collections.emptyList() : duplicateList;
|
|
duplicateList = duplicateList == null ? Collections.emptyList() : duplicateList;
|
|
@@ -1764,7 +1800,7 @@ public class WorkInvoiceAllController extends BaseController {
|
|
|
inexistenceList = inexistenceList == null ? Collections.emptyList() : inexistenceList;
|
|
inexistenceList = inexistenceList == null ? Collections.emptyList() : inexistenceList;
|
|
|
moneyMismatchingList = moneyMismatchingList == null ? Collections.emptyList() : moneyMismatchingList;
|
|
moneyMismatchingList = moneyMismatchingList == null ? Collections.emptyList() : moneyMismatchingList;
|
|
|
|
|
|
|
|
- // 3. 添加Sheet页(页签名称、标题、实体类、数据列表)
|
|
|
|
|
|
|
+ // 5. 添加Sheet页(原有逻辑完全不变)
|
|
|
if (!uniqueList.isEmpty()) {
|
|
if (!uniqueList.isEmpty()) {
|
|
|
exporter.addSheet("有效数据", "批量收款导入有效数据", WorkInvoiceReceiptInfo.class, uniqueList);
|
|
exporter.addSheet("有效数据", "批量收款导入有效数据", WorkInvoiceReceiptInfo.class, uniqueList);
|
|
|
}
|
|
}
|
|
@@ -1777,38 +1813,131 @@ public class WorkInvoiceAllController extends BaseController {
|
|
|
if (!alreadyExistList.isEmpty()) {
|
|
if (!alreadyExistList.isEmpty()) {
|
|
|
exporter.addSheet("已存在收款数据", "批量收款导入已存在收款数据", WorkInvoiceReceiptInfo.class, alreadyExistList);
|
|
exporter.addSheet("已存在收款数据", "批量收款导入已存在收款数据", WorkInvoiceReceiptInfo.class, alreadyExistList);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
if (!inexistenceList.isEmpty()) {
|
|
if (!inexistenceList.isEmpty()) {
|
|
|
exporter.addSheet("不存在的发票信息", "批量收款导入不存在的发票信息", WorkInvoiceReceiptInfo.class, inexistenceList);
|
|
exporter.addSheet("不存在的发票信息", "批量收款导入不存在的发票信息", WorkInvoiceReceiptInfo.class, inexistenceList);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
if (!moneyMismatchingList.isEmpty()) {
|
|
if (!moneyMismatchingList.isEmpty()) {
|
|
|
exporter.addSheet("发票金额大于系统开票金额", "批量收款导入发票金额大于系统开票金额数据", WorkInvoiceReceiptInfo.class, moneyMismatchingList);
|
|
exporter.addSheet("发票金额大于系统开票金额", "批量收款导入发票金额大于系统开票金额数据", WorkInvoiceReceiptInfo.class, moneyMismatchingList);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
if (!metadataList.isEmpty()) {
|
|
if (!metadataList.isEmpty()) {
|
|
|
exporter.addSheet("原数据", "批量收款导入原数据", WorkInvoiceReceiptInfo.class, metadataList);
|
|
exporter.addSheet("原数据", "批量收款导入原数据", WorkInvoiceReceiptInfo.class, metadataList);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-
|
|
|
|
|
- // 4. 导出文件(关键:设置响应头,确保浏览器正确下载)
|
|
|
|
|
- String fileName = "发票收款导入数据汇总_" + DateUtils.getDate("yyyyMMddHHmmss") + ".xlsx";
|
|
|
|
|
- // 设置响应类型为Excel
|
|
|
|
|
- response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
|
|
|
|
- // 设置文件名(解决中文乱码)
|
|
|
|
|
- String encodedFileName = URLEncoder.encode(fileName, "UTF-8");
|
|
|
|
|
- response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedFileName);
|
|
|
|
|
- // 禁用缓存
|
|
|
|
|
- response.setHeader("Pragma", "no-cache");
|
|
|
|
|
- response.setHeader("Cache-Control", "no-cache");
|
|
|
|
|
- response.setDateHeader("Expires", 0);
|
|
|
|
|
-
|
|
|
|
|
- // 修正:直接传递response对象给write方法(移除错误的类型转换)
|
|
|
|
|
- exporter.write(response, fileName);
|
|
|
|
|
|
|
+ // 6. 核心修改:生成Excel到指定文件夹(通过FileOutputStream)
|
|
|
|
|
+ try (FileOutputStream fos = new FileOutputStream(fullFilePath)) {
|
|
|
|
|
+ exporter.write(fos); // 输出到文件流,而非response
|
|
|
|
|
+ }
|
|
|
exporter.dispose(); // 清理资源
|
|
exporter.dispose(); // 清理资源
|
|
|
|
|
|
|
|
|
|
+ // 7. 返回唯一文件名(传给前端)
|
|
|
|
|
+ return fileName;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 新增:Excel下载接口(前端询问用户确认后调用)
|
|
|
|
|
+ * @param fileName 前端传递的Excel文件名
|
|
|
|
|
+ * @param response 响应对象
|
|
|
|
|
+ */
|
|
|
|
|
+ @RequestMapping("/downloadExcel")
|
|
|
|
|
+ public void downloadExcel(String fileName, HttpServletResponse response) {
|
|
|
|
|
+ // 1. 新增日志:打印关键信息,方便排查
|
|
|
|
|
+ logger.info("开始下载Excel,文件名:{}", fileName);
|
|
|
|
|
+ if (StringUtils.isBlank(fileName)) {
|
|
|
|
|
+ logger.error("下载Excel失败:文件名为空");
|
|
|
|
|
+ response.setContentType("text/plain;charset=UTF-8"); // 明确响应类型
|
|
|
|
|
+ try {
|
|
|
|
|
+ response.getWriter().write("文件名不能为空");
|
|
|
|
|
+ } catch (IOException e) {
|
|
|
|
|
+ logger.error("返回文件名空提示失败", e);
|
|
|
|
|
+ }
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 确定文件存储路径(新增日志打印路径)
|
|
|
|
|
+ String path = null;
|
|
|
|
|
+ if (System.getProperty("os.name").toLowerCase().contains("win")) {
|
|
|
|
|
+ path = "D:/attachment-file/invoiceBatch/";
|
|
|
|
|
+ } else {
|
|
|
|
|
+ path = "/attachment-file/invoiceBatch/";
|
|
|
|
|
+ }
|
|
|
|
|
+ String fullFilePath = path + fileName;
|
|
|
|
|
+ logger.info("Excel文件完整路径:{}", fullFilePath);
|
|
|
|
|
+ File excelFile = new File(fullFilePath);
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 检查文件是否存在(新增权限检查)
|
|
|
|
|
+ if (!excelFile.exists()) {
|
|
|
|
|
+ logger.error("下载Excel失败:文件不存在,路径:{}", fullFilePath);
|
|
|
|
|
+ response.setContentType("text/plain;charset=UTF-8");
|
|
|
|
|
+ try {
|
|
|
|
|
+ response.getWriter().write("文件不存在或已被清理");
|
|
|
|
|
+ } catch (IOException e) {
|
|
|
|
|
+ logger.error("返回文件不存在提示失败", e);
|
|
|
|
|
+ }
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!excelFile.canRead()) {
|
|
|
|
|
+ logger.error("下载Excel失败:文件无读取权限,路径:{}", fullFilePath);
|
|
|
|
|
+ response.setContentType("text/plain;charset=UTF-8");
|
|
|
|
|
+ try {
|
|
|
|
|
+ response.getWriter().write("服务器无文件读取权限");
|
|
|
|
|
+ } catch (IOException e) {
|
|
|
|
|
+ logger.error("返回权限提示失败", e);
|
|
|
|
|
+ }
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 4. 核心修复:补全响应头(适配Servlet 2.5)
|
|
|
|
|
+ response.reset(); // 清空原有响应头,避免冲突
|
|
|
|
|
+ response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
|
|
|
|
+ response.setCharacterEncoding("UTF-8");
|
|
|
|
|
+ // 修复Content-Disposition格式:兼容所有浏览器
|
|
|
|
|
+ String encodedFileName = URLEncoder.encode(fileName, "UTF-8");
|
|
|
|
|
+ response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedFileName + "\"; filename*=UTF-8''" + encodedFileName);
|
|
|
|
|
+
|
|
|
|
|
+ // ========== Servlet 2.5 兼容关键:替换 setContentLengthLong ==========
|
|
|
|
|
+ // setContentLength(int):Servlet 2.5 原生方法,Excel文件大小远小于2G,完全够用
|
|
|
|
|
+ long fileSize = excelFile.length();
|
|
|
|
|
+ if (fileSize > Integer.MAX_VALUE) {
|
|
|
|
|
+ logger.warn("文件大小超过2G({}字节),Servlet 2.5无法设置Content-Length,可能影响部分浏览器下载", fileSize);
|
|
|
|
|
+ // 超过2G时不设置(Excel几乎不会出现此情况)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ response.setContentLength((int) fileSize); // 兼容Servlet 2.5
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 禁用缓存(补全)
|
|
|
|
|
+ response.setHeader("Pragma", "no-cache");
|
|
|
|
|
+ response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
|
|
|
|
|
+ response.setDateHeader("Expires", 0);
|
|
|
|
|
+
|
|
|
|
|
+ // 5. 读取文件并输出(增大缓冲区+强制flush)
|
|
|
|
|
+ try (FileInputStream fis = new FileInputStream(excelFile);
|
|
|
|
|
+ OutputStream os = response.getOutputStream()) {
|
|
|
|
|
+ byte[] buffer = new byte[4096]; // 增大缓冲区,提升传输效率
|
|
|
|
|
+ int len;
|
|
|
|
|
+ while ((len = fis.read(buffer)) != -1) {
|
|
|
|
|
+ os.write(buffer, 0, len);
|
|
|
|
|
+ }
|
|
|
|
|
+ os.flush(); // 强制刷出所有数据,避免流残留
|
|
|
|
|
+ }
|
|
|
|
|
+ logger.info("Excel下载成功,文件名:{},路径:{}", fileName, fullFilePath);
|
|
|
|
|
+
|
|
|
|
|
+ // 可选:下载完成后删除文件
|
|
|
|
|
+ // if (excelFile.delete()) {
|
|
|
|
|
+ // logger.info("下载后删除临时文件成功:{}", fullFilePath);
|
|
|
|
|
+ // } else {
|
|
|
|
|
+ // logger.warn("下载后删除临时文件失败:{}", fullFilePath);
|
|
|
|
|
+ // }
|
|
|
|
|
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ logger.error("下载Excel失败,文件名:{},路径:{}", fileName, fullFilePath, e);
|
|
|
|
|
+ response.setContentType("text/plain;charset=UTF-8");
|
|
|
|
|
+ try {
|
|
|
|
|
+ response.getWriter().write("下载失败:" + e.getMessage());
|
|
|
|
|
+ } catch (IOException ex) {
|
|
|
|
|
+ logger.error("返回下载失败提示失败", ex);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
}
|
|
}
|