Browse Source

导出修改

master
shenzhouyu 5 months ago
parent
commit
bda25ce542
  1. 5
      src/main/java/com/xujie/sys/modules/pms/controller/QcReportController.java
  2. 6
      src/main/java/com/xujie/sys/modules/pms/mapper/QcReportMapper.java
  3. 134
      src/main/java/com/xujie/sys/modules/pms/service/Impl/QcReportServiceImpl.java
  4. 185
      src/main/resources/mapper/pms/QcReportMapper.xml

5
src/main/java/com/xujie/sys/modules/pms/controller/QcReportController.java

@ -6,10 +6,7 @@ import com.xujie.sys.modules.pms.data.QcMethodData;
import com.xujie.sys.modules.pms.data.QcReportData;
import com.xujie.sys.modules.pms.service.QcReportService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

6
src/main/java/com/xujie/sys/modules/pms/mapper/QcReportMapper.java

@ -36,4 +36,10 @@ public interface QcReportMapper {
IPage<QcReportData> getOQCReportCount(Page<QcReportData> qcReportDataPage, @Param("query") QcReportData data);
List<QcReportFQASData> downloadOQCRecord(QcReportData data);
// 优化方法使用OFFSET分页避免PageHelper开销
List<QcReportIPQCData> downloadIPQCRecordWithOffset(Page<QcReportData> qcReportDataPage,@Param("query")QcReportData data);
// 优化方法仅查询总数不返回具体数据
int getIPQCReportCountOptimized(@Param("query") QcReportData data);
}

134
src/main/java/com/xujie/sys/modules/pms/service/Impl/QcReportServiceImpl.java

@ -20,10 +20,7 @@ import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.concurrent.*;
@Service
@ -124,59 +121,108 @@ public class QcReportServiceImpl implements QcReportService {
@Override
public void downloadQcRecordMillion(HttpServletResponse response, QcReportData data) throws Exception {
ServletOutputStream out = null;
ExcelWriter writer = null;
ExecutorService executor = null;
try {
// 1. 提前设置响应头必须在获取输出流前
String fileName = URLEncoder.encode("QC报表", "UTF-8");
response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
// 2. 获取输出流
out = response.getOutputStream();
// 设置EXCEL名称
String fileName = URLEncoder.encode("QC报表", "UTF-8");
// 3. 校验下载类型
if (!"ipqc".equals(data.getDownloadType())) {
throw new IllegalArgumentException("不支持的下载类型: " + data.getDownloadType());
}
// 设置SHEET名称
WriteSheet sheet = new WriteSheet();
sheet.setSheetName("明细列表sheet1");
// 4. 查询总数
int totalRowCount = this.qcReportMapper.getIPQCReportCountOptimized(data);
if (totalRowCount <= 0) {
// 处理空数据写入空Excel避免客户端收到损坏文件
writer = EasyExcel.write(out, QcReportIPQCData.class).autoCloseStream(false).build();
WriteSheet sheet = EasyExcel.writerSheet("检验单明细").build();
writer.write(Collections.emptyList(), sheet);
writer.finish();
out.flush();
return;
}
int totalRowCount = 0;
// 查询总数并封装相关变量
if ("ipqc".equals(data.getDownloadType())) {
IPage<QcReportData> list = this.qcReportMapper.getIPQCReportCount(new Page<QcReportData>(data.getPage(), data.getLimit()), data);
totalRowCount = (int)list.getTotal();
int pageSize = ExcelConstant.PER_WRITE_ROW_COUNT;
int writeCount = totalRowCount % pageSize == 0 ? (totalRowCount / pageSize) : (totalRowCount / pageSize + 1);
// 1. 循环外创建线程池
ExecutorService executor = Executors.newFixedThreadPool(Math.min(writeCount, 10));
List<FutureTask<List<QcReportIPQCData>>> futureTaskList = new ArrayList<>();
for (int i = 0; i < writeCount; i++) {
int pageNum = i + 1; // 子线程中使用的页码
FutureTask<List<QcReportIPQCData>> futureTask = new FutureTask<>(() -> {
PageHelper.startPage(pageNum, pageSize);
return this.qcReportMapper.downloadIPQCRecord(data);
});
executor.execute(futureTask);
futureTaskList.add(futureTask);
}
// 5. 分页参数
int pageSize = ExcelConstant.PER_WRITE_ROW_COUNT;
int writeCount = (totalRowCount + pageSize - 1) / pageSize; // 优化分页计算
executor.shutdown();
executor.awaitTermination(1, TimeUnit.HOURS);
// 6. 线程池明确配置避免资源泄漏
executor = new ThreadPoolExecutor(
Math.min(10, Runtime.getRuntime().availableProcessors() + 1),
10,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(100),
new ThreadPoolExecutor.CallerRunsPolicy()
);
ExcelWriter writer = EasyExcel.write(out, QcReportIPQCData.class).build();
sheet = EasyExcel.writerSheet("检验单明细").build();
for (FutureTask<List<QcReportIPQCData>> task : futureTaskList) {
List<QcReportIPQCData> dataList = task.get(); // 获取单批数据
writer.write(dataList, sheet); // 分批写入
}
writer.finish();
List<Future<List<QcReportIPQCData>>> futureList = new ArrayList<>();
for (int i = 0; i < writeCount; i++) {
int pageNum = i + 1;
futureList.add(executor.submit(() ->
this.qcReportMapper.downloadIPQCRecordWithOffset(new Page<>(pageNum, pageSize), data)
));
}
// 7. 关闭线程池并等待
executor.shutdown();
if (!executor.awaitTermination(1, TimeUnit.HOURS)) {
executor.shutdownNow(); // 超时强制关闭
}
// 下载EXCEL
response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
// 8. 写入Excel禁用自动关闭流
writer = EasyExcel.write(out, QcReportIPQCData.class)
.autoCloseStream(false) // 手动控制流关闭
.build();
WriteSheet sheet = EasyExcel.writerSheet("检验单明细").build();
// 9. 处理子线程结果捕获异常
for (Future<List<QcReportIPQCData>> future : futureList) {
try {
List<QcReportIPQCData> dataList = future.get(30, TimeUnit.SECONDS); // 单个任务超时
if (dataList != null) {
writer.write(dataList, sheet);
}
} catch (ExecutionException e) {
// 子线程异常如SQL错误
throw new RuntimeException("分页查询失败: " + e.getCause().getMessage(), e.getCause());
} catch (TimeoutException e) {
throw new RuntimeException("分页查询超时", e);
}
}
writer.finish();
out.flush();
} catch (Exception e) {
// 增强异常信息便于排查
throw new RuntimeException("下载QC报表失败: " + e.getMessage(), e);
} finally {
// 10. 按顺序关闭资源先关闭writer再关闭流
if (writer != null) {
try {
writer.finish(); // 确保最后关闭writer
} catch (Exception e) {
e.printStackTrace();
}
}
if (out != null) {
out.close();
try {
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (executor != null && !executor.isTerminated()) {
executor.shutdownNow();
}
}
}

185
src/main/resources/mapper/pms/QcReportMapper.xml

@ -1347,4 +1347,189 @@
END, a.create_date desc
</select>
<!-- 优化版本:使用OFFSET分页的IPQC导出查询 -->
<select id="downloadIPQCRecordWithOffset" parameterType="com.xujie.sys.modules.pms.data.QcReportData" resultType="com.xujie.sys.modules.pms.data.QcReportIPQCData">
SELECT
a.inspection_no,
a.site,
a.bu_no,
dbo.get_bu_desc(a.site, a.bu_no) as buDesc,
a.state,
a.inspection_result,
a.task_date,
a.inspection_type_no,
a.inspection_cycle,
a.order_no,
a.operation_desc,
a.resource_id,
r.resourceDesc,
a.part_no,
d.PartDescription as part_desc,
d.spec,
a.inspection_remark,
a.roll_qty,
a.sampling_qty,
a.disposal_measures,
a.disposal_remark,
a.inspector_date,
a.seq_no,
a.batch_roll_no,
a.special_requirements,
a.work_center_no,
wc.WorkCenterDesc as workCenterDesc,
a.roll_no,
a.um_id,
um.UMName as umName,
a.action_date,
a.action_by,
a.pass_qty,
a.not_pass_qty,
b.item_no,
b.item_desc,
b.default_value,
b.max_value,
b.min_value,
b.sampling_qty as itemSamplingQty,
b.unqualified_quantity,
b.item_result,
CASE WHEN b.item_result = 'Y' THEN '合格'
WHEN b.item_result = 'N' THEN '不合格'
END as itemResultDesc,
CASE WHEN b.value_type_db = 'T' THEN b.text_value
WHEN b.value_type_db = 'N' THEN CONVERT(varchar, b.number_value, 126)
END as textValue,
isnull(dbo.joint_name (a.site, a.bu_no, a.inspection_no, 'coordination'), '') AS operatorName,
isnull(dbo.joint_id (a.site, a.bu_no, a.inspection_no, 'supplier'), '') AS responsiblePerson
FROM qc_ipqc_record as a
LEFT JOIN qc_ipqc_detailed_record b ON a.site = b.site AND a.bu_no = b.bu_no AND a.inspection_no = b.inspection_no
left join WorkCenterResource as r on a.site = r.site and a.resource_id = r.resourceID
left join part as d on a.site = d.site and a.part_no = d.PartNo
left join UM as um on a.site = um.site and a.um_id = um.UMID
left join WorkCenter as wc on a.site = wc.site and a.work_center_no = wc.WorkCenterNo
<where>
a.site in (select site from eam_access_site where username = #{query.userName})
and (a.site + '-' + a.bu_no) in (select * from dbo.query_bu(#{query.userName}))
<if test="query.buDesc != null and query.buDesc != ''">
AND dbo.get_bu_desc (a.site, a.bu_no) = #{query.buDesc}
</if>
<if test = "query.inspectionNo != null and query.inspectionNo != ''">
AND a.inspection_no LIKE #{query.inspectionNo}
</if>
<if test = "query.partNo != null and query.partNo != ''">
AND a.part_no LIKE #{query.partNo}
</if>
<if test = "query.partDesc != null and query.partDesc != ''">
AND d.PartDescription LIKE #{query.partDesc}
</if>
<if test = "query.states != null and query.states.size > 0">
AND a.state in
<foreach item="item" collection="query.states" open="(" separator="," close=")">
#{item}
</foreach>
</if>
<if test = "query.inspectionTypeNo != null and query.inspectionTypeNo != ''">
AND a.inspection_type_no = #{query.inspectionTypeNo}
</if>
<if test = "query.inspectionResult != null and query.inspectionResult != ''">
AND a.inspection_result = #{query.inspectionResult}
</if>
<if test = "query.disposalMeasures != null and query.disposalMeasures != ''">
AND a.disposal_measures = #{query.disposalMeasures}
</if>
<if test = "query.orderNo != null and query.orderNo != ''">
AND a.order_no LIKE #{query.orderNo}
</if>
<if test = "query.seqNo != null and query.seqNo != ''">
AND a.seq_no LIKE #{query.seqNo}
</if>
<if test = "query.operationDesc != null and query.operationDesc != ''">
AND a.operation_desc LIKE #{query.operationDesc}
</if>
<if test="query.startDate != null">
AND a.inspector_date >= #{query.startDate}
</if>
<if test="query.endDate != null">
AND #{query.endDate} >= a.inspector_date
</if>
<if test="query.startDate2 != null">
AND a.task_date >= #{query.startDate2}
</if>
<if test="query.endDate2 != null">
AND #{query.endDate2} >= a.task_date
</if>
<if test = "query.itemResult != null and query.itemResult != ''">
AND b.item_result = #{query.itemResult}
</if>
</where>
ORDER BY
CASE WHEN a.state = '待检验' THEN 1
WHEN a.state = '待审核' THEN 2
WHEN a.state = '已完成' THEN 3
END, a.task_date desc
</select>
<!-- 优化版本:仅查询总数的IPQC统计查询 -->
<select id="getIPQCReportCountOptimized" parameterType="com.xujie.sys.modules.pms.data.QcReportData" resultType="int">
SELECT
count(1)
from qc_ipqc_detailed_record as b
Left JOIN qc_ipqc_record as a ON a.site = b.site AND a.bu_no = b.bu_no AND a.inspection_no = b.inspection_no
left join part as d on a.site = d.site and a.part_no = d.PartNo
<where>
a.site in (select site from eam_access_site where username = #{query.userName})
and (a.site + '-' + a.bu_no) in (select * from dbo.query_bu(#{query.userName}))
<if test="query.buDesc != null and query.buDesc != ''">
AND dbo.get_bu_desc (a.site, a.bu_no) = #{query.buDesc}
</if>
<if test = "query.inspectionNo != null and query.inspectionNo != ''">
AND a.inspection_no LIKE #{query.inspectionNo}
</if>
<if test = "query.partNo != null and query.partNo != ''">
AND a.part_no LIKE #{query.partNo}
</if>
<if test = "query.partDesc != null and query.partDesc != ''">
AND d.PartDescription LIKE #{query.partDesc}
</if>
<if test = "query.states != null and query.states.size > 0">
AND a.state in
<foreach item="item" collection="query.states" open="(" separator="," close=")">
#{item}
</foreach>
</if>
<if test = "query.inspectionTypeNo != null and query.inspectionTypeNo != ''">
AND a.inspection_type_no = #{query.inspectionTypeNo}
</if>
<if test = "query.inspectionResult != null and query.inspectionResult != ''">
AND a.inspection_result = #{query.inspectionResult}
</if>
<if test = "query.disposalMeasures != null and query.disposalMeasures != ''">
AND a.disposal_measures = #{query.disposalMeasures}
</if>
<if test = "query.orderNo != null and query.orderNo != ''">
AND a.order_no LIKE #{query.orderNo}
</if>
<if test = "query.seqNo != null and query.seqNo != ''">
AND a.seq_no LIKE #{query.seqNo}
</if>
<if test = "query.operationDesc != null and query.operationDesc != ''">
AND a.operation_desc LIKE #{query.operationDesc}
</if>
<if test="query.startDate != null">
AND a.inspector_date >= #{query.startDate}
</if>
<if test="query.endDate != null">
AND #{query.endDate} >= a.inspector_date
</if>
<if test="query.startDate2 != null">
AND a.task_date >= #{query.startDate2}
</if>
<if test="query.endDate2 != null">
AND #{query.endDate2} >= a.task_date
</if>
<if test = "query.itemResult != null and query.itemResult != ''">
AND b.item_result = #{query.itemResult}
</if>
</where>
</select>
</mapper>
Loading…
Cancel
Save