首页 > 其他分享 >easyExcel通用导出(非注解,多线程)

easyExcel通用导出(非注解,多线程)

时间:2024-04-05 19:11:33浏览次数:24  
标签:return easyExcel ExcelWriter List new import 注解 多线程 public

1、基础类描述

  1. ExcelWriter(导出工具类)
  2. Query(通用查询)
  3. Consumer(函数参数)
  4. SpringBeanUtil(获取bean)

2、代码

ExcelWriter


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.PageUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.handler.WriteHandler;
import com.alibaba.excel.write.handler.context.CellWriteHandlerContext;
import com.alibaba.excel.write.handler.context.SheetWriteHandlerContext;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.WriteTable;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.itxl.common.utils.SpringBeanUtil;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @authar liuWei
 * @ @date 2024/3/27
 */
public class ExcelWriter<T>{

    private Map<String,WriteSheet> sheetMap = null;
    private Map<String,WriteTable> tableMap = null;

    private List<WriteHandler> writeHandlers = null;

    private com.alibaba.excel.ExcelWriter writer = null;

    private OutputStream outputStream = null;


    private String curSheetMame = "sheet";

    private Integer sheetNo = 1;

    private Integer cueSheetDataSize = 0;
    private static final Integer sheetMaxNum = 1000000;

    private List<List<String>> heads = null;

    /**
     * 响应文件流类型
     */
    private static final String CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
    /**
     * 响应头文件名编码格式
     */
    private static final String ENCODE = "UTF-8";

    private Long total;

    private boolean multiThread = false;

    public static <T> ExcelWriter<T> create(){
        return new ExcelWriter<>();
    }

    public ExcelWriter<T> setResponse(HttpServletResponse response,String fileName) throws IOException {
        response.setContentType(CONTENT_TYPE);
        response.setCharacterEncoding(ENCODE);
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        fileName = URLEncoder.encode(fileName, ENCODE).replaceAll("\\+", "%20");
        response.setHeader("fileName",fileName+".xlsx");
        return setOutputStream(response.getOutputStream());
    }

    public ExcelWriter<T> setOutputStream(OutputStream outputStream){
        this.outputStream = outputStream;
        return this;
    }

    private WriteSheet getSheet(String sheetName){
        if (CollUtil.isEmpty(sheetMap)){
            sheetMap = new HashMap<>();
        }
        if (StrUtil.isEmpty(sheetName)){
            sheetName = curSheetMame;
        }
        if (sheetNo > 1){
            sheetName = sheetName + sheetNo;
        }
        WriteSheet sheet = sheetMap.get(sheetName);
        if (sheet == null){
            sheet = new WriteSheet();
            sheet.setSheetName(sheetName);
            sheetMap.put(sheetName,sheet);
        }
        return sheet;
    }

    public ExcelWriter<T> setCurSheet(String sheetMame){
        this.curSheetMame = sheetMame;
        return this;
    }

    private WriteTable getTable(String tableName){
        if (CollUtil.isEmpty(tableMap)){
            tableMap = new HashMap<>();
        }
        if (StrUtil.isEmpty(tableName)){
            tableName = "table";
        }
        return tableMap.computeIfAbsent(tableName, k -> new WriteTable());
    }

    public ExcelWriter<T> addWriteHandlers(WriteHandler writeHandler){
        if (CollUtil.isEmpty(writeHandlers)){
            writeHandlers = new ArrayList<>();
        }
        writeHandlers.add(writeHandler);
        return this;
    }

    public ExcelWriter<T> builder(){
        ExcelWriterBuilder write = EasyExcelFactory.write(outputStream);
        if (CollUtil.isNotEmpty(writeHandlers)){
            for (WriteHandler writeHandler : writeHandlers) {
                write.registerWriteHandler(writeHandler);
            }
        }
        this.writer = write.build();
        return this;
    }

    public ExcelWriter<T> setHead(List<String> heads){
        return setHeads(parseHead(heads));
    }

    private List<List<String>> parseHead(List<String> heads) {
        List<List<String>> res = new ArrayList<>(heads.size());
        for (String head : heads) {
            res.add(Collections.singletonList(head));
        }
        return res;
    }

    private ExcelWriter<T> setHeads(List<List<String>> heads){
        getTable(null).setHead(heads);
        return this;
    }


    public ExcelWriter<T> writer(List<List<Object>> data){
        if (CollUtil.isEmpty(data)){
            return this;
        }
        while (cueSheetDataSize + data.size() > sheetMaxNum){
            List<List<Object>> left = ListUtil.sub(data, 0, sheetMaxNum - cueSheetDataSize);
            writer.write(left,getSheet(null),getTable(null));
            data = ListUtil.sub(data, sheetMaxNum - cueSheetDataSize, data.size());
            cueSheetDataSize = 0;
            sheetNo++;
        }
        cueSheetDataSize += data.size();
        writer.write(data,getSheet(null),getTable(null));
        return this;
    }

    public ExcelWriter<T> writer(Query<List<List<Object>>> query) throws InterruptedException {
        return writer(query, query.getPageSize());
    }

    public ExcelWriter<T> writer(Query<List<List<Object>>> query, Integer pageSize) throws InterruptedException {
        if (total == null){
            List<List<Object>> accept = query.accept();
            return writer(accept);
        }
        query.setPageSize(pageSize);
        int totalPage = PageUtil.totalPage(total, query.getPageSize());
        AtomicInteger pageNum = new AtomicInteger(1);
        if (!multiThread){
            writer(pageNum,totalPage, query);
            return this;
        }
        ThreadPoolTaskExecutor bean = SpringBeanUtil.getBean(ThreadPoolTaskExecutor.class);
        List<Future<?>> futures = new ArrayList<>();
        int treadPoolSize = Math.min(totalPage, 4);
        for (int i = 0; i < treadPoolSize; i++) {
            Future<?> future = bean.submit(() -> {
                writer(pageNum, totalPage, query);
            });
            futures.add(future);
        }
        for (Future<?> future : futures) {
            try {
                future.get();
            } catch (ExecutionException e) {
                throw new RuntimeException(e);
            }
        }
        return this;
    }

    private void writer(AtomicInteger pageNum, Integer totalPage, Query<List<List<Object>>> query){
        while (pageNum.get() <= totalPage) {
            query.setPageNum(pageNum.getAndIncrement());
            List<List<Object>> accept = query.accept();
            synchronized (writer){
                writer(accept);
            }
            query.removePage();
        }
    }

    public static  List<List<Object>> parseData(List<Object> datas,List<String> fields){
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        List<List<Object>> res = new ArrayList<>(datas.size());
        for (Object data : datas) {
            JSONObject json = JSONUtil.parseObj(data);
            List<Object> objects = new ArrayList<>(fields.size());
            for (String field : fields) {
                Object o = json.get(field);
                if (o == null){
                    o = "";
                }else if (o instanceof Date){
                    o = format.format(o);
                }else{
                    o = o.toString();
                }
                objects.add(o);
            }
            res.add(objects);
        }
        return res;
    }

    public void close() {
        if (writer == null){
           return;
        }
        writer.close();
    }

    /**
     * 开启分页查询
     * @param total
     * @return
     */
    public ExcelWriter<T> paging(Long total){
        this.total = total;
        return this;
    }

    /**
     * 开启多线程
     * @param total
     * @return
     */
    public ExcelWriter<T> multiThread(Long total){
        this.multiThread = true;
        return paging(total);
    }

    /**
     * 合并数据
     * @param firstRow
     * @param lastRow
     * @param firstCol
     * @param lastCol
     * @return
     */
    public ExcelWriter<T>  merge(Integer firstRow, Integer lastRow, Integer firstCol, Integer lastCol){
        List<List<Integer>> mergeInfo = new ArrayList<>();
        mergeInfo.add(ListUtils.newArrayList(firstRow,lastRow,firstCol,lastCol));
        return merge(mergeInfo);
    }


    /**
     * 合并数据
     * @param mergeInfo
     * @return
     */
    public ExcelWriter<T>  merge(List<List<Integer>> mergeInfo) {
        SheetWriteHandler mergeHandler = new SheetWriteHandler(){
            @Override
            public void afterSheetCreate(SheetWriteHandlerContext context) {
            for (List<Integer> merge : mergeInfo) {
                CellRangeAddress addressList = new CellRangeAddress(merge.get(0), merge.get(1), merge.get(2), merge.get(3));
                context.getWriteSheetHolder().getSheet().addMergedRegionUnsafe(addressList);
            }
            }
        };
        return addWriteHandlers(mergeHandler);
    }

    /**
     * 设置下拉框
     * @param axisInfo
     * @param data
     * @return
     */
    public ExcelWriter<T> setDropDownBox(List<Integer> axisInfo,List<String> data){
        SheetWriteHandler dropDownBoxHandler = new SheetWriteHandler() {
            @Override
            public void afterSheetCreate(SheetWriteHandlerContext context) {
                CellRangeAddressList cellRangeAddressList = new CellRangeAddressList(axisInfo.get(0), axisInfo.get(1), axisInfo.get(2), axisInfo.get(3));
                DataValidationHelper helper = context.getWriteSheetHolder().getSheet().getDataValidationHelper();
                DataValidationConstraint constraint = helper.createExplicitListConstraint(data.toArray(new String[0]));
                DataValidation dataValidation = helper.createValidation(constraint, cellRangeAddressList);
                context.getWriteSheetHolder().getSheet().addValidationData(dataValidation);
            }
        };
        return addWriteHandlers(dropDownBoxHandler);
    }

    /**
     * 设置下拉框
     * @param col
     * @param data
     * @return
     */
    public ExcelWriter<T> setDropDownBox(Integer col,List<String> data){
        //设置下拉框为col列往下1000行
        List<Integer> axisInfo = ListUtils.newArrayList(1,1000,col,col);
        return setDropDownBox(axisInfo,data);
    }

    /**
     * 设置列宽
     * @return
     */
    public ExcelWriter<T> setColumnWidth(List<List<Integer>> columnWidths){
        AbstractColumnWidthStyleStrategy strategy = new AbstractColumnWidthStyleStrategy(){
            @Override
            protected void setColumnWidth(CellWriteHandlerContext context) {
                Sheet sheet = context.getWriteSheetHolder().getSheet();
                for (List<Integer> columnWidth : columnWidths) {
                    sheet.setColumnWidth(columnWidth.get(0),columnWidth.get(1) * 256);
                }
            }
        };
        return addWriteHandlers(strategy);
    }

    /**
     * 设置列宽
     * @return
     */
    public ExcelWriter<T> setColumnWidth(Integer col,Integer width){
        List<List<Integer>> columnWidths = new ArrayList<>();
        columnWidths.add(ListUtils.newArrayList(col,width));
        return setColumnWidth(columnWidths);
    }

    /**
     * 设置行高
     * @param row
     * @param height
     * @return
     */
    public ExcelWriter<T> setRowHeight(Integer row,Integer height){
        List<List<Integer>> rowHeights = new ArrayList<>();
        rowHeights.add(ListUtils.newArrayList(row,height));
        return setRowHeight(rowHeights);
    }

    /**
     * 设置行高
     * @param rowHeights
     * @return
     */
    private ExcelWriter<T> setRowHeight(List<List<Integer>> rowHeights) {
        SheetWriteHandler strategy = new SheetWriteHandler(){
            @Override
            public void afterSheetCreate(SheetWriteHandlerContext context) {
                Sheet sheet = context.getWriteSheetHolder().getSheet();
                for (List<Integer> rowHeight : rowHeights) {
                    Row row = sheet.getRow(rowHeight.get(0));
                    row.setHeightInPoints(rowHeight.get(1));
                }
            }
        };
        return addWriteHandlers(strategy);
    }

    /**
     * 设置单元格样式
     * @param firstRow
     * @param lastRow
     * @param firstCol
     * @param lastCol
     * @return
     */
    public ExcelWriter<T> setCellStyle(Integer firstRow, Integer lastRow, Integer firstCol, Integer lastCol,CellStyle cellStyle){
        List<List<Integer>> axisInfo = new ArrayList<>();
        axisInfo.add(ListUtils.newArrayList(firstRow,lastRow,firstCol,lastCol));
        return setCellStyle(axisInfo,cellStyle);
    }

    /**
     * 设置单元格样式
     * @param axisInfo
     * @return
     */
    public ExcelWriter<T> setCellStyle(List<List<Integer>> axisInfo,CellStyle cellStyle){
        SheetWriteHandler handler = new SheetWriteHandler(){
            @Override
            public void afterSheetCreate(SheetWriteHandlerContext context) {
                Sheet sheet = context.getWriteSheetHolder().getSheet();
                for (List<Integer> axis : axisInfo) {
                    for (int i = axis.get(0); i < axis.get(1); i++) {
                        Row row = sheet.getRow(i);
                        for (int j = axis.get(2); j < axis.get(3); j++) {
                            //设置样式
                            Cell cell = row.getCell(j);
                            cell.setCellStyle(cellStyle);
                        }
                    }
                }
                SheetWriteHandler.super.afterSheetCreate(context);
            }
        };
        return addWriteHandlers(handler);
    }


    public static void error(HttpServletResponse response,String msg) throws IOException {
        response.reset();
        response.setContentType("application/json");
        response.sendError(HttpServletResponse.SC_NOT_FOUND,msg);
    }



}

Query


import org.itxl.common.utils.Consumer;

/**
 * @authar liuWei
 * @ @date 2024/3/25
 */
public abstract class Query<T> implements Consumer<T> {

    private final ThreadLocal<Integer> local = new ThreadLocal<>();

    private Integer pageSize = 10000;

    public void setPageNum(Integer pageNum){
        local.set(pageNum);
    }

    public Integer getPageNum(){
       return local.get();
    }

    public void removePage(){
        local.remove();
    }

    public Integer getPageSize() {
        return pageSize;
    }

    public void setPageSize(Integer pageSize) {
        if (pageSize == null){
            return;
        }
        this.pageSize = pageSize;
    }

    @Override
    public T accept() {
        return andThen();
    }
}

Consumer


/**
 * @authar  liuWei
 * 通用函数参数
 * @param <T>
 */
public interface Consumer<T>{
    /**
     * 方法实现
     * @return T
     */
    T andThen();

    /**
     * 方法执行
     * @return T
     */
    T accept();
}

SpringBeanUtil


import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * @authar liuWei
 * @ @date 2024/2/2
 */
@Component
public class SpringBeanUtil  implements ApplicationContextAware {
    private static ApplicationContext applicationContext;

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    public static Object getBean(String beanName) {
        return applicationContext.getBean(beanName);
    }

    public static <T> T getBean(Class<T> clazz) {
        return applicationContext.getBean(clazz);
    }

    public static <T> T getBean(String beanName, Class<T> clazz) {
        return applicationContext.getBean(beanName, clazz);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (SpringBeanUtil.applicationContext == null){
            SpringBeanUtil.applicationContext = applicationContext;
        }
    }
}

3、使用

ExcelWriter<Object> writer = ExcelWriter.create();
try {
    writer.setResponse(response,"测试")
            .setHead(ListUtils.newArrayList("测试"))
            .builder()
            .multiThread(436L)
            .writer(new Query<List<List<Object>>>() {
                @Override
                public List<List<Object>> andThen() {
                    List<Object> data=new ArrayList<>();
                    Date date = new Date();
                    data.add(date);
                    List<List<Object>> res = new ArrayList<>();
                    res.add(data);
                    return res;
                }
            });
} catch (Exception e) {
    try {
        ExcelWriter.error(response,e.getMessage());
    } catch (IOException ex) {
        throw new RuntimeException(ex);
    }
    throw new RuntimeException(e);
}finally {
    writer.close();
}

标签:return,easyExcel,ExcelWriter,List,new,import,注解,多线程,public
From: https://www.cnblogs.com/1024-lzy/p/18116066

相关文章

  • Spring 注解编程之 AnnotationMetadata
    Spring注解编程之AnnotationMetadata这篇文章我们主要深入AnnotationMetadata,了解其底层原理。Spring版本为5.1.8-RELEASEAnnotationMetadata结构使用IDEA生成AnnotationMetadata类图,如下:AnnotationMetadata存在两个实现类分别为StandardAnnotationMeta......
  • Java:多线程-继承Thread类
    在Java中,通过继承Thread类是实现多线程的一种方式。这种方式允许你创建自己的线程类,并定义线程执行的具体内容。以下是关于继承Thread类的详细讲解:继承Thread类的步骤创建线程类:创建一个继承自Thread的子类。重写run方法:在子类中重写run方法,定义线程执行的任务。run方法是......
  • Java:多线程相关知识概念
    Java中的多线程是指在单个程序中并行执行多个线程(即执行路径或任务)的能力。多线程在Java中是一个核心概念,它允许应用程序更有效地利用CPU资源,同时还能进行并发操作。以下是Java中多线程相关的详细知识:线程的基本概念线程(Thread):是操作系统能够进行运算调度的最小单位。它......
  • 多线程常用函数
    在Linux多线程编程中,有一些常用的函数和相关概念。这里做个记录方便查找:pthread_create:创建线程。该函数的原型为intpthread_create(pthread_t*thread,constpthread_attr_t*attr,void*(*start_routine)(void*),void*arg),其中thread是用于存储新线程标识符......
  • 多线程(2)-线程同步互斥锁Mutex
    在Linux多线程编程中,互斥锁(Mutex)是一种常用的同步机制,用于保护共享资源,防止多个线程同时访问导致的竞争条件。在POSIX线程库中,互斥锁通常通过pthread_mutex_t类型表示,相关的函数包括pthread_mutex_init、pthread_mutex_lock、pthread_mutex_unlock等。 下面为一个demo,......
  • 多线程(2)-线程同步条件变量
    在Linux多线程编程中,条件变量是一种用于线程间同步的重要机制。它通常与互斥锁结合使用,用于解决多个线程竞争共享资源的问题。条件变量允许一个线程在等待某个条件变为真时阻塞,并且在另一个线程改变条件并通知时恢复执行。这个玩意跟内核等待队列差不多意思。 在Linux多线......
  • 安全访问多线程环境:掌握 Java 并发集合的使用技巧
    哈喽,各位小伙伴们,你们好呀,我是喵手。  今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。  我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把......
  • Lombok常用注解详解: val, @Cleanup, @RequiredArgsConstructor
    From: https://blog.csdn.net/hy6533/article/details/131030094从零开始SpringBoot35:Lombok图源:简书(jianshu.com)Lombok是一个java项目,旨在帮助开发者减少一些“模板代码”。其具体方式是在Java代码生成字节码(class文件)时,根据你添加的相关Lombok注解或类来“自动”添加......
  • Swagger工具集及Swagger工具集常见注解和用法
    目录一、什么是Swagger工具集二、swagger常用的注解和用法@Api@ApiOperation@ApiParam@ApiModel@ApiModelProperty@ApiIgnore三、常见问题1.@ApiModelProperty和@ApiOperation有什么区别?一、什么是Swagger工具集Swagger工具集是一系列围绕OpenAPISpecification......
  • 多线程的案例
    目录1.单例模式1.1饿汉模式1.2懒汉模式-单线程版1.3懒汉模式-多线程版1.3懒汉模式-多线程版(改进)2.阻塞队列2.1阻塞队列是什么2.2生产者消费模型2.3标准库中的阻塞队列2.4阻塞队列实现3.定时器3.1定时器是什么3.2标准库中的定时器3.3实现定时器4.线程池4.1线......