小型java easy Excel导出工具类(可拓展) jdk8函数式接口
首先需求是前端传入对象list,指定后端配置的Excel导出实体类package地址(根据需求可脱离前端根据业务需求定义接口直接调工具类方法即可,传参数方式由指向地址改为Excel导出实体类Class对象)并且以application/vnd.ms-excel类型的回执返回给前端download(实现逻辑简单不喜勿喷,希望得到各路神仙🐮的指点OwO)。讲一下实现思路首先后端拿到list和实体类映射地址或者类Class定义文件输出流定义两个方法一个作为创建列头和数据,另一个作为导出操作(这一步操作是由Lambda表达式写入提交)直接写入到流中返回给前端。
1.引入maven poi依赖以及其他应用到的依赖
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2.结构目录
annotations:字段型自定义注解(列头/日期格式/字典式数字替换文字/列头宽度……后期拓展字段交给你们OwO🐮)
as:函数接口/自定义接口/定义接口实现
entity:Excel导出行数据转换实体
model:Excel导出实体类
uitls:Excel导出工具类
3.定义字段型注解(解释都在注释里了)
package 这个你们放你们自己的包吧;
import java.lang.annotation.*;
@Documented
@Target({ElementType.FIELD}) //注解应用类型(应用到方法的注解,还有类的可以自己试试)
@Retention(RetentionPolicy.RUNTIME) // 注解的类型
public @interface Excel {
/**
* Excel列头
**/
String name() default "";
/**
* 日期格式转换
**/
String format() default "yyyy/MM/dd";
/** 文字替换根据 ":" 提供两种方式如下
* 1.普通数组替换: {"文本1:文本2",……}
* 2.反射方法替换: "${无参数方法返回值类型为List<Object>}"
* 且方法必须在同一实体类
**/
String[] filterText() default {};
/**
* 列头宽度
**/
int width() default 30;
/**
* 函数配置
**/
String func() default "";
}
4.自定义一个消费型函数式接口
这里着重讲一下含义所谓消费,其实就是将数据提交到接口里由方法重写由Lambda表达式的方式处理数据优化代码避免性能浪费
package 这个你们放你们自己的包吧;
/** 有且只有一个的函数式接口,称之为函数接口,接口可以包含其他方法(静态和默认以及私有)
* @Author du_zy
* @Description //TODO
* @Date 3:18 PM 2022/3/8
**/
@FunctionalInterface
public interface ExportConsumer<ByteArrayOutputStream, Workbook, List>{
/** 自定义导出数据拼装
* @Author du_zy
* @Description //TODO
* @Date 2:46 PM 2022/3/8
* @Param [fileOut, wk, list]
* fileOut文件输出流最后是将文件写入到这个里传给前端的,wk是poi处理Excel样式以及数据的APi里面有很多强大的功能可以参考官方有兴趣可以看看,list是前端传入的数据
* @return void
**/
public abstract void accept(ByteArrayOutputStream fileOut, Workbook wk, List list) throws Exception;
}
5.定义数据转换类实体
这里是对list的属性的一些定义因为要对list里的数据标记那些要日期格式化那些要文字替换下文在注释里有详解
package 这个你们放你们自己的包吧;
/**
* @ClassName FieldExcel
* @Description TODO
* @Author du_zy
* @Date 2022/3/11 10:09 AM
* @Version 1.0
**/
public class FieldExcel {
private String[] fieldArr;
private String fieldName;
private String fieldType;
private String fieldFormat;
public String[] getFieldArr() {
return fieldArr;
}
public void setFieldArr(String[] fieldArr) {
this.fieldArr = fieldArr;
}
public String getFieldName() {
return fieldName;
}
public void setFieldName(String fieldName) {
this.fieldName = fieldName;
}
public String getFieldType() {
return fieldType;
}
public void setFieldType(String fieldType) {
this.fieldType = fieldType;
}
public String getFieldFormat() {
return fieldFormat;
}
public void setFieldFormat(String fieldFormat) {
this.fieldFormat = fieldFormat;
}
public FieldExcel() {
this.fieldArr = new String[]{};
this.fieldName = "null_flag";
}
}
6.导出列头实体类(这个类里的属性根据业务需求制作)
主要需要看Excel注解
package 这个你们放你们自己的包吧;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import 这个你们放你们自己的包吧.CfmRepairCodeEnum;
import 这个你们放你们自己的包吧.annotations.Excel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 实体类
* @author du
* @since 2021-12-07 15:23:53
*/
@Data
@EqualsAndHashCode(callSuper = false)
@NoArgsConstructor
@AllArgsConstructor
@Component
public class FitMentExcelModel implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 装店装修业务单主键id
*/
private Long cfmRepairId;
/**
* 装店装修单R单单号
*/
@Excel(name = "装店装修单R单单号")
private String cfmRepairCode;
/**
* 申请日期
*/
@Excel(name = "申请日期")
private LocalDateTime applyTime;
/**
* 申请人
*/
@Excel(name = "申请人")
private String applyName;
/**
* 申请人电话
*/
@Excel(name = "申请人电话")
private String applyMobile;
/**
* 城市经理名称
*/
@Excel(name = "城市经理名称")
private String cityManager;
/**
* 城市经理电话
*/
@Excel(name = "城市经理电话")
private String cityManagerPhone;
/**
* 装修负责人
*/
@Excel(name = "装修负责人")
private String repairLeader;
/**
* 负责人电话
*/
@Excel(name = "负责人电话")
private String leaderPhone;
/**
* 省份
*/
@Excel(name = "省份")
private String province;
/**
* 城市
*/
@Excel(name = "城市")
private String city;
/**
* 区
*/
@Excel(name = "区")
private String area;
/**
* 店面名称
*/
@Excel(name = "店面名称")
private String storeName;
/**
* 店面类别
*/
@Excel(name = "店面类别")
private String storeType;
/**
* 店面类型
*/
@Excel(name = "店面类型")
private String storeCategory;
/**
* 店面性质
*/
@Excel(name = "店面性质")
private String storeProperty;
/**
* 店面面积
*/
@Excel(name = "店面面积")
private BigDecimal storeArea;
/**
* 店面所属商圈
*/
@Excel(name = "店面所属商圈")
private String storeBusinessArea;
/**
* 地级/县级
*/
@Excel(name = "地级/县级", filterText = {"1:地级", "2:县级"})
private String cityLevel;
/**
* 老店历史装修时间
*/
@Excel(name = "老店历史装修时间")
private LocalDate decorateDate;
/**
* 装修性质
*/
@Excel(name = "装修性质")
private String repairLevelName;
/**
* 装修模式
*/
@Excel(name = "装修模式")
private String repairModelName;
/**
* 预计开业时间
*/
@Excel(name = "预计开业时间")
private LocalDate openDate;
/**
* 店面专区备注
*/
@Excel(name = "店面专区备注")
private String storeTeamRemark;
/**
* 店面专区面积
*/
@Excel(name = "店面专区面积")
private BigDecimal storeTeamArea;
/**
* 开始设计时间
*/
@Excel(name = "开始设计时间")
private LocalDate designingDate;
/**
* 设计完成时间
*/
@Excel(name = "设计完成时间")
private LocalDate designFinishDate;
/**
* 设计周期
*/
@Excel(name = "设计周期")
private Integer designCycle;
/**
* 铺地砖日期
*/
@Excel(name = "铺地砖日期")
private LocalDate brickDate;
/**
* 木工日期
*/
@Excel(name = "木工日期")
private LocalDate woodDate;
/**
* 油工日期
*/
@Excel(name = "油工日期")
private LocalDate oilDate;
/**
* 安装样品日期
*/
@Excel(name = "安装样品日期")
private LocalDate installDate;
/**
* 软装摆场日期
*/
@Excel(name = "软装摆场日期")
private LocalDate softDate;
/**
* 暂不装修时间
*/
@Excel(name = "暂不装修时间")
private LocalDate notRepairDate;
/**
* 暂不装修原因
*/
@Excel(name = "暂不装修原因")
private String notRepairReason;
/**
* 不装修时间
*/
@Excel(name = "不装修时间")
private LocalDate noRepairDate;
/**
* 不装修原因
*/
@Excel(name = "不装修原因")
private String noRepairReason;
/**
* 装修完成时间
*/
@Excel(name = "装修完成时间")
private LocalDate repairFinishDate;
/**
* 装修周期
*/
@Excel(name = "装修周期")
private Integer repairCycle;
/**
* 验收完成时间
*/
@Excel(name = "验收完成时间")
private LocalDate checkDate;
/**
* 验收周期
*/
@Excel(name = "验收周期")
private Integer checkCycle;
/**
* 验收状态 0:不合格 1:合格 2:无验收
*/
@Excel(name = "验收状态", filterText = {"0:不合格", "1:合格", "2:无验收"})
private Integer checkState;
/**
* 装修单状态
*/
@Excel(name = "装修单状态", filterText = "${getEnumRepairSate}")
private Integer repairState;
@Excel(name = "状态")
private String state;
/**
* 支付时间
*/
@Excel(name = "支付时间")
private LocalDateTime payTime;
/**
* 支付单号
*/
@Excel(name = "支付单号")
private String cfmPayCode;
/**
* 设计费金额(分)
*/
@Excel(name = "设计费金额(分)")
private Long sumDesignCost;
/**
* 支付方式
*/
@Excel(name = "支付方式")
private String payMethod;
/**
* 评价状态 0:未评价 1:已评价
*/
@Excel(name = "评价状态", filterText = {"0:未评价", "1:已评价"})
private Integer evaluateState;
/**
* 评价信息 图纸设计
*/
@Excel(name = "评价信息-图纸设计")
private BigDecimal evaluateDesign;
/**
* 评价信息 装修效果
*/
@Excel(name = "评价信息-装修效果")
private BigDecimal evaluateRepair;
/**
* 评价信息 服务沟通
*/
@Excel(name = "评价信息-服务沟通")
private BigDecimal evaluateCommunication;
/**
* 评价内容
*/
@Excel(name = "评价内容")
private String evaluateContent;
/**
* 设计师负责人名称
*/
@Excel(name = "设计师负责人名称")
private String responseName;
/**
* 设计师名称
*/
@Excel(name = "设计师名称")
private String designName;
/**
* 表单备注
*/
@Excel(name = "表单备注")
private String formRemark;
/**
* 备注
*/
@Excel(name = "备注")
private String remark;
/**
* 关联店面id
*/
private String storeId;
/**
* 店面编码
*/
private String storeCode;
/**
* 申请人id
*/
private Long applyId;
/**将一串key-value数据转换成key:value数据并返回成list
* @Author du_zy
* @Description //TODO
* @Date 4:12 PM 2022/3/23
* @Param []
* @return java.util.List<java.lang.Object>
**/
@Bean
public List<Object> getEnumRepairSate() {
List<Object> resultList = new ArrayList<>();
for (Map.Entry<String, Object> stringObjectEntry : CfmRepairCodeEnum.getEnum().entrySet()) {
JSONObject j = JSONObject.parseObject(JSON.toJSONString(stringObjectEntry.getValue()));
resultList.add(j.get("code") + ":" + j.get("msg"));
}
return resultList;
}
/**
* 装修性质code
*/
private String repairLevelCode;
/**
* 联系电话
*/
private String mobile;
/**
* 省份编码
*/
private String provinceCode;
/**
* 城市编码
*/
private String cityCode;
/**
* 区编码
*/
private String areaCode;
/**
* 装修模式code
*/
private String repairModelCode;
/**
* 设计费单价(分)
*/
private Long designCost;
/**
* 设计部数据员id
*/
private Long dataId;
/**
* 设计部数据员名称
*/
private String dataName;
/**
* 设计师负责人id
*/
private Long responseId;
/**
* 设计师id
*/
private Long designId;
/**
* 验收图片 0:未上传 1:已上传
*/
private Integer checkPhotoState;
/**
* 关闭时间
*/
private LocalDateTime closeTime;
/**
* 是否删除(0:未删除、1:删除)
*/
private String delFg;
/**
* 创建人
*/
private String createBy;
/**
* 创建人编码
*/
private String createCode;
/**
* 创建时间
*/
private LocalDateTime createDt;
/**
* 更新人
*/
private String updateBy;
/**
* 更新人编码
*/
private String updateCode;
/**
* 更新时间
*/
private LocalDateTime updateDt;
/**
* 时间戳
*/
private Long timeStamp;
}
7.导出工具类(创建列头和数据以及提交写入流方法)都在注释里了
package 这个你们放你们自己的包吧;
import com.alibaba.fastjson.JSONObject;
import 这个你们放你们自己的包吧;
import 这个你们放你们自己的包吧;
import 这个你们放你们自己的包吧;
import 这个你们放你们自己的包吧;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.WorkbookUtil;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import java.io.ByteArrayOutputStream;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Pattern;
/**
* @ClassName ExportUtils
* @Description TODO
* @Author du_zy
* @Date 2022/3/8 11:03 AM
* @Version 1.0
**/
public class ExportUtils {
/** 导出Excel
* @Author du_zy
* @Description //TODO
* @Date 3:04 PM 2022/3/8
* @Param [fileOut, wb, listData, fileName, consumer]
* @return org.springframework.http.ResponseEntity<byte[]>
**/
public static <T> ResponseEntity<byte[]> exportExcel(ByteArrayOutputStream fileOut,
Workbook wb,
List<T> listData,
String fileName,
ExportConsumer<ByteArrayOutputStream, Workbook, List<T>> consumer) {
HttpHeaders headers = new HttpHeaders();
try {
consumer.accept(fileOut, wb, listData); // 函数接口数据配置
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); // 配置请求头类型
headers.setContentDispositionFormData("attachment", new String((fileName + ".xlsx").getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1)); //配置表单信息,字符转换
return new ResponseEntity<>(fileOut.toByteArray(), headers, HttpStatus.OK);
} catch (Exception e) {
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
/** 创建标头和数据
* @Author du_zy
* @Description //TODO
* @Date 2:59 PM 2022/3/8
* @Param [wb, data, className]
* @return org.apache.poi.ss.usermodel.Workbook
**/
public static <T> Workbook createCell(Workbook wb, List<T> data, Class<?> className) {
try {
String safeName = WorkbookUtil.createSafeSheetName("sheet1");
Sheet sheet = wb.createSheet(safeName); // 创建工作空间
//第一行标题
Row title = sheet.createRow(0);
List<Map<String, Object>> cols = new LinkedList<>();
for (int i = 0; i < className.getDeclaredFields().length; i++) { // 循环如果反射里的类里有注解name配置就存入到标头list里
boolean is = className.getDeclaredFields()[i].isAnnotationPresent(Excel.class);
if (is) {
Map<String, Object> coverMap = new HashMap<>();
Excel annotation = className.getDeclaredFields()[i].getAnnotation(Excel.class);
coverMap.put("name", annotation.name());
coverMap.put("width", annotation.width());
cols.add(coverMap);
}
}
for (int i = 0; i < cols.size(); i++) { //第一行放标题
title.createCell(i).setCellValue(cols.get(i).get("name").toString());
// sheet.autoSizeColumn(i, true);
sheet.setColumnWidth(i, (int)((Integer.parseInt(cols.get(i).get("width").toString()) + 0.72) * 256));
}
// //如果list里有数组数据,加入到list里
// String dataJson = JSONArray.toJSONString(data);// 先把list转换成json str数组格式
// JSONArray objects = JSONArray.parseArray(dataJson); // 在转成json 数组
// for (Object o : objects) {
// String s = JSONObject.toJSONString(o); //Object 对象转成jsonString
// JSONObject jsonObject = JSONObject.parseObject(s);
// jsonObject.forEach( (key, value) -> {
// if (jsonObject.get(key) instanceof List) { // 如果这一行数据里有list数据,那么循环他并给给他放初始list里一并导出
// JSONArray jsonArray = jsonObject.getJSONArray(key);
// for (Object o1 : jsonArray) {
// data.add((T) o1);
// }
// System.out.println("是list类型");
// } else {
// System.out.println("不是list类型");
// }
// });
// }
// if (1==1) {
// throw new NullPointerException();
// }
Field[] fields = className.getDeclaredFields();// 获取到反射类里所有的属性
Map<Integer, FieldExcel> fieldMap = new HashMap<>(); // integer: 存放的Excel列下标, map:存放的属性名称、类型、日期格式转换
data.forEach( o -> { // 数据拼接
Row row = sheet.createRow(data.indexOf(o) + 1);// 创建一行数据
String s = JSONObject.toJSONString(o); //Object 对象转成jsonString
JSONObject jsonObject = JSONObject.parseObject(s); //jsonString转成JSONObject
int mapIndex = 0; // 定义Excel列下标
for (int i = 0; i < fields.length; i++) {// 循环找出如果有注解配置的字段添加到数组里
boolean is = fields[i].isAnnotationPresent(Excel.class);
if (is) {
Excel annotation = fields[i].getAnnotation(Excel.class); // 获取注解里的属性
fields[i].setAccessible(true); // 设置私有属性可见
FieldExcel fieldExcel = new FieldExcel();
if (!StringUtils.isEmpty(jsonObject.get(fields[i].getName()))) { // 如果反射里的字段可以在传入list里json对象找到就存找的数据,没有存空
if (annotation.filterText().length > 0) { // 如果注解里配置了数组类型属性,将会被替换自负分割0 替换 1
String s1 = annotation.filterText()[0];
if (s1.startsWith("${") && s1.endsWith("}")) {// 用第一个元素做校验
try {
int startIndex = s1.indexOf("${") + 2;
int endIndex = s1.indexOf("}");
String methodName = s1.substring(startIndex, endIndex); // 获取到反射类里的方法名称这个是在注解上定义的名称不包含El表达式的名称
List<String> beanList = SpringUtils.getBean(methodName, List.class); // 获取实体里的list方法方式1:通过spring bean装载方式实现映射方法返回(实体类规范: 1.类必须交给spring管理 2.方法必须加注解Bean(name = "方法名"))
// Method getEnumRepairSate = className.getMethod(methodName); // 获取实体里的list方法方式2: 获取到方法实例通过java反射机制的方式加载射射方法返回
// Object obj = className.newInstance(); // 生成反射加载类实例(调用实体类里带有无参数的构造方法) 从jvm角度看此类必须保证是加载了才能够使用此方法,而new不同new可以不用加载
// List<Object> fieldCoverList = (List<Object>) getEnumRepairSate.invoke(obj); // 指定类实例转List<Object>类型
String[] fieldArr = beanList.toArray(new String[beanList.size()]); // List 转 数组
fieldExcel.setFieldArr(fieldArr);
} catch (Exception e) {
e.printStackTrace();
}
} else {
fieldExcel.setFieldArr(annotation.filterText());
}
}
fieldExcel.setFieldName(fields[i].getName());
if (fields[i].getGenericType().toString().contains("Date")) { //如果属性类型包含Date说明是日期类型放入注解的format的属性
fieldExcel.setFieldFormat(annotation.format());
}
}
fieldExcel.setFieldType(fields[i].getGenericType().toString());
fieldMap.put(mapIndex, fieldExcel);
mapIndex++;
}
}
for (Map.Entry<Integer, FieldExcel> i : fieldMap.entrySet()) { //循环带有注解的字段依次排放数据(在加个循环的原因是:第一次循环有注解的for拼接数据会导致数据顺序错乱,因为注解的顺序不一定每个属性都有)
FieldExcel value = i.getValue();
if (value.getFieldArr().length > 0) {
for (String s1 : value.getFieldArr()) {
String[] split = s1.split(":"); // ":"号分割
if (split[0].equals(jsonObject.get(value.getFieldName()).toString())) { // 0 替换 1
row.createCell(i.getKey()).setCellValue(split[1]);
}
}
} else if (!StringUtils.isEmpty(value.getFieldFormat()) && value.getFieldType().contains("Date")) { // 如果日期格式转换属性不为空并且字段类型包含Date进行格式转换,如果没有就正常赋值
SimpleDateFormat dateFormat = getDateFormat(jsonObject.get(value.getFieldName()).toString()); // 验证日期格式这里做了一个正则日期校验 斜杠和- 任意转换加时间或者不加时间
Date fieldNameDate = null;
try {
fieldNameDate = dateFormat.parse(jsonObject.get(value.getFieldName()).toString());
} catch (ParseException e) {
e.printStackTrace();
}
SimpleDateFormat format = new SimpleDateFormat(value.getFieldFormat()); // 转换成注解定义的格式 yyyy/MM/dd HH:mm:ss yyyy-MM-dd HH:mm:ss ……
String strFieldName = format.format(fieldNameDate);
row.createCell(i.getKey()).setCellValue(strFieldName);
} else {
row.createCell(i.getKey()).setCellValue(value.getFieldName().equals("null_flag") ? "" : jsonObject.get(value.getFieldName()).toString());
}
}
mapIndex = 0;
fieldMap.clear();// 下标清0 map清空 进行下一次循环
});
return wb;
}catch (Exception e) {
e.printStackTrace();
return null;
}
}
private static SimpleDateFormat getDateFormat(String source) {
SimpleDateFormat sdf = new SimpleDateFormat();
sdf.setLenient(false);
if(Pattern.matches("^\\d{4}-\\d{2}-\\d{2}$",source)){
sdf = new SimpleDateFormat("yyyy-MM-dd");
}else if(Pattern.matches("^\\d{4}/\\d{2}/\\d{2}$",source)){
sdf = new SimpleDateFormat("yyyy/MM/dd");
}else if(Pattern.matches("^\\d{4}\\d{2}\\d{2}$",source)){
sdf = new SimpleDateFormat("yyyyMMdd");
}else if(Pattern.matches("^\\d{4}-\\d{2}-\\d{2}\\s\\d{2}:\\d{2}:\\d{2}$",source)) {
sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}else if(Pattern.matches("^\\d{4}/\\d{2}/\\d{2}\\s\\d{2}:\\d{2}:\\d{2}$",source)) {
sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
}else if(Pattern.matches("^\\d{4}\\d{2}\\d{2}\\s\\d{2}:\\d{2}:\\d{2}$",source)) {
sdf = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
}else {
//这里抛出一个异常,
throw new TypeMismatchException("",Date.class);
}
return sdf;
}
}
8.自定义接口调用
到了这一步这个方法已经注入到spring的管辖范围内了,就可以根据业务需求处理list然后导出啦!
package 这个你们放你们自己的包吧;
import 这个你们放你们自己的包吧;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.ByteArrayOutputStream;
import java.util.List;
@Service
public class OrdCfmExport implements IOrdCfmExport {
@Override
public ResponseEntity<byte[]> export(List<Object> list, String className){
try {
ByteArrayOutputStream fileout = new ByteArrayOutputStream();
Workbook wb = new HSSFWorkbook();
Class<?> aClass = Class.forName(className); // 反射加载类实体
return ExportUtils.exportExcel(
fileout,
wb,
list,
"",
(out, workbook, data) -> ExportUtils.createCell(
wb,
data,
aClass).write(fileout));
} catch (Exception e) {
e.printStackTrace();
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@Override
public ResponseEntity<byte[]> export(List<Object> list, Class<?> className) {
try {
ByteArrayOutputStream fileout = new ByteArrayOutputStream();
Workbook wb = new HSSFWorkbook();
Class<?> aClass = className; // 反射加载类实体
return ExportUtils.exportExcel(
fileout,
wb,
list,
"",
(out, workbook, data) -> ExportUtils.createCell(
wb,
data,
aClass).write(fileout));
} catch (Exception e) {
e.printStackTrace();
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
9.最后贴一下vue代码
export() {
let that = this
let params = {}
params.data = that.exportBatchWrapper
params.baseUrl = that.url.baseUrlExport
framework.save(that.url.data.saveExport, params, 'EXPORT_POST').then((res) => {
let blob = new Blob([res.data], { type: 'application/vnd.ms-excel' })
// 其他浏览器
let link = document.createElement('a') // 创建a标签
link.style.display = 'none'
let objectUrl = URL.createObjectURL(blob)
link.href = objectUrl
link.click()
URL.revokeObjectURL(objectUrl)
}).catch((e) => {
that.$message.error('导出失败,内部服务器错误!')
})
}
save: function (url, params, method) {
if (method === 'GET') {
return http.get(url, params.data, null, params.baseUrl)
} else if (method === 'POST') {
return http.post(url, params.data, null, params.baseUrl)
} else if (method === 'EXPORT_POST') {
return http.post(url, params.data, { responseType: 'blob' }, params.baseUrl)
}
}
/**
* http post请求
* @param url请求的url地址
* @param params 基于post请求参数,格式必须是json,例如{id: '1111'}
* @param config 其他配置,一般是用于配置其他属性
*/
export function post(url, data, config, baseUrl) {
let options = { url: url, data: data, method: 'post' }
let opt = config ? Object.assign(config, options) : options
if (baseUrl === '' || baseUrl === null || baseUrl === undefined) {
axios = new HttpRequest(getBaseUrl())
return axios.request(opt)
} else {
if (nodeEnv === 'production') {
axios = new HttpRequest(getBaseUrl() + baseUrl)
} else {
axios = new HttpRequest(baseUrl)
}
return axios.request(opt)
}
}
axios配置这里不做展示了,相信到这里就已经能明白了。后期如果有代码技术上的问题请后台联系我发起技术讨论大家相互学习。最后希望大家学无止境,欲穷千里目,更上一层楼。谢谢🙏