4 changed files with 167 additions and 6 deletions
			
			
		- 
					36src/main/java/com/example/demo/controller/ExportExcelController.java
- 
					25src/main/java/com/example/demo/mapper/DetailYMapper.java
- 
					71src/main/java/com/example/demo/sevice/DataExportService.java
- 
					41src/main/java/com/example/demo/sevice/ExportExcelService.java
| @ -0,0 +1,36 @@ | |||||
|  | package com.example.demo.controller; | ||||
|  | 
 | ||||
|  | import com.example.demo.sevice.DataExportService; | ||||
|  | import jakarta.servlet.http.HttpServletResponse; | ||||
|  | import lombok.RequiredArgsConstructor; | ||||
|  | import lombok.extern.slf4j.Slf4j; | ||||
|  | import org.springframework.beans.factory.annotation.Autowired; | ||||
|  | import org.springframework.transaction.annotation.Transactional; | ||||
|  | import org.springframework.web.bind.annotation.CrossOrigin; | ||||
|  | import org.springframework.web.bind.annotation.PostMapping; | ||||
|  | import org.springframework.web.bind.annotation.RequestMapping; | ||||
|  | import org.springframework.web.bind.annotation.RestController; | ||||
|  | 
 | ||||
|  | import java.io.IOException; | ||||
|  | 
 | ||||
|  | @RestController | ||||
|  | @RequestMapping("/export") | ||||
|  | @RequiredArgsConstructor | ||||
|  | @Transactional | ||||
|  | @Slf4j | ||||
|  | @CrossOrigin | ||||
|  | public class ExportExcelController { | ||||
|  | 
 | ||||
|  |     @Autowired | ||||
|  |     private DataExportService dataExportService; | ||||
|  | 
 | ||||
|  |     @PostMapping("/exportUserExcel") | ||||
|  |     public void exportUserExcel(HttpServletResponse response) { | ||||
|  |         try { | ||||
|  |             dataExportService.exportData(response); | ||||
|  |         } catch (IOException e) { | ||||
|  |             e.printStackTrace(); | ||||
|  |             throw new RuntimeException("导出 Excel 文件失败", e); | ||||
|  |         } | ||||
|  |     } | ||||
|  | } | ||||
| @ -0,0 +1,71 @@ | |||||
|  | package com.example.demo.sevice; | ||||
|  | 
 | ||||
|  | import com.example.demo.domain.entity.UserDetailExport; | ||||
|  | import com.example.demo.mapper.DetailYMapper; | ||||
|  | import jakarta.servlet.http.HttpServletResponse; | ||||
|  | import org.springframework.beans.factory.annotation.Autowired; | ||||
|  | import org.springframework.stereotype.Service; | ||||
|  | 
 | ||||
|  | import java.io.IOException; | ||||
|  | import java.util.ArrayList; | ||||
|  | import java.util.List; | ||||
|  | import java.util.concurrent.ExecutorService; | ||||
|  | import java.util.concurrent.Executors; | ||||
|  | import java.util.concurrent.Future; | ||||
|  | 
 | ||||
|  | @Service | ||||
|  | public class DataExportService { | ||||
|  |     // 设置线程池 | ||||
|  |     private final ExecutorService executorService = Executors.newFixedThreadPool(3); // 使用10个线程的线程池 | ||||
|  | 
 | ||||
|  |     // 每次查询20w条数据 | ||||
|  |     private static final int PAGE_SIZE = 100000; | ||||
|  | 
 | ||||
|  |     @Autowired | ||||
|  |     private DetailYMapper detailYMapper; | ||||
|  | 
 | ||||
|  |     @Autowired | ||||
|  |     private ExportExcelService exportExcelService; | ||||
|  | 
 | ||||
|  |     public void exportData(HttpServletResponse response) throws IOException { | ||||
|  |         // 获取总记录数 | ||||
|  |         int totalRecords = detailYMapper.getTotalCount(); // 获取总记录数 | ||||
|  |         int totalPages = (totalRecords + PAGE_SIZE - 1) / PAGE_SIZE; // 计算总页 | ||||
|  |         // 设置Excel响应头 | ||||
|  |         exportExcelService.setExcelResponseProp(response, "userDetail"); | ||||
|  | 
 | ||||
|  |         // 创建一个集合用于收集所有查询结果 | ||||
|  |         List<UserDetailExport> allData = new ArrayList<>(); | ||||
|  |         List<Future<List<UserDetailExport>>> futures = new ArrayList<>(); | ||||
|  | 
 | ||||
|  |         // 使用多线程导出数据 | ||||
|  |         for (int page = 0; page < totalPages; page++) { | ||||
|  |             final int currentPage = page; | ||||
|  |             futures.add(executorService.submit(() -> { | ||||
|  |                 try { | ||||
|  |                     return fetchData(currentPage, PAGE_SIZE); // 查询当前页的数据 | ||||
|  |                 } catch (Exception e) { | ||||
|  |                     e.printStackTrace(); | ||||
|  |                     return new ArrayList<UserDetailExport>(); // 出错时返回空数据 | ||||
|  |                 } | ||||
|  |             })); | ||||
|  |         } | ||||
|  | 
 | ||||
|  |         // 等待所有任务完成,并收集结果 | ||||
|  |         for (Future<List<UserDetailExport>> future : futures) { | ||||
|  |             try { | ||||
|  |                 allData.addAll(future.get()); // 将每个线程的结果合并 | ||||
|  |             } catch (Exception e) { | ||||
|  |                 e.printStackTrace(); | ||||
|  |             } | ||||
|  |         } | ||||
|  | 
 | ||||
|  |         // 一次性写入Excel | ||||
|  |         exportExcelService.writeDataToSheet(response, allData, 0); | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     private List<UserDetailExport> fetchData(int page, int pageSize) { | ||||
|  |         int offset = page * pageSize; // 计算偏移量 | ||||
|  |         return detailYMapper.searchExport(offset, pageSize); // 调用Mapper查询数据 | ||||
|  |     } | ||||
|  | } | ||||
| @ -0,0 +1,41 @@ | |||||
|  | package com.example.demo.sevice; | ||||
|  | 
 | ||||
|  | import com.alibaba.excel.EasyExcel; | ||||
|  | import com.example.demo.domain.entity.UserDetailExport; | ||||
|  | import jakarta.servlet.http.HttpServletResponse; | ||||
|  | import org.springframework.stereotype.Service; | ||||
|  | 
 | ||||
|  | import java.io.IOException; | ||||
|  | import java.util.List; | ||||
|  | 
 | ||||
|  | @Service | ||||
|  | public class ExportExcelService { | ||||
|  | 
 | ||||
|  |     // 设置响应头以导出 Excel 文件 | ||||
|  |     public void setExcelResponseProp(HttpServletResponse response, String fileName) throws IOException { | ||||
|  |         response.setContentType("application/vnd.ms-excel"); | ||||
|  |         response.setCharacterEncoding("UTF-8"); | ||||
|  |         response.setHeader("Content-Disposition", "attachment; filename=" + fileName + ".xlsx"); | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     // 使用 EasyExcel 写入数据到 Excel | ||||
|  |     public void writeDataToSheet(HttpServletResponse response, List<UserDetailExport> allData, int sheetIndex) throws IOException { | ||||
|  |         int batchSize = 2000000; // 每次写入200w条 | ||||
|  |         int totalDataSize = allData.size(); | ||||
|  |         int currentSheetIndex = sheetIndex; // 用来区分不同的Sheet | ||||
|  | 
 | ||||
|  |         for (int i = 0; i < totalDataSize; i += batchSize) { | ||||
|  |             int endIndex = Math.min(i + batchSize, totalDataSize); | ||||
|  |             List<UserDetailExport> batchData = allData.subList(i, endIndex); | ||||
|  | 
 | ||||
|  |             // 每次写入一个新的 Sheet,Sheet 名称使用 currentSheetIndex | ||||
|  |             EasyExcel.write(response.getOutputStream(), UserDetailExport.class) | ||||
|  |                     .sheet("Sheet " + (currentSheetIndex + 1))  // 设置Sheet名称 | ||||
|  |                     .doWrite(batchData);  // 写入当前批次的数据 | ||||
|  | 
 | ||||
|  |             currentSheetIndex++; // 增加 Sheet 索引 | ||||
|  |         } | ||||
|  |     } | ||||
|  | } | ||||
|  | 
 | ||||
|  | 
 | ||||
						Write
						Preview
					
					
					Loading…
					
					Cancel
						Save
					
		Reference in new issue