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();
}
}
}
}