解析、写出、合并excle

POI:



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.7.15-SNAPSHOT
         
    
    com.qx
    qx
    0.0.1-SNAPSHOT
    package1
    package1
    
        1.8
    
    
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            com.mysql
            mysql-connector-j
            runtime
        
        
            org.apache.poi
            ooxml-schemas
            1.3
        

        
            com.alibaba
            easyexcel
            2.2.3
            
                
                    poi-ooxml-schemas
                    org.apache.poi
                
            
        
        
            org.apache.xmlbeans
            xmlbeans
            2.6.0
        
        
            org.projectlombok
            lombok
            true
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
                
                    
                        
                            org.projectlombok
                            lombok
                        
                    
                
            
        
    
    
        
            spring-milestones
            Spring Milestones
            https://repo.spring.io/milestone
            
                false
            
        
        
            spring-snapshots
            Spring Snapshots
            https://repo.spring.io/snapshot
            
                false
            
        
    
    
        
            spring-milestones
            Spring Milestones
            https://repo.spring.io/milestone
            
                false
            
        
        
            spring-snapshots
            Spring Snapshots
            https://repo.spring.io/snapshot
            
                false
            
        
    


使用一个简单的写入Excle,步骤还是相同,创建文件,创建表,创建行,列。输入数据。 

package com.quxiao.controller;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
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.xssf.streaming.SXSSFWorkbook;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;


/**
 * @program: package1
 * @author: quxiao
 * @create: 2023-08-16 15:53
 **/
@RestController
@RequestMapping("t")
public class t1 {
    @RequestMapping("get")
    public String get() throws Exception {
        //03版excle
        Workbook workbook = new HSSFWorkbook();
        //表
        Sheet sheet1 = workbook.createSheet("sheet1");
        for (int i = 0; i < 10; i++) {
            Row row = sheet1.createRow(i);
            for (int j = 0; j < 20; j++) {
                row.createCell(j).setCellValue(j + "你爹");
            }
        }
        FileOutputStream file = new FileOutputStream("D:\\我的电脑\\fsdownload" + "表.xls");
        workbook.write(file);
        file.close();
        return "ok";
    }
}

读取文件,poi还是不好用,它区分2003、2007的Excle

package com.quxiao.controller;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.InputStream;


/**
 * @program: package1
 * @author: quxiao
 * @create: 2023-08-16 15:53
 **/
@RestController
@RequestMapping("t")
public class t1 {
    @RequestMapping("get")
    public String get() throws Exception {
        //03版excle
        Workbook workbook = new HSSFWorkbook();
        //表
        Sheet sheet1 = workbook.createSheet("sheet1");
        for (int i = 0; i < 10; i++) {
            Row row = sheet1.createRow(i);
            for (int j = 0; j < 20; j++) {
                row.createCell(j).setCellValue(j + "你爹");
            }
        }
        FileOutputStream file = new FileOutputStream("D:\\我的电脑\\fsdownload\\" + "表.xlsx");
        workbook.write(file);
        file.close();
        return "ok";
    }

    @RequestMapping("put")
    public String put(MultipartFile filter) throws Exception {
        InputStream inputStream = filter.getInputStream();
        Workbook workbook = new HSSFWorkbook(inputStream);
//        workbook.getNumberOfSheets()
        Sheet sheet = workbook.getSheetAt(0);
        int ofRows = sheet.getPhysicalNumberOfRows();
        for (int j = 0; j < ofRows; j++) {
            Row row = sheet.getRow(j);
            int oneRowSum = row.getPhysicalNumberOfCells();
            //获取第一行
            for (int i = 0; i < oneRowSum; i++) {
                System.out.print(row.getCell(i).getRichStringCellValue() + " ");
            }
            System.out.println();
        }
        inputStream.close();
        return "ok";
    }
}

使用EasyExcel读:

package com.quxiao.vo;

import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;

@Data
@EqualsAndHashCode
public class DemoData {
    @ExcelProperty("编号")
    public String id;
    @ExcelProperty("姓名")
    public String name;
    @ExcelProperty("年龄")
    public String age;
    @ExcelProperty("日期")
    public Date time;
    public String date;

    @Override
    public String toString() {
        return id + "," + name + "," + age + "," + timeToString(time);
    }

    public String timeToString(Date t) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(time.toInstant(), ZoneId.of("GMT+8"));
        String s = localDateTime.toLocalDate().toString() + " " + localDateTime.toLocalTime().toString();
        return s;
    }
//上面是实现类,区分开
@PostMapping("upload")
    @ResponseBody
    public List upload(MultipartFile file) throws IOException {
        List list = new ArrayList<>();
        //数据,封装类,如何使用
        EasyExcel.read(file.getInputStream(), DemoData.class, new ReadListener() {
            @Override
            public void invoke(DemoData o, AnalysisContext analysisContext) {
                //收集
                o.setDate(o.timeToString(o.getTime()));
                list.add(o);
            }

            @Override
            public void doAfterAllAnalysed(AnalysisContext analysisContext) {

            }
        }).sheet(0).doRead();

        return list;
    }
}

 导出:

  @RequestMapping("Ecget")
    public String Ecget(HttpServletResponse response) throws Exception {
        DemoData d1 = new DemoData("1", "qx1", "10", new Date());
        DemoData d2 = new DemoData("2", "qx2", "11", new Date());
        DemoData d3 = new DemoData("3", "qx3", "12", new Date());
        DemoData d4 = new DemoData("4", "qx4", "13", new Date());
        DemoData d5 = new DemoData("5", "qx5", "14", new Date());
        ArrayList list = new ArrayList<>();
        list.add(d1);
        list.add(d2);
        list.add(d3);
        list.add(d4);
        list.add(d5);
        export("a.xlsx", response, DemoData.class, list);
        return "ok";
    }

    void export(String fileName, HttpServletResponse response, Class head, List data) throws IOException {
        try {
            fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString());
            response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
            WriteCellStyle headWriteCellStyle = new WriteCellStyle();
            //设置背景颜色
            headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
            //设置头字体
            WriteFont headWriteFont = new WriteFont();
            headWriteFont.setFontHeightInPoints((short) 13);
            headWriteFont.setBold(true);
            headWriteCellStyle.setWriteFont(headWriteFont);

            //设置头居中
            headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);

            //内容策略
            WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
            //设置 水平居中
            contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
            contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
            contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);
            contentWriteCellStyle.setBorderTop(BorderStyle.THIN);
            contentWriteCellStyle.setBorderRight(BorderStyle.THIN);
            contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);

            HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);

            EasyExcel.write(response.getOutputStream(), head)
                    .registerWriteHandler(horizontalCellStyleStrategy)
                    .sheet("sheet1")
                    .doWrite(data);
            response.getOutputStream().flush();
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            response.getOutputStream().close();
        }
    }

合并方法:

在实体类中标识需要合并的字段,然后合并过程中调用EasyExcel的回调函数,判断合并

package com.quxiao.vo;

import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;

@Data
@EqualsAndHashCode
public class DemoData {
    public DemoData(String id, String name, String age, Date time) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.time = time;
    }

    public DemoData() {
    }

    @CollectCustomMerge(needMerge = true, isPk = true)
    @ExcelProperty("编号")
    public String id;
    @CollectCustomMerge(needMerge = true)
    @ExcelProperty("姓名")
    public String name;

    @ExcelProperty("年龄")
    public String age;
    @ExcelProperty("日期")
    public Date time;
    @ExcelIgnore
    public String date;

    @Override
    public String toString() {
        return id + "," + name + "," + age + "," + timeToString(time);
    }

    public String timeToString(Date t) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(time.toInstant(), ZoneId.of("GMT+8"));
        String s = localDateTime.toLocalDate().toString() + " " + localDateTime.toLocalTime().toString();
        return s;
    }
}

注解类:

package com.quxiao.vo;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 自定义注解,用于判断是否需要合并以及合并的主键
 * 标记哪些属性需要合并,哪个是主键
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface CollectCustomMerge {
    /**
     * 是否需要合并单元格
     */
    boolean needMerge() default false;

    /**
     * 是否是主键,即该字段相同的行合并
     */
    boolean isPk() default false;

}

 创建回调函数类:

package com.quxiao.vo;

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.write.handler.RowWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Administrator
 * @date 2023/08/02 16:29
 **/
public class CustomMergeStrategyTwo implements RowWriteHandler {
    /**
     * 主键下标
     */
    private Integer pkIndex;

    /**
     * 需要合并的列的下标集合
     */
    private List needMergeColumnIndex = new ArrayList<>();

    /**
     * DTO数据类型
     */
    private Class elementType;

    public CustomMergeStrategyTwo(Class elementType, int listendIndex) {
        this.elementType = elementType;
        this.listendIndex = listendIndex;
    }

    @Override
    public void beforeRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Integer rowIndex, Integer relativeRowIndex, Boolean isHead) {

    }

    @Override
    public void afterRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) {

    }

    int listendIndex = 0;
    //开始行
    int l = 1;

    @Override
    public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) {
        // 如果是标题,则直接返回
        if (isHead) {
            return;
        }
        // 获取当前sheet
        Sheet sheet = writeSheetHolder.getSheet();
        if (null == pkIndex) {
            this.lazyInit(writeSheetHolder);
        }
        // 不能和标题合并,只能数据行之间合并
        if (row.getRowNum() <= 1) {
            return;
        }
        // 获取上一行数据
        Row lastRow = sheet.getRow(row.getRowNum() - 1);
        // 将本行和上一行是同一类型的数据(通过主键字段进行判断),则需要合并
        if (lastRow.getCell(pkIndex).getStringCellValue().equalsIgnoreCase(row.getCell(pkIndex).getStringCellValue())) {
            //判断是不是最后一个,最后一个单独合并哦
            if (listendIndex == row.getRowNum()) {
                for (Integer needMerIndex : needMergeColumnIndex) {
                    CellRangeAddress cellRangeAddress = new CellRangeAddress(l, row.getRowNum(),
                            needMerIndex, needMerIndex);
                    sheet.addMergedRegionUnsafe(cellRangeAddress);
                }
            }
        } else {
            //开始行,上一行合并
            for (Integer needMerIndex : needMergeColumnIndex) {
                CellRangeAddress cellRangeAddress = new CellRangeAddress(l, row.getRowNum() - 1,
                        needMerIndex, needMerIndex);
                sheet.addMergedRegionUnsafe(cellRangeAddress);
            }
            //更新开始行
            l = row.getRowNum();
        }
    }

    /**
     * 初始化主键下标和需要合并字段的下标
     */
    private void lazyInit(WriteSheetHolder writeSheetHolder) {

        // 获取当前sheet
        Sheet sheet = writeSheetHolder.getSheet();

        // 获取标题行
        Row titleRow = sheet.getRow(0);
        // 获取DTO的类型
        Class eleType = this.elementType;

        // 获取DTO所有的属性
        Field[] fields = eleType.getDeclaredFields();

        // 遍历所有的字段,因为是基于DTO的字段来构建excel,所以字段数 >= excel的列数
        for (Field theField : fields) {
            // 获取@ExcelProperty注解,用于获取该字段对应在excel中的列的下标
            ExcelProperty easyExcelAnno = theField.getAnnotation(ExcelProperty.class);
            // 为空,则表示该字段不需要导入到excel,直接处理下一个字段
            if (null == easyExcelAnno) {
                continue;
            }
            // 获取自定义的注解,用于合并单元格
            CollectCustomMerge collectCustomMerge = theField.getAnnotation(CollectCustomMerge.class);

            // 没有@CustomMerge注解的默认不合并
            if (null == collectCustomMerge) {
                continue;
            }

            for (int index = 0; index < fields.length; index++) {
                Cell theCell = titleRow.getCell(index);
                // 当配置为不需要导出时,返回的为null,这里作一下判断,防止NPE
                if (null == theCell) {
                    continue;
                }
                // 将字段和excel的表头匹配上
                if (easyExcelAnno.value()[0].equalsIgnoreCase(theCell.getStringCellValue())) {
                    if (collectCustomMerge.isPk()) {
                        pkIndex = index;
                    }

                    if (collectCustomMerge.needMerge()) {
                        needMergeColumnIndex.add(index);
                    }
                }
            }
        }

        // 没有指定主键,则异常
        if (null == this.pkIndex) {
            throw new IllegalStateException("使用@CustomMerge注解必须指定主键");
        }

    }

}

我们在调用时,把行总数传入,这样就可以解决是否最后一行的判断。 

   @RequestMapping("Ecget2")
    public String Ecget2(HttpServletResponse response) throws Exception {
        DemoData d1 = new DemoData("1", "qx1", "11", new Date());
        DemoData d2 = new DemoData("1", "qx1", "12", new Date());
        DemoData d3 = new DemoData("1", "qx1", "13", new Date());
        DemoData d4 = new DemoData("1", "qx1", "14", new Date());
        DemoData d5 = new DemoData("1", "qx1", "15", new Date());
        DemoData d6 = new DemoData("2", "2", "16", new Date());
        DemoData d7 = new DemoData("2", "2", "17", new Date());
        DemoData d8 = new DemoData("2", "2", "18", new Date());
        DemoData d9 = new DemoData("2", "2", "19", new Date());
        DemoData d10 = new DemoData("2", "2", "20", new Date());
        DemoData d11 = new DemoData("3", "3", "21", new Date());
        ArrayList list = new ArrayList<>();
        list.add(d1);
        list.add(d2);
        list.add(d3);
        list.add(d4);
        list.add(d5);
        list.add(d6);
        list.add(d7);
        list.add(d8);
        list.add(d9);
        list.add(d10);
        list.add(d11);
        exportMerge("a.xlsx", response, DemoData.class, list, list.size());
        return "ok";
    }
  
void export(String fileName, HttpServletResponse response, Class head, List data) throws IOException {
        try {
            fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString());
            response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
            WriteCellStyle headWriteCellStyle = new WriteCellStyle();
            //设置背景颜色
            headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
            //设置头字体
            WriteFont headWriteFont = new WriteFont();
            headWriteFont.setFontHeightInPoints((short) 13);
            headWriteFont.setBold(true);
            headWriteCellStyle.setWriteFont(headWriteFont);

            //设置头居中
            headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);

            //内容策略
            WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
            //设置 水平居中
            contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
            contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
            contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);
            contentWriteCellStyle.setBorderTop(BorderStyle.THIN);
            contentWriteCellStyle.setBorderRight(BorderStyle.THIN);
            contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);

            HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);

            EasyExcel.write(response.getOutputStream(), head)
                    .registerWriteHandler(horizontalCellStyleStrategy)
                    .sheet("sheet1")
                    .doWrite(data);
            response.getOutputStream().flush();
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            response.getOutputStream().close();
        }
    }

 

你可能感兴趣的:(java)