最近做项目时,有一个比较棘手的问题,就是导出多个sheet。不好处理的地方如下:
花了五六个小时,总算是大功告成,保姆式的,我把优化,转换这些细枝末节的都做完了,参考这个例子可解决导出多个 sheet 的疑难杂症。
创建订单表:tb_order
CREATE TABLE `tb_order` (
`order_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '订单id',
`total_pay` bigint(20) NOT NULL COMMENT '总金额,单位为分',
`actual_pay` bigint(20) NOT NULL COMMENT '实付金额。单位:分。如:20007,表示:200元7分',
`payment_type` tinyint(1) unsigned zerofill NOT NULL COMMENT '支付类型,1、在线支付,2、货到付款',
`post_fee` bigint(20) NOT NULL COMMENT '邮费。单位:分。如:20007,表示:200元7分',
`create_time` datetime DEFAULT NULL COMMENT '订单创建时间',
`shipping_name` varchar(20) COLLATE utf8_bin DEFAULT NULL COMMENT '物流名称',
`shipping_code` varchar(20) COLLATE utf8_bin DEFAULT NULL COMMENT '物流单号',
`user_id` varchar(50) COLLATE utf8_bin NOT NULL COMMENT '用户id',
`buyer_message` varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '买家留言',
`buyer_nick` varchar(50) COLLATE utf8_bin NOT NULL COMMENT '买家昵称',
`buyer_rate` tinyint(1) DEFAULT NULL COMMENT '买家是否已经评价,0未评价,1已评价',
`receiver_state` varchar(100) COLLATE utf8_bin DEFAULT '' COMMENT '收获地址(省)',
`receiver_city` varchar(255) COLLATE utf8_bin DEFAULT '' COMMENT '收获地址(市)',
`receiver_district` varchar(255) COLLATE utf8_bin DEFAULT '' COMMENT '收获地址(区/县)',
`receiver_address` varchar(255) COLLATE utf8_bin DEFAULT '' COMMENT '收获地址(街道、住址等详细地址)',
`receiver_mobile` varchar(12) COLLATE utf8_bin DEFAULT NULL COMMENT '收货人手机',
`receiver_zip` varchar(15) COLLATE utf8_bin DEFAULT NULL COMMENT '收货人邮编',
`receiver` varchar(50) COLLATE utf8_bin DEFAULT NULL COMMENT '收货人',
`invoice_type` int(1) DEFAULT '0' COMMENT '发票类型(0无发票1普通发票,2电子发票,3增值税发票)',
`source_type` int(1) DEFAULT '2' COMMENT '订单来源:1:app端,2:pc端,3:M端,4:微信端,5:手机qq端',
PRIMARY KEY (`order_id`),
KEY `create_time` (`create_time`),
KEY `buyer_nick` (`buyer_nick`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
创建订单详情表:
CREATE TABLE `tb_order_detail` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '订单详情id ',
`order_id` bigint(20) NOT NULL COMMENT '订单id',
`sku_id` bigint(20) NOT NULL COMMENT 'sku商品id',
`num` int(11) NOT NULL COMMENT '购买数量',
`title` varchar(200) NOT NULL COMMENT '商品标题',
`own_spec` varchar(1000) DEFAULT '' COMMENT '商品动态属性键值集',
`price` bigint(20) NOT NULL COMMENT '价格,单位:分',
`image` varchar(200) DEFAULT '' COMMENT '商品图片',
PRIMARY KEY (`id`),
KEY `key_order_id` (`order_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8 COMMENT='订单详情表';
为了完整性,决定还是全部贴出来。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.5.5version>
<relativePath/>
parent>
<groupId>com.examplegroupId>
<artifactId>springBoot-easyExcelartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>springBoot-easyExcelname>
<description>springBoot-easyExceldescription>
<properties>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<scope>runtimescope>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.5.1version>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-generatorartifactId>
<version>3.5.1version>
dependency>
<dependency>
<groupId>org.freemarkergroupId>
<artifactId>freemarkerartifactId>
<version>2.3.31version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druid-spring-boot-starterartifactId>
<version>1.2.8version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>easyexcelartifactId>
<version>3.0.5version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.2.80version>
dependency>
<dependency>
<groupId>com.github.xiaoymingroupId>
<artifactId>knife4j-spring-boot-starterartifactId>
<version>2.0.9version>
dependency>
<dependency>
<groupId>cn.hutoolgroupId>
<artifactId>hutool-allartifactId>
<version>5.7.22version>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-collections4artifactId>
<version>4.4version>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<version>2.5.5version>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
exclude>
excludes>
configuration>
plugin>
plugins>
build>
project>
文档配置类:Knife4jConfiguration.java
package cn.com.easyExcel.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
@Configuration
@EnableSwagger2WebMvc
public class Knife4jConfiguration {
@Bean(value = "createRestFulApi")
public Docket createRestFulApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(new ApiInfoBuilder()
.description(" swagger-bootstrap-ui RestFul APIs")
.version("1.0")
.build())
//分组名称
.groupName("2.X版本")
.select()
//这里指定Controller扫描包路径
.apis(RequestHandlerSelectors.basePackage("cn.com.easyExcel.controller"))
.paths(PathSelectors.any())
.build();
}
}
package cn.com.easyExcel.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("cn.com.ztn.excel.mapper")
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
package cn.com.easyExcel.pojo;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.util.Collections;
public class AutoGenerator {
public static void main(String[] args) {
FastAutoGenerator.create("jdbc:mysql://localhost:3306/test", "root", "root")
.globalConfig(builder -> {
builder.author("") // 设置作者
.enableSwagger() // 开启 swagger 模式
.fileOverride() // 覆盖已生成文件
.outputDir("D://autoGenerator"); // 指定输出目录
})
.packageConfig(builder -> {
builder.parent("cn.com") // 设置父包名
.moduleName("easyExcel") // 设置父包模块名
.pathInfo(Collections.singletonMap(OutputFile.mapperXml, "D://autoGenerator/xml")); // 设置mapperXml生成路径
})
.strategyConfig(builder -> {
builder.addInclude("tb_order", "tb_order_detail") // 设置需要生成的表名
.addTablePrefix("tb_", "t_"); // 设置过滤表前缀
})
.templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
.execute();
}
}
Order.java,包含 easyExcel 注解
package cn.com.easyExcel.pojo;
import cn.com.easyExcel.excel.converter.BuyerRateConverter;
import cn.com.easyExcel.excel.converter.InvoiceTypeConverter;
import cn.com.easyExcel.excel.converter.PaymentTypeConverter;
import cn.com.easyExcel.excel.converter.SourceTypeConverter;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@TableName("tb_order")
@ApiModel(value = "Order", description = "Order对象")
public class Order implements Serializable {
private static final long serialVersionUID = -3009679794631979306L;
@ExcelIgnore
@ApiModelProperty("订单id")
@TableId(value = "order_id", type = IdType.AUTO)
private Long orderId;
@ApiModelProperty("总金额,单位为分")
@ColumnWidth(18)
@ExcelProperty(value = "总金额", index = 0)
private Long totalPay;
@ApiModelProperty("实付金额。单位:分。如:20007,表示:200元7分")
@ColumnWidth(18)
@ExcelProperty(value = "实付金额", index = 1)
private Long actualPay;
@ApiModelProperty("支付类型,1、在线支付,2、货到付款")
@ColumnWidth(22)
@ExcelProperty(value = "支付类型", index = 2, converter = PaymentTypeConverter.class)
private Boolean paymentType;
@ApiModelProperty("邮费。单位:分。如:20007,表示:200元7分")
@ColumnWidth(18)
@ExcelProperty(value = "邮费", index = 3)
private Long postFee;
@ApiModelProperty("订单创建时间")
@ColumnWidth(22)
@ExcelProperty(value = "订单创建时间", index = 4)
private LocalDateTime createTime;
@ApiModelProperty("物流名称")
@ColumnWidth(24)
@ExcelProperty(value = "物流名称", index = 5)
private String shippingName;
@ApiModelProperty("物流单号")
@ColumnWidth(24)
@ExcelProperty(value = "物流单号", index = 6)
private String shippingCode;
@ApiModelProperty("用户id")
@ExcelIgnore
private String userId;
@ApiModelProperty("买家留言")
@ColumnWidth(30)
@ExcelProperty(value = "买家留言", index = 7)
private String buyerMessage;
@ApiModelProperty("买家昵称")
@ColumnWidth(20)
@ExcelProperty(value = "买家昵称", index = 8)
private String buyerNick;
@ApiModelProperty("买家是否已经评价,0未评价,1已评价")
@ColumnWidth(22)
@ExcelProperty(value = "买家是否已经评价", index = 9, converter = BuyerRateConverter.class)
private Boolean buyerRate;
@ApiModelProperty("收获地址(省)")
@ColumnWidth(16)
@ExcelProperty(value = "省", index = 10)
private String receiverState;
@ApiModelProperty("收获地址(市)")
@ColumnWidth(16)
@ExcelProperty(value = "市", index = 11)
private String receiverCity;
@ApiModelProperty("收获地址(区/县)")
@ColumnWidth(16)
@ExcelProperty(value = "县", index = 12)
private String receiverDistrict;
@ApiModelProperty("收获地址(街道、住址等详细地址)")
@ColumnWidth(32)
@ExcelProperty(value = "街道、住址等详细地址", index = 13)
private String receiverAddress;
@ApiModelProperty("收货人手机")
@ColumnWidth(22)
@ExcelProperty(value = "手机号码", index = 14)
private String receiverMobile;
@ApiModelProperty("收货人邮编")
@ColumnWidth(20)
@ExcelProperty(value = "邮编", index = 15)
private String receiverZip;
@ApiModelProperty("收货人")
@ColumnWidth(20)
@ExcelProperty(value = "收货人", index = 16)
private String receiver;
@ApiModelProperty("发票类型(0无发票1普通发票,2电子发票,3增值税发票)")
@ColumnWidth(22)
@ExcelProperty(value = "发票类型", index = 17, converter = InvoiceTypeConverter.class)
private Integer invoiceType;
@ApiModelProperty("订单来源:1:app端,2:pc端,3:M端,4:微信端,5:手机qq端")
@ColumnWidth(20)
@ExcelProperty(value = "订单来源", index = 18, converter = SourceTypeConverter.class)
private Integer sourceType;
}
OrderDetail.java
package cn.com.easyExcel.pojo;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@TableName("tb_order_detail")
@ApiModel(value = "OrderDetail", description = "订单详情表")
public class OrderDetail implements Serializable {
private static final long serialVersionUID = 7472956543906342272L;
@ExcelIgnore
@ApiModelProperty("订单详情id ")
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@ApiModelProperty("订单id")
@ColumnWidth(22)
@ExcelProperty(value = "订单id", index = 0)
private Long orderId;
@ApiModelProperty("sku商品id")
@ColumnWidth(20)
@ExcelProperty(value = "sku商品id", index = 1)
private Long skuId;
@ApiModelProperty("购买数量")
@ColumnWidth(18)
@ExcelProperty(value = "购买数量", index = 2)
private Integer num;
@ApiModelProperty("商品标题")
@ColumnWidth(24)
@ExcelProperty(value = "商品标题", index = 3)
private String title;
@ApiModelProperty("商品动态属性键值集")
@ExcelIgnore
private String ownSpec;
@ApiModelProperty("价格,单位:分")
@ColumnWidth(20)
@ExcelProperty(value = "价格", index = 4)
private Long price;
@ApiModelProperty("商品图片")
@ExcelIgnore
private String image;
}
OrderImage.java
package cn.com.easyExcel.pojo;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ApiModel(value = "OrderImage", description = "订单图片")
public class OrderImage {
@ColumnWidth(56)
@ExcelProperty(value = "图片", index = 0)
@ApiModelProperty("图片")
private String image;
}
BuyerRateEnum.java
package cn.com.easyExcel.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.fasterxml.jackson.annotation.JsonValue;
public enum BuyerRateEnum {
ONLINE(Boolean.TRUE, "未评价"),
OFFLINE(Boolean.FALSE, "已评价");
@EnumValue
private Boolean key;
@JsonValue
private String value;
BuyerRateEnum(Boolean key, String value) {
this.key = key;
this.value = value;
}
public Boolean getKey() {
return key;
}
public String getValue() {
return value;
}
}
InvoiceTypeEnum.java
package cn.com.easyExcel.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.fasterxml.jackson.annotation.JsonValue;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public enum InvoiceTypeEnum {
NO_INVOICE(0, "无发票"),
NORMAL_INVOICE(1, "普通发票"),
ELECTRON_INVOICE(2, "电子发票"),
VAT_INVOICE(3, "增值税发票");
@EnumValue
private Integer key;
@JsonValue
private String value;
InvoiceTypeEnum(int key, String value) {
this.key = key;
this.value = value;
}
public Integer getKey() {
return key;
}
public String getValue() {
return value;
}
public static Integer getRandomInvoiceType() {
List<Integer> invoiceKeys = Arrays.stream(InvoiceTypeEnum.values())//
.map(InvoiceTypeEnum::getKey)//
.collect(Collectors.toList());
int index = (int) (Math.random() * invoiceKeys.size());
return invoiceKeys.get(index);
}
}
PaymentTypeEnum.java
package cn.com.easyExcel.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.fasterxml.jackson.annotation.JsonValue;
public enum PaymentTypeEnum {
ONLINE(Boolean.TRUE, "在线支付"),
OFFLINE(Boolean.FALSE, "货到付款");
@EnumValue
private Boolean key;
@JsonValue
private String value;
PaymentTypeEnum(Boolean key, String value) {
this.key = key;
this.value = value;
}
public Boolean getKey() {
return key;
}
public String getValue() {
return value;
}
}
SourceTypeEnum.java
package cn.com.easyExcel.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.fasterxml.jackson.annotation.JsonValue;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public enum SourceTypeEnum {
APP(0, "app端"),
PC(1, "pc端"),
M(2, "M端"),
WX(3, "微信端"),
QQ(4, "手机QQ端");
@EnumValue
private Integer key;
@JsonValue
private String value;
SourceTypeEnum(Integer key, String value) {
this.key = key;
this.value = value;
}
public Integer getKey() {
return key;
}
public String getValue() {
return value;
}
public static Integer getRandomSourceType() {
List<Integer> sourceKeys = Arrays.stream(SourceTypeEnum.values())//
.map(SourceTypeEnum::getKey)//
.collect(Collectors.toList());
int index = (int) (Math.random() * sourceKeys.size());
return sourceKeys.get(index);
}
}
OrderController.java
package cn.com.easyExcel.controller;
import cn.com.easyExcel.param.OrderExportParam;
import cn.com.easyExcel.service.OrderService;
import cn.com.easyExcel.vo.ResultVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
@Api(tags = "订单表")
@RestController
@RequestMapping(value = "/order")
public class OrderController {
@Autowired
private OrderService orderService;
@ApiOperation(value = "初始化订单数据")
@GetMapping("/initOrderData")
public ResultVo initOrderData(){
orderService.initOrderData();
return ResultVo.success();
}
@ApiOperation(value = "多sheet导出")
@PostMapping("/excel/moreSheetExport")
public void moreSheetExport(HttpServletResponse response, OrderExportParam param){
orderService.moreSheetExport(response, param);
}
}
ResultVo.java
package cn.com.easyExcel.vo;
import lombok.Data;
@Data
public class ResultVo<T> {
private static final String SUCCESS_CODE = "S10000";
private static final String UNKNOWN_FAIL_CODE = "E10001";
private T data;
private String code;
private String message;
private boolean success;
public ResultVo() {
}
public ResultVo(boolean success, String code) {
this.success = success;
this.code = code;
}
public ResultVo(T data, boolean success, String code, String message) {
this.data = data;
this.success = success;
this.code = code;
this.message = message;
}
public static ResultVo<Void> success() {
return success(null, (String)null);
}
public static <R> ResultVo<R> success(R data) {
return success(data, (String)null);
}
public static <R> ResultVo<R> success(R data, String message) {
return new ResultVo(data, true, SUCCESS_CODE, message);
}
public static ResultVo<Void> successMsg(String message) {
return success(null, message);
}
public static <R> ResultVo<R> failure(String code) {
return failure(code, (String)null);
}
public static <R> ResultVo<R> failure(String code, String message) {
return failure(null, code, message);
}
public static <R> ResultVo<R> failure(R data, String code, String message) {
return new ResultVo(data, false, code, message);
}
public static <R> ResultVo<R> failureMsg(String message) {
return failure(UNKNOWN_FAIL_CODE, message);
}
}
OrderService.java
package cn.com.easyExcel.service;
import cn.com.easyExcel.param.OrderExportParam;
import javax.servlet.http.HttpServletResponse;
public interface OrderService {
/**
* 初始化订单数据
*/
void initOrderData();
/**
* 多 sheet 导出
*/
void moreSheetExport(HttpServletResponse response, OrderExportParam param);
}
package cn.com.easyExcel.service.impl;
import cn.com.easyExcel.enums.InvoiceTypeEnum;
import cn.com.easyExcel.enums.SourceTypeEnum;
import cn.com.easyExcel.excel.listener.ExportListener;
import cn.com.easyExcel.mapper.OrderDetailMapper;
import cn.com.easyExcel.mapper.OrderMapper;
import cn.com.easyExcel.param.OrderExportParam;
import cn.com.easyExcel.pojo.Order;
import cn.com.easyExcel.pojo.OrderDetail;
import cn.com.easyExcel.pojo.OrderImage;
import cn.com.easyExcel.service.OrderService;
import cn.com.easyExcel.util.InitDataUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.SneakyThrows;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private OrderDetailMapper orderDetailMapper;
private static final int PAGE_SIZE = 100;
private static final String PATTERN = "yyyy-MM-dd-HH-mm-ss";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(PATTERN);
private static final String CHARACTER_UTF_8 = "UTF-8";
private static final String ORDER_INFO = "订单信息";
@Override
public void initOrderData() {
for (int i = 1; i <= 280; i++) {
Order order = Order.builder()
// .orderId((long) i)
.totalPay(2000L) //单位:分
.actualPay(2000L)
.paymentType(InitDataUtil.getBoolean())
.postFee(1000L)
.createTime(LocalDateTime.now())
.shippingName(InitDataUtil.getShippingName())
.shippingCode(InitDataUtil.getShippingCode())
.userId(InitDataUtil.getShippingCode())
.buyerMessage("质量不错,买的很划算")
.buyerNick(InitDataUtil.getReceiver())
.buyerRate(InitDataUtil.getBoolean())
.receiverState(InitDataUtil.getReceiverState())
.receiverCity("华夏国泰民安市")
.receiverAddress("华夏国泰民安街道")
.receiverMobile(InitDataUtil.getMobile())
.receiver(InitDataUtil.getReceiver())
.invoiceType(InvoiceTypeEnum.getRandomInvoiceType())
.sourceType(SourceTypeEnum.getRandomSourceType())
.build();
orderMapper.insert(order);
OrderDetail orderDetail = OrderDetail.builder()
.orderId(order.getOrderId())
.skuId(33L)
.num(10)
.title(InitDataUtil.getTitle())
.price(3000L)
.image(InitDataUtil.getImage())
.build();
orderDetailMapper.insert(orderDetail);
}
}
@SneakyThrows
@Override
public void moreSheetExport(HttpServletResponse response, OrderExportParam param) {
LambdaQueryWrapper<Order> queryWrapper = Wrappers.lambdaQuery();
//TODO:用queryWrapper组装前端传递的参数省略
moreSheetExport(response, ORDER_INFO, queryWrapper);
}
/**
* 多sheet导出
*/
public void moreSheetExport(HttpServletResponse response, String sheetName,
LambdaQueryWrapper<Order> queryWrapper) throws IOException {
ServletOutputStream out = ExportListener.getServletOutputStream(response, sheetName);
ExcelWriter excelWriter = EasyExcel.write(out).build();
String nowTime = dtf.format(LocalDateTime.now());
int startIndex = 1;
while (true){
int startParam =(startIndex - 1) * PAGE_SIZE;
int pageIndex = (int) Math.ceil((double) startParam / (double) PAGE_SIZE+1);
Page<Order> pageQuery = new Page<>(pageIndex, PAGE_SIZE, false);
Page<Order> orderListByPage = orderMapper.selectPage(pageQuery, queryWrapper);
List<Order> orderList = orderListByPage.getRecords();
if (CollectionUtils.isEmpty(orderList)) {
break;
}
WriteSheet orderSheet = EasyExcel.writerSheet(0, "订单信息").head(Order.class).build();
excelWriter.write(orderList, orderSheet);
LambdaQueryWrapper<OrderDetail> detailWrapper = Wrappers.lambdaQuery();
List<Long> orderIds = orderList.stream().map(Order::getOrderId).collect(Collectors.toList());
detailWrapper.in(OrderDetail::getOrderId, orderIds);
List<OrderDetail> orderDetailList = orderDetailMapper.selectList(detailWrapper); //查询详情
WriteSheet detailSheet = EasyExcel.writerSheet(1, "订单详情").head(OrderDetail.class).build();
excelWriter.write(orderDetailList, detailSheet);
List<String> imageList = orderDetailList.stream().map(OrderDetail::getImage).collect(Collectors.toList());
List<OrderImage> orderImageList = new ArrayList<>();
for (String image : imageList) {
OrderImage orderImage = OrderImage.builder().image(image).build();
orderImageList.add(orderImage);
}
WriteSheet imageSheet = EasyExcel.writerSheet(2, "订单图片").head(OrderImage.class).build();
excelWriter.write(orderImageList, imageSheet);
if(CollectionUtils.isNotEmpty(imageList)){
for(String image : imageList){
downloadFile(image, "D:\\ORDER-" + nowTime);
}
}
startIndex++;
}
// 千万别忘记finish 会帮忙关闭流
excelWriter.finish();
}
public static void downloadFile(String urlStr, String savePath) throws IOException {
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// 设置超时间为3秒
conn.setConnectTimeout(3 * 1000);
// 防止屏蔽程序抓取而返回:403
conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
// 得到输入流
InputStream inputStream = conn.getInputStream();
String headerField = conn.getHeaderField("Content-Disposition");
String realFileName = headerField.split(";")[2].split("=")[1];
String fileName = URLDecoder.decode(realFileName, CHARACTER_UTF_8);
// 获取字节数组
byte[] getData = readInputStream(inputStream);
// 文件保存位置
File saveDir = new File(savePath);
if (!saveDir.exists()) {
saveDir.mkdir();
}
File file = new File(saveDir + File.separator + fileName);
FileOutputStream fos = new FileOutputStream(file);
fos.write(getData);
fos.close();
inputStream.close();
}
public static byte[] readInputStream(InputStream inputStream) throws IOException {
byte[] buffer = new byte[1024];
int len = 0;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while ((len = inputStream.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
bos.close();
return bos.toByteArray();
}
}
导出监听器:ExportListener.java,在前面的好几篇关于 easyExcel 的文章已经分享过,详情请移步 EasyExcel3.0.5 加快大数据查询速度,查询性能优化。
初始化数据:InitDataUtil.java
package cn.com.easyExcel.util;
import java.util.UUID;
public class InitDataUtil {
public static Boolean getBoolean(){
Boolean[] doc = {Boolean.TRUE, Boolean.FALSE};
int index = (int) (Math.random() * doc.length);
return doc[index];
}
public static String getShippingName(){
String[] doc = {"顺丰物流", "中通物流", "韵达物流", "百世通", "云途物流"};
int index = (int) (Math.random() * doc.length);
return doc[index];
}
public static String getReceiverState(){
String[] doc = {"北京", "上海", "广东省", "河北省", "河南省", "湖南省", "湖北省", "江西省", "福建省"};
int index = (int) (Math.random() * doc.length);
return doc[index];
}
public static String getShippingCode(){
//随机生成一位整数
int random = (int) (Math.random()*9+1);
String valueOf = String.valueOf(random);
//生成uuid的hashCode值
int hashCode = UUID.randomUUID().toString().hashCode();
//可能为负数
if(hashCode<0){
hashCode = -hashCode;
}
return valueOf + String.format("%015d", hashCode);
}
public static String getMobile() {
//给予真实的初始号段,号段是在百度上面查找的真实号段
String[] start = {"133", "149", "153", "173", "177",
"180", "181", "189", "199", "130", "131", "132",
"145", "155", "156", "166", "171", "175", "176", "185", "186", "166", "134", "135",
"136", "137", "138", "139", "147", "150", "151", "152", "157", "158", "159", "172",
"178", "182", "183", "184", "187", "188", "198", "170", "171"};
String phoneFirstNum = start[(int) (Math.random() * start.length)];
String phoneLastNum = "";
//定义尾号,尾号是8位
final int LENPHONE = 8;
//循环剩下的位数
for (int i = 0; i < LENPHONE; i++) {
//每次循环都从0~9挑选一个随机数
phoneLastNum += (int) (Math.random() * 10);
}
//最终将号段和尾数连接起来
return phoneFirstNum + phoneLastNum;
}
public static String getReceiver(){
String[] doc = {"朝歌晚酒", "都怪时光太动听", "笑我孤陋", "水墨青花","时光清浅", "草帽撸夫", "江山如画",
"热度不够", "盏茶浅抿", "把酒临风", "且听风吟", "梦忆笙歌", "倾城月下", "清风墨竹", "自愈心暖", "几许轻唱",
"平凡之路", "半夏倾城", "南栀倾寒", "孤君独战", "温酒杯暖", "眉目亦如画", "旧雪烹茶", "律断华章", "清酒暖风",
"清羽墨安", "一夕夙愿", "南顾春衫", "和云相伴", "夕颜若雪", "时城旧巷", "梦屿千寻", "故港笑别", "水袖萦香",
"秋水墨凉", "海棠花瘦", "千城暮雪", "华灯初上", "一纸枕书", "剑断青丝", "风烟影月", "日月星辰", "浅喜深爱"};
int index = (int) (Math.random() * doc.length);
return doc[index];
}
public static String getTitle(){
String[] doc = {"手机", "小家电", "白色家电", "饮料食品","办公用品", "户外运动", "美妆护肤", "母婴"};
int index = (int) (Math.random() * doc.length);
return doc[index];
}
//图片上传到 OSS 返回的路径
public static String getImage(){
String[] doc = {"https://yunexpress-fileupload.oss-cn-shenzhen.aliyuncs.com/day1/file/19236f66ba0b4a08988961ec15c6047f",
"https://yunexpress-fileupload.oss-cn-shenzhen.aliyuncs.com/day1/file/4e2a64bb97f8439b8d5cde57b3337aea",
"https://yunexpress-fileupload.oss-cn-shenzhen.aliyuncs.com/day1/file/54737626a07d4147ab1fcb8beac7eaa8",
"https://yunexpress-fileupload.oss-cn-shenzhen.aliyuncs.com/day1/file/1f1b064497914a16b847801c13890a28",
"https://yunexpress-fileupload.oss-cn-shenzhen.aliyuncs.com/day1/file/af7f868044634ddabc52da7e6778eb36",
"https://yunexpress-fileupload.oss-cn-shenzhen.aliyuncs.com/day1/file/15eb6eaa6241402eb79ee9b938cdea31",
"https://yunexpress-fileupload.oss-cn-shenzhen.aliyuncs.com/day1/file/56ef58f283f34c5e986101c9ca091cef"};
int index = (int) (Math.random() * doc.length);
return doc[index];
}
}
OrderMapper.java
package cn.com.easyExcel.mapper;
import cn.com.easyExcel.pojo.Order;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface OrderMapper extends BaseMapper<Order> {
}
OrderDetailMapper.java
package cn.com.easyExcel.mapper;
import cn.com.easyExcel.pojo.OrderDetail;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface OrderDetailMapper extends BaseMapper<OrderDetail> {
}
mapper.xml 没有写任何代码,mybatis-plus 的方便强大之处。
好了,费了很大功夫才实现,觉得有用,欢迎留言点赞。