1、背景介绍
读13张表,4000条放到一个excel,打包成zip,并加密下载。本文为Demo版本,实现了多线程导出excel并打包zip提供下载,没有实现每4000条放到一个zip中以及zip加密。
2、pom.xml
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.8.0</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.8.0</version> </dependency> <!-- https://mvnrepository.com/artifact/com.alibaba/druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.22</version> </dependency> <!--MySQL数据库驱动--> <dependency> <groupId>javax.jms</groupId> <artifactId>javax.jms-api</artifactId> <version>2.0.1</version> </dependency> <dependency> <groupId>com.caucho</groupId> <artifactId>hessian</artifactId> <version>4.0.38</version> </dependency> <!-- json schema 转换 fge --> <dependency> <groupId>com.github.fge</groupId> <artifactId>json-schema-validator</artifactId> <version>2.2.6</version> </dependency> <!-- mybatis-plus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.3.2</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-support</artifactId> <version>2.3</version> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.5</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.1.6</version> </dependency> </dependencies>
2、config包下多线程配置类
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.Executor; import java.util.concurrent.ThreadPoolExecutor; @Configuration public class ExecutorConfig { private static final Logger logger = LoggerFactory.getLogger(ExecutorConfig.class); @Value("${task.pool.corePoolSize}") private int corePoolSize; @Value("${task.pool.maxPoolSize}") private int maxPoolSize; @Value("${task.pool.keepAliveSeconds}") private int keepAliveSeconds; @Value("${task.pool.queueCapacity}") private int queueCapacity; @Value("${task.pool.threadNamePrefix}") private String threadNamePrefix; @Bean public Executor asyncExcelServiceExecutor() { logger.info("...ExecutorConfig...asyncServiceExecutor()...启动[zip任务]线程池..."); ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(corePoolSize); executor.setMaxPoolSize(maxPoolSize); executor.setThreadNamePrefix(threadNamePrefix); executor.setKeepAliveSeconds(keepAliveSeconds); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.initialize(); return executor; } }
3、application-dev.properties多线程设置
task.pool.corePoolSize=15 task.pool.maxPoolSize=99 task.pool.keepAliveSeconds=300 task.pool.queueCapacity=999 task.pool.threadNamePrefix=Grape-
4、开启多线程
@EnableAsync @SpringBootApplication @MapperScan(basePackages = {"....ry.dao"}) public class BasicSystem { public static void main(String[] args) { SpringApplication.run(BasicSystem.class, args); } }
5、service层方法
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.InputStream; import java.util.concurrent.CountDownLatch; import java.util.zip.ZipOutputStream; @Service public class NOnij { @Autowired private NOnijAsync nOnijAsync; public void zip(HttpServletResponse response) throws IOException { response.setContentType("application/force-download"); response.addHeader("Access-Control-Expose-Headers", "Content-Disposition"); response.setHeader("Content-Disposition", "attachment; filename=" + new String(("sjn-" + DateUtils.getDateTime() + ".zip").getBytes("UTF-8"), "ISO8859-1")); ZipOutputStream zipout = new ZipOutputStream(response.getOutputStream()); InputStream inputStream = null; try { //加闩 CountDownLatch latch = new CountDownLatch(2); nOnijAsync.excelUser(latch, zipout, inputStream); nOnijAsync.excelProject(latch, zipout, inputStream); //等待N个线程执行完毕 latch.await(); System.out.println("---所有线程---end---"); } catch (InterruptedException e) { } catch (IOException e) { System.out.println(e.getMessage()); } finally { if (zipout != null) { zipout.close(); } if (inputStream != null) { inputStream.close(); } } } }
6、多线程方法
import com.alibaba.excel.EasyExcel; import com.alibaba.excel.ExcelWriter; import com.alibaba.excel.write.metadata.WriteSheet; import com.baomidou.mybatisplus.plugins.Page; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Future; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; @Component public class NOnijAsync { @Autowired private UserMapper userMapper; @Autowired private ProductMapper productMapper; @Async("asyncExcelServiceExecutor") public void excelProject(CountDownLatch latch, ZipOutputStream zipout, InputStream inputStream) throws IOException { String currentThreadName = Thread.currentThread().getName(); System.out.println("---线程: 【" + currentThreadName + "】 ---start---Project---"); //分页查询数据,然后放到循环中进行写表 List<Product> products = productMapper.selectList(null); products.add(new Product("小明", "21")); products.add(new Product("小明", "21")); products.add(new Product("小明", "21")); products.add(new Product("小明", "21")); products.add(new Product("小明", "21")); getZip(products, zipout, inputStream, Product.class, "project"); latch.countDown(); } @Async("asyncExcelServiceExecutor") public Future<List<Page>> excelUser(CountDownLatch latch, ZipOutputStream zipout, InputStream inputStream) throws IOException { String currentThreadName = Thread.currentThread().getName(); System.out.println("---线程: 【" + currentThreadName + "】 ---start---User---"); List<User> users = userMapper.selectList(null); users.add(new User("小丽", "18")); users.add(new User("小丽", "18")); users.add(new User("小丽", "18")); users.add(new User("小丽", "18")); users.add(new User("小丽", "18")); users.add(new User("小丽", "18")); getZip(users, zipout, inputStream, User.class, "user"); latch.countDown(); return null; } private void getZip(List datas, ZipOutputStream zipout, InputStream inputStream, Class clazz, String excelName) throws IOException { //sheetName页名称 String sheetName1 = "sheet1"; ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ExcelWriter writer = EasyExcel.write(outputStream, clazz).build(); WriteSheet writeSheet = EasyExcel.writerSheet(sheetName1).build(); //导出excel writer.write(datas, writeSheet); writer.finish(); inputStream = new ByteArrayInputStream(outputStream.toByteArray()); //excel文件写入zip ZipEntry zipEntry = new ZipEntry(excelName + DateUtils.getDateTime() + ".xlsx");///DateUtils.getDateTime()线程非安全 zipout.putNextEntry(zipEntry); int len; byte[] buf = new byte[1024]; while ((len = inputStream.read(buf)) > 0) { zipout.write(buf, 0, len); } } }
参考:
https://blog.csdn.net/qq_35493807/article/details/105613898
参考2:
@Controller public class TestExportZipController { @GetMapping("/111") public void export(HttpServletResponse response) throws IOException { response.setContentType("application/force-download"); response.addHeader("Access-Control-Expose-Headers", "Content-Disposition"); response.setHeader("Content-Disposition", "attachment; filename=" + new String(("sjn-" + DateUtils.getDateTime() + ".zip").getBytes("UTF-8"), "ISO8859-1")); ZipOutputStream zipout = new ZipOutputStream(response.getOutputStream()); InputStream inputStream = null; try { for (int i = 0; i < 3; i++) { ArrayList<UserVO> userVOList = new ArrayList<>(); userVOList.add(new UserVO("haha", 1)); userVOList.add(new UserVO("haha2", 12)); userVOList.add(new UserVO("haha4", 14)); userVOList.add(new UserVO("haha3", 13)); userVOList.add(new UserVO("haha5", 15)); //sheetName页名称 String sheetName = "sheetName"; ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ExcelWriter writer = EasyExcel.write(outputStream, UserVO.class).build(); WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).build(); //导出excel writer.write(userVOList, writeSheet); writer.finish(); inputStream = new ByteArrayInputStream(outputStream.toByteArray()); //excel文件写入zip ZipEntry zipEntry = new ZipEntry(DateUtils.getDateTime() + "-" + i + ".xlsx"); zipout.putNextEntry(zipEntry); int len; byte[] buf = new byte[1024]; while ((len = inputStream.read(buf)) > 0) { zipout.write(buf, 0, len); } } } catch (IOException e) { System.out.println(e.getMessage()); } finally { if (zipout != null) { zipout.close(); } if (inputStream != null) { inputStream.close(); } } } }