自定注解,导出Excel

POI导出

poi的依赖

        <dependencies>
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi</artifactId>
                <version>4.0.1</version>
            </dependency>
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi-ooxml</artifactId>
                <version>4.0.1</version>
            </dependency>
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi-ooxml-schemas</artifactId>
                <version>4.0.1</version>
            </dependency>
        </dependencies>

poi结构说明:

HSSF提供读写Microsoft Excel XLS格式档案的功能
XSSF提供读写Microsoft Excel OOXML XLSX格式档案的功能
HWPF提供读写Microsoft Word DOC格式档案的功能。
HSLF提供读写Microsoft PowerPoint格式档案的功能。
HDGF提供读Microsoft Visio格式档案的功能。
HPBF提供读Microsoft Publisher格式档案的功能。
HSMF提供读Microsoft Outlook格式档案的功能

API:

API名称 
Workbook   Excel的文档对象,针对不同的Excel类型分为:
                    HSSFWorkbook(2003)和XSSFWorkbool(2007)
Sheet Excel的表单
Row Excel的行
Cell Excel的格子单元
Font Excel字体
CellStyle 格子单元样式

行数,列数 都是从0开始的.

自定义注解:


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

//注解会在class字节码文件中存在,在运行时可以通过反射获
@Retention(RetentionPolicy.RUNTIME)
//字段、枚举的常量
@Target(ElementType.FIELD)
public @interface ExcelAttribute {
    /**
     * 对应的列名称
     *
     * @return
     */
    String name() default "";

    /**
     * 编号
     *
     * @return
     */
    int sort();

    /**
     * 字段类型对应的格式
     *
     * @return
     */
    String format() default "";

}

导出的工具类:

import lombok.Getter;
import lombok.Setter;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

@Getter
@Setter
/**
 * 导出的工具类
 */
public class ExcelExportUtil<T> {

    /**
     * 写入数据的起始行
     */
    private int rowIndex;
    /**
     * 抽取样式的起始行
     */
    private int styleIndex;
    /**
     * 模版路径
     */
    private String templatePath;
    /**
     * 对象的字节码
     */
    private Class clazz;
    /**
     * 对象中的所有属性
     */
    private Field fields[];

    /**
     * 构造方法,直接new 就可以了.
     *
     * @param clazz
     * @param rowIndex
     * @param styleIndex
     */
    public ExcelExportUtil(Class clazz, int rowIndex, int styleIndex) {
        this.clazz = clazz;
        this.rowIndex = rowIndex;
        this.styleIndex = styleIndex;
        fields = clazz.getDeclaredFields();
    }

    /**
     * 根据模版导入
     *
     * @param response
     * @param is       模版的输入流
     * @param objs     要写入的数据
     * @param fileName 文件名称
     * @throws Exception
     */
    public void export(HttpServletResponse response, InputStream is, List<T> objs, String fileName) throws Exception {

        XSSFWorkbook workbook = new XSSFWorkbook(is);
        Sheet sheet = workbook.getSheetAt(0);

        CellStyle[] styles = getTemplateStyles(sheet.getRow(styleIndex));

        AtomicInteger datasAi = new AtomicInteger(rowIndex);
        for (T t : objs) {
            Row row = sheet.createRow(datasAi.getAndIncrement());
            for (int i = 0; i < styles.length; i++) {
                Cell cell = row.createCell(i);
                cell.setCellStyle(styles[i]);
                for (Field field : fields) {
                    if (field.isAnnotationPresent(ExcelAttribute.class)) {
                        field.setAccessible(true);
                        ExcelAttribute ea = field.getAnnotation(ExcelAttribute.class);
                        /**
                         * i:当前格子,第几个
                         * ea: 属性上面的注解
                         * 如果两个匹配的话,就使用反射调用get方法.
                         */
                        if (i == ea.sort()) {
                            cell.setCellValue(field.get(t).toString());
                        }
                    }
                }
            }
        }
        fileName = URLEncoder.encode(fileName, "UTF-8");
        response.setContentType("application/octet-stream");
        response.setHeader("content-disposition", "attachment;filename=" + new String(fileName.getBytes("ISO8859-1")));
        response.setHeader("filename", fileName);
        workbook.write(response.getOutputStream());
    }

    public CellStyle[] getTemplateStyles(Row row) {
        CellStyle[] styles = new CellStyle[row.getLastCellNum()];
        for (int i = 0; i < row.getLastCellNum(); i++) {
            styles[i] = row.getCell(i).getCellStyle();
        }
        return styles;
    }
}

导入的工具类:

import com.ihrm.domain.poi.ExcelAttribute;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.format.CellFormat;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 导入的工具类
 * @param <T>
 */
public class ExcelImportUtil<T> {
 
    private Class clazz;
    private  Field fields[];
 
    public ExcelImportUtil(Class clazz) {
        this.clazz = clazz;
        fields = clazz.getDeclaredFields();
    }
 
    /**
     * 基于注解读取excel
     */
    public List<T> readExcel(InputStream is, int rowIndex,int cellIndex) {
        List<T> list = new ArrayList<T>();
        T entity = null;
        try {
            XSSFWorkbook workbook = new XSSFWorkbook(is);
            Sheet sheet = workbook.getSheetAt(0);
            // 不准确
            int rowLength = sheet.getLastRowNum();

            System.out.println(sheet.getLastRowNum());
            for (int rowNum = rowIndex; rowNum <= sheet.getLastRowNum(); rowNum++) {
                Row row = sheet.getRow(rowNum);
                entity = (T) clazz.newInstance();
                System.out.println(row.getLastCellNum());
                for (int j = cellIndex; j < row.getLastCellNum(); j++) {
                    Cell cell = row.getCell(j);
                    for (Field field : fields) {
                        if(field.isAnnotationPresent(ExcelAttribute.class)){
                            field.setAccessible(true);
                            ExcelAttribute ea = field.getAnnotation(ExcelAttribute.class);
                            if(j == ea.sort()) {
                                field.set(entity, covertAttrType(field, cell));
                            }
                        }
                    }
                }
                list.add(entity);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }
 

    /**
     * 类型转换 将cell 单元格格式转为 字段类型
     */
    private Object covertAttrType(Field field, Cell cell) throws Exception {
        String fieldType = field.getType().getSimpleName();
        if ("String".equals(fieldType)) {
            return getValue(cell);
        }else if ("Date".equals(fieldType)) {
            return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse(getValue(cell)) ;
        }else if ("int".equals(fieldType) || "Integer".equals(fieldType)) {
            return Integer.parseInt(getValue(cell));
        }else if ("double".equals(fieldType) || "Double".equals(fieldType)) {
            return Double.parseDouble(getValue(cell));
        }else {
            return null;
        }
    }
 
 
    /**
     * 格式转为String
     * @param cell
     * @return
     */
    public String getValue(Cell cell) {
        if (cell == null) {
            return "";
        }
        switch (cell.getCellType()) {
            case STRING:
                return cell.getRichStringCellValue().getString().trim();
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    Date dt = DateUtil.getJavaDate(cell.getNumericCellValue());
                    return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(dt);
                } else {
                    // 防止数值变成科学计数法
                    String strCell = "";
                    Double num = cell.getNumericCellValue();
                    BigDecimal bd = new BigDecimal(num.toString());
                    if (bd != null) {
                        strCell = bd.toPlainString();
                    }
                    // 去除 浮点型 自动加的 .0
                    if (strCell.endsWith(".0")) {
                        strCell = strCell.substring(0, strCell.indexOf("."));
                    }
                    return strCell;
                }
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            default:
                return "";
        }
    }
}

注解解释:

java中元注解有四个: @Retention @Target @Document @Inherited;

//注解的保留位置     
@Retention:    
    //注解仅存在于源码中,在class字节码文件中不包含
    @Retention(RetentionPolicy.SOURCE)   
    // 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得,
    @Retention(RetentionPolicy.CLASS) 
    // 注解会在class字节码文件中存在,在运行时可以通过反射获取到
    @Retention(RetentionPolicy.RUNTIME)  
  
@Target:注解的作用目标        
    @Target(ElementType.TYPE)   //接口、类、枚举、注解
    @Target(ElementType.FIELD) //字段、枚举的常量
    @Target(ElementType.METHOD) //方法
    @Target(ElementType.PARAMETER) //方法参数
    @Target(ElementType.CONSTRUCTOR)  //构造函数
    @Target(ElementType.LOCAL_VARIABLE)//局部变量
    @Target(ElementType.ANNOTATION_TYPE)//注解
    @Target(ElementType.PACKAGE) ///包   

@Document:说明该注解将被包含在javadoc中 
@Inherited:说明子类可以继承父类中的该注解

-- jdk8写法

package com.fofund.sale.ia.biz.common;

import com.fofund.sale.common.exception.BusinessException;
import com.fofund.sale.ia.biz.enums.ExcleFileTypeEnum;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @description: 导入Excel工具类
 * @author: zwl
 * @create: 2021-03-02 17:57
 */
public class ImportExcelUtil {

    /**
     * @Description: 读取文件数据
     * @Param: path-服务器文件路径,file-上传文件,c-反射实体类,sheetIndex-sheet页,rowIndex-行号,colIndex-列数]
     * @return: java.util.List<T>
     * @Author: zwl
     * @Date: 2021/3/2 18:28
     */
    public static <T> List<T> readObjFromExcel(String path, MultipartFile file, Class<T> c
            , int sheetIndex, int rowIndex, int colIndex) {
        // 获取 Workbook 对象
        Workbook workbook;
        if (null != file) {
            workbook = multipartFileConvertToWorkbook(file);
        } else {
            workbook = excelFileConvertToWorkbook(path);
        }
        // Sheet 下标从 0 开始
        Sheet sheet = getSheetFromWorkbook(workbook, sheetIndex);
        List<T> list = new ArrayList<>();
        Stream.iterate(0, i -> i + 1)
                // 最大行数
                .limit(sheet.getLastRowNum() + 1)
                // 跳过前几行
                .skip(rowIndex)
                // 获取行列表
                .map(i -> sheet.getRow(i))
                // 获取单个列表
                .map(a -> getCellList(a, colIndex))
                // 每行对应转化为一个目标对象
                .map(a -> textConvertToObj(a, c))
                // 目标对象列表
                .forEach(a -> list.add(a));
        return list;
    }

    private static Workbook multipartFileConvertToWorkbook(MultipartFile file) {
        if (null == file) {
            throw new BusinessException("文件不存在");
        }
        // 文件类型
        String path = file.getOriginalFilename();
        int pointIndex = path.lastIndexOf('.');
        if (pointIndex == -1) {
            throw new BusinessException("文件名不合法");
        }
        // 去掉所有空格
        String type = StringUtils.trimAllWhitespace(path.substring(pointIndex));
        if (StringUtils.isEmpty(type)) {
            throw new BusinessException("文件类型不合法");
        }
        // 文件对象
        Workbook wb;
        try {
            if (ExcleFileTypeEnum.XLS.getValue().equalsIgnoreCase(type)) {
                wb = new HSSFWorkbook(file.getInputStream());
            } else if (ExcleFileTypeEnum.XLSX.getValue().equalsIgnoreCase(type)) {
                wb = new XSSFWorkbook(file.getInputStream());
            } else {
                throw new BusinessException("文件类型不合法");
            }
        } catch (EncryptedDocumentException | IOException e) {
            throw new BusinessException("获取文件失败");
        }
        return wb;
    }

    private static Workbook excelFileConvertToWorkbook(String path) {
        if (StringUtils.isEmpty(path)) {
            throw new BusinessException("文件路径不能为空");
        }
        // 文件类型
        int pointIndex = path.lastIndexOf('.');
        if (pointIndex == -1) {
            throw new BusinessException("文件路径不合法");
        }
        // 去掉所有空格
        String type = StringUtils.trimAllWhitespace(path.substring(pointIndex));
        if (StringUtils.isEmpty(type)) {
            throw new BusinessException("文件类型不合法");
        }
        // 文件对象
        Workbook wb;
        try {
            if (ExcleFileTypeEnum.XLS.getValue().equalsIgnoreCase(type)) {
                // xls 文件
                wb = new HSSFWorkbook(new FileInputStream(path));
            } else if (ExcleFileTypeEnum.XLSX.getValue().equalsIgnoreCase(type)) {
                // xlsx 文件
                wb = new XSSFWorkbook(new FileInputStream(path));
            } else {
                throw new BusinessException("文件类型不合法");
            }
        } catch (EncryptedDocumentException | IOException e) {
            throw new BusinessException("获取文件类型失败");
        }
        return wb;
    }

    private static Sheet getSheetFromWorkbook(Workbook workbook, int sheetIndex) {
        // Sheet 下标从 0 开始
        Sheet sheet = workbook.getSheetAt(sheetIndex);
        if (null == sheet) {
            throw new BusinessException("文件内容不能为空");
        }
        // Row 下标从 0 开始 // 3 行返回 2
        sheet.getLastRowNum();
        // Col 下标从 1 开始 // 3 列返回 3
        sheet.getRow(0).getLastCellNum();
        return sheet;
    }

    private static List<Cell> getCellList(Row row, int colIndex) {
        return Stream.iterate(0, i -> i + 1)
                .limit(row.getLastCellNum())
                .skip(colIndex)
                .map(i -> row.getCell(i))
                .collect(Collectors.toList());
    }

    private static <T> T textConvertToObj(List<Cell> cellList, Class<T> c) {
        T t;
        try {
            // 对象实例化
            t = c.getConstructor().newInstance();
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            throw new BusinessException("反射获取实例化对象失败");
        }
        // 属性赋值
        Arrays.stream(c.getDeclaredFields()).forEach(a -> setFieldValue(a, t, cellList));
        return t;
    }

    private static <T> void setFieldValue(Field field, T t, List<Cell> cellList) {
        if ("serialVersionUID".equalsIgnoreCase(field.getName())) {
            return;
        }
        // 获取属性类型名称
        String typeName = field.getGenericType().getTypeName();
        // 允许赋值私有变量
        field.setAccessible(true);
        // 过滤未加注解属性
        ExcelColField excelColField = field.getAnnotation(ExcelColField.class);
        if (null == excelColField) {
            setDefaultValue(field, t);
            return;
        }
        // 注解列数
        int col = excelColField.col();
        // 空单元格赋值为 null
        if (col > cellList.size() - 1) {
            setDefaultValue(field, t);
            return;
        }
        // 单元格
        Cell cell = cellList.get(col);
        if (null == cell) {
            setDefaultValue(field, t);
            return;
        }
        String value;
        // 单元格值类型
        CellType cellType = cell.getCellTypeEnum();
        switch (cellType) {
            case NUMERIC:
                value = String.valueOf(cell.getNumericCellValue());
                break;
            case BOOLEAN:
                value = String.valueOf(cell.getBooleanCellValue());
                break;
            case STRING:
                value = cell.getStringCellValue();
                break;
            default:
                setDefaultValue(field, t);
                return;
        }
        if (typeName.indexOf(".") != -1) {
            typeName = typeName.substring(typeName.lastIndexOf(".") + 1);
        }
        // 精度保留类型
        RoundingMode roundingMode = excelColField.roundingMode();
        // 精度
        int roundingNum = excelColField.roundingNum();
        try {
            // 根据类型判断
            switch (typeName) {
                // 布尔
                case "boolean":
                case "Boolean":
                    field.set(t, Boolean.valueOf(value));
                    break;
                // 字符串
                case "char":
                case "Character":
                    field.set(t, value.charAt(0));
                    break;
                case "String":
                    field.set(t, value);
                    break;
                // 整数
                case "byte":
                case "Byte":
                    field.set(t, (byte) Double.parseDouble(value));
                    break;
                case "short":
                case "Short":
                    field.set(t, (short) Double.parseDouble(value));
                    break;
                case "int":
                case "Integer":
                    field.set(t, (int) Double.parseDouble(value));
                    break;
                case "long":
                case "Long":
                    field.set(t, (long) Double.parseDouble(value));
                    break;
                // 浮点数 由 BigDecimal 进行格式化
                case "float":
                case "Float":
                    field.set(t, new BigDecimal(value).setScale(roundingNum, roundingMode).floatValue());
                    break;
                case "double":
                case "Double":
                    field.set(t, new BigDecimal(value).setScale(roundingNum, roundingMode).doubleValue());
                    break;
                // 大数据类型
                case "BigDecimal":
                    field.set(t, new BigDecimal(value).setScale(roundingNum, roundingMode));
                    break;
                case "BigInteger":
                    field.set(t, new BigDecimal(value).setScale(0
                            , RoundingMode.DOWN).unscaledValue());
                    break;
                // 默认赋值
                default:
                    setDefaultValue(field, t);
                    break;
            }
        } catch (IllegalAccessException e) {
            throw new BusinessException("访问权限异常");
        }
    }

    private static <T> void setDefaultValue(Field field, T t) {
        // 基本类型设置为 null
        try {
            field.set(t, null);
        } catch (IllegalAccessException e) {
            throw new BusinessException("访问权限异常");
        }
    }
}

package com.fofund.sale.ia.biz.common;

import java.lang.annotation.*;
import java.math.RoundingMode;

/**
 * @Description: 导入Excel 实体类注解
 * @Author: zwl
 * @Date: 2021/3/2 18:41
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface ExcelColField {
    // 列数,从 0 开始
    int col();

    // 浮点数据类型保留类型
    RoundingMode roundingMode() default RoundingMode.HALF_UP;

    // 浮点数据类型保留位数
    int roundingNum() default 2;

}

package com.fofund.sale.ia.biz.enums;


public enum ExcleFileTypeEnum {
    XLS(".XLS", "2003"),
    XLSX(".XLSX", "2007");

    private String value;
    private String desc;

    ExcleFileTypeEnum(String value, String desc) {
        this.value = value;
        this.desc = desc;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

}

工具类优化后:

package com.fofund.sale.ia.biz.common;

import com.fofund.sale.common.exception.BusinessException;
import com.fofund.sale.ia.biz.enums.ExcleFileTypeEnum;
import org.apache.poi.EncryptedDocumentException;
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.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @description: 导入Excel工具类 拆了两个方法,一个http字符串 一个传文件
 *  纯数字 会返回 .0 比如 110 字符串类型会返回 110.0 需要特殊处理一下. 因为excle格式的问题
 * @author: zwl
 * @create: 2021-03-02 17:57
 */
public class ImportExcelUtil {

    /**
     * @Description: 读取文件数据 file
     * @Param: file-文件,c-实体类,sheetIndex-sheet页,rowIndex-行号,colIndex-列数]
     * @return: java.util.List<T>
     * @Author: zwl
     * @Date: 2021/3/2 18:28
     */
    public static <T> List<T> readObjFromExcelByFile(MultipartFile file, Class<T> c
            , int sheetIndex, int rowIndex, int colIndex) {
        Workbook workbook = multipartFileConvertToWorkbook(file);
        return gettList(c, sheetIndex, rowIndex, colIndex, workbook);
    }

    /**
     * @Description: 读取文件数据
     * @Param: path-http文件路径,c-实体类,sheetIndex-sheet页,rowIndex-行号,colIndex-列数]
     * @return: java.util.List<T>
     * @Author: zwl
     * @Date: 2021/3/2 18:28
     */
    public static <T> List<T> readObjFromExcelByPath(String path, Class<T> c
            , int sheetIndex, int rowIndex, int colIndex) {
        Workbook workbook = excelFileConvertToWorkbook(path);
        return gettList(c, sheetIndex, rowIndex, colIndex, workbook);
    }

    private static <T> List<T> gettList(Class<T> c, int sheetIndex, int rowIndex, int colIndex, Workbook workbook) {
        // Sheet 下标从 0 开始
        Sheet sheet = getSheetFromWorkbook(workbook, sheetIndex);
        List<T> list = new ArrayList<>();
        Stream.iterate(0, i -> i + 1)
                .limit(sheet.getLastRowNum() + 1)
                .skip(rowIndex)
                .map(i -> sheet.getRow(i))
                .map(a -> getCellList(a, colIndex))
                .map(a -> textConvertToObj(a, c))
                .forEach(a -> list.add(a));
        return list;
    }

    private static Workbook multipartFileConvertToWorkbook(MultipartFile file) {
        if (null == file) {
            throw new BusinessException("文件不存在");
        }
        String path = file.getOriginalFilename();
        int pointIndex = path.lastIndexOf('.');
        if (pointIndex == -1) {
            throw new BusinessException("文件名不合法");
        }
        // 去掉所有空格
        String type = StringUtils.trimAllWhitespace(path.substring(pointIndex));
        if (StringUtils.isEmpty(type)) {
            throw new BusinessException("文件类型不合法");
        }
        // 文件对象
        Workbook wb;
        try {
            InputStream inputStream = file.getInputStream();
            if (POIFSFileSystem.hasPOIFSHeader(inputStream)) {
                wb = new HSSFWorkbook(inputStream);
            } else {
                wb = new XSSFWorkbook(inputStream);
            }
        } catch (EncryptedDocumentException | IOException e) {
            throw new BusinessException("获取文件失败");
        }
        return wb;
    }

    private static Workbook excelFileConvertToWorkbook(String path) {
        if (StringUtils.isEmpty(path)) {
            throw new BusinessException("文件路径不能为空");
        }
        int pointIndex = path.lastIndexOf('.');
        if (pointIndex == -1) {
            throw new BusinessException("文件路径不合法");
        }
        // 去掉所有空格
        String type = StringUtils.trimAllWhitespace(path.substring(pointIndex));
        if (StringUtils.isEmpty(type)) {
            throw new BusinessException("文件类型不合法");
        }
        Workbook wb;
        try {
//判断优化 参考地址:https://my.oschina.net/u/4314581/blog/3316664
            BufferedInputStream inputStream = new BufferedInputStream(getExcleFileUrl(path).openStream());
            if (POIFSFileSystem.hasPOIFSHeader(inputStream)) {
                wb = new HSSFWorkbook(inputStream);
            } else {
                wb = new XSSFWorkbook(inputStream);
            }

            /* //如果是path是文件所在路径 比如 /test/file.xls 这种 用文件流
            Workbook wb;
            try {
                if (ExcleFileTypeEnum.XLS.getValue().equalsIgnoreCase(type)) {
                    wb = new HSSFWorkbook(new FileInputStream(path));
                } else if (ExcleFileTypeEnum.XLSX.getValue().equalsIgnoreCase(type)) {
                    wb = new XSSFWorkbook(new FileInputStream(path));
                } else {
                    throw new BusinessException("文件类型不合法");
                }
            } catch (EncryptedDocumentException | IOException e) {
                throw new BusinessException("获取文件类型失败");
            }*/
        } catch (EncryptedDocumentException | IOException e) {
            throw new BusinessException("获取文件失败");
        }
        return wb;
    }

    private static URL getExcleFileUrl(String path) throws IOException {
        URL url = new URL(path);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setConnectTimeout(3 * 1000);
        //防止屏蔽程序抓取而返回403错误
        conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
        String newUrl = path;
        //解决重定向的问题. 比如:  http 变 https
        // 参考链接:https://blog.csdn.net/weixin_42687829/article/details/109113117
        Map<String, List<String>> map = conn.getHeaderFields();
        for (String key : map.keySet()) {
            if ("Location".equals(key)) {
                newUrl = map.get(key).get(0);
                break;
            }
        }
        url = new URL(newUrl);
        return url;
    }

    private static Sheet getSheetFromWorkbook(Workbook workbook, int sheetIndex) {
        // Sheet 下标从 0 开始
        Sheet sheet = workbook.getSheetAt(sheetIndex);
        if (null == sheet) {
            throw new BusinessException("文件内容不能为空");
        }
        // Row 下标从 0 开始 // 3 行返回 2
        sheet.getLastRowNum();
        sheet.getRow(0).getLastCellNum();
        return sheet;
    }

    private static List<Cell> getCellList(Row row, int colIndex) {
        return Stream.iterate(0, i -> i + 1)
                .limit(row.getLastCellNum())
                .skip(colIndex)
                .map(i -> row.getCell(i))
                .collect(Collectors.toList());
    }

    private static <T> T textConvertToObj(List<Cell> cellList, Class<T> c) {
        T t;
        try {
            // 对象实例化
            t = c.getConstructor().newInstance();
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            throw new BusinessException("反射获取实例化对象失败");
        }
        // 属性赋值
        Arrays.stream(c.getDeclaredFields()).forEach(a -> setFieldValue(a, t, cellList));
        return t;
    }

    private static <T> void setFieldValue(Field field, T t, List<Cell> cellList) {
        field.setAccessible(true);
        // 过滤未加注解属性
        ExcelColField excelColField = field.getAnnotation(ExcelColField.class);
        if (null == excelColField) {
            return;
        }
        Class<?> className = field.getType();
        // 注解列数
        int col = excelColField.col();
        // 空单元格赋值为 null
        if (col > cellList.size() - 1) {
            setDefaultValue(field, t);
            return;
        }
        // 单元格
        Cell cell = cellList.get(col);
        if (null == cell) {
            setDefaultValue(field, t);
            return;
        }
        String value = String.valueOf(cell);

        // 精度保留类型
        RoundingMode roundingMode = excelColField.roundingMode();
        // 精度
        int roundingNum = excelColField.roundingNum();
        try {
            // 根据类型判断
            if (Boolean.class.equals(className) || boolean.class.equals(className)) {
                // 布尔
                field.set(t, Boolean.valueOf(value));
            } else if (char.class.equals(className) || Character.class.equals(className)) {
                // 字符串
                field.set(t, value.charAt(0));
            } else if (String.class.equals(className)) {
                field.set(t, value);
            } else if (byte.class.equals(className) || Byte.class.equals(className)) {
                field.set(t, (byte) Double.parseDouble(value));
            } else if (short.class.equals(className) || Short.class.equals(className)) {
                field.set(t, (short) Double.parseDouble(value));
            } else if (int.class.equals(className) || Integer.class.equals(className)) {
                field.set(t, (int) Double.parseDouble(value));
            } else if (long.class.equals(className) || Long.class.equals(className)) {
                field.set(t, (long) Double.parseDouble(value));
            } else if (float.class.equals(className) || Float.class.equals(className)) {
                // 浮点数 由 BigDecimal 进行格式化
                field.set(t, new BigDecimal(value).setScale(roundingNum, roundingMode).floatValue());
            } else if (double.class.equals(className) || Double.class.equals(className)) {
                field.set(t, new BigDecimal(value).setScale(roundingNum, roundingMode).doubleValue());
            } else if (BigDecimal.class.equals(className)) {
                // 大数据类型
                field.set(t, new BigDecimal(value).setScale(roundingNum, roundingMode));
            } else {
                // 默认赋值
                setDefaultValue(field, t);
            }
        } catch (IllegalAccessException e) {
            throw new BusinessException("访问权限异常");
        }
    }

    private static <T> void setDefaultValue(Field field, T t) {
        // 基本类型设置为 null
        try {
            field.set(t, null);
        } catch (IllegalAccessException e) {
            throw new BusinessException("访问权限异常");
        }
    }
}

问题:域名重定向

是因为 有重定向的情况存在, 所以要在获取链接的时候, 拿到重定向的地址, 然后重新构建链接. 获取流

easyexcel

pom

        <!-- easyexcel -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>2.1.6</version>
        </dependency>

导出工具类

import static com.alibaba.excel.EasyExcelFactory.write;
import static com.alibaba.excel.EasyExcelFactory.writerSheet;
import static com.google.common.collect.Lists.partition;

import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;
import javax.servlet.http.HttpServletResponse;

/**
 * @version 1.0
 * @description: 导出excle工具类
 * @author: 单人影
 * @create: 2021-12-09 13:22
 **/
public class ExportExcle {

    private ExportExcle() {
        throw new IllegalStateException("ExportExcle class");
    }

    private static final int MAX_NUMBER = 20000;
    /** 
    * @description 导出方法 
    * @param: [response, list, clazz, name]
    * @return void
    * @author 单人影
    * @date 2021/12/16 14:56
    * @version 1.0
    */ 
    public static <T> void export(HttpServletResponse response, List<T> list, Class clazz, String name) throws IOException {
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf8");
        //  URLEncoder 防止中文名乱码
        response.setHeader("Content-Disposition", "attachment;filename*= UTF-8''" + URLEncoder.encode(name, "UTF-8"));
        //获取response的输出流
        List<List<T>> splitList = partition(list, MAX_NUMBER);
        int i = 0;
        ExcelWriter writer = write(response.getOutputStream()).registerWriteHandler(new AutoWidth()).build();
        for (List<T> splic : splitList) {
            // .writerSheet里面放入两个参数 1. sheet编号(从0开始)  2. sheet名字
            // .head里面放入 实体类的class
            WriteSheet sheet = writerSheet(i, "sheet_" + i).head(clazz).build();
            //写入
            writer.write(splic, sheet);
            i++;
        }
        writer.finish();
    }
}

自适应样式

import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.util.CollectionUtils;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.poi.ss.usermodel.Cell;

/**
 * 自适应样式
 */
public class AutoWidth extends AbstractColumnWidthStyleStrategy {

    private static final int MAX_COLUMN_WIDTH = 255;
    //因为在自动列宽的过程中,有些设置地方让列宽显得紧凑,所以做出了个判断
    private static final int COLUMN_WIDTH = 10;
    private Map<Integer, Map<Integer, Integer>> CACHE = new HashMap(16);

    public AutoWidth() {
    }

    /**
     * @return void
     * @description 设置自适应宽度
     * @param: [writeSheetHolder, cellDataList, cell, head, relativeRowIndex, isHead]
     * @author 单人影
     * @date 2021/12/9 21:28
     * @version 1.0
     */
    @Override
    protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<CellData> cellDataList, Cell cell, Head head,
            Integer relativeRowIndex, Boolean isHead) {
        boolean needSetWidth = isHead || !CollectionUtils.isEmpty(cellDataList);
        if (needSetWidth) {
            Map<Integer, Integer> maxColumnWidthMap = (Map) CACHE.get(writeSheetHolder.getSheetNo());
            if (maxColumnWidthMap == null) {
                maxColumnWidthMap = new HashMap(16);
                CACHE.put(writeSheetHolder.getSheetNo(), maxColumnWidthMap);
            }

            Integer columnWidth = this.dataLength(cellDataList, cell, isHead);
            if (columnWidth >= 0) {
                if (columnWidth > MAX_COLUMN_WIDTH) {
                    columnWidth = MAX_COLUMN_WIDTH;
                } else {
                    if (columnWidth < COLUMN_WIDTH) {
                        columnWidth = columnWidth * 2;
                    }
                }
                Integer maxColumnWidth = (Integer) ((Map) maxColumnWidthMap).get(cell.getColumnIndex());
                if (maxColumnWidth == null || columnWidth > maxColumnWidth) {
                    ((Map) maxColumnWidthMap).put(cell.getColumnIndex(), columnWidth);
                    writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), columnWidth * 256);
                }
            }
        }
    }

    /**
     * @return java.lang.Integer
     * @description 数据长度
     * @param: [cellDataList, cell, isHead]
     * @author 单人影
     * @date 2021/12/9 21:28
     * @version 1.0
     */
    private Integer dataLength(List<CellData> cellDataList, Cell cell, Boolean isHead) {
        if (isHead) {
            return cell.getStringCellValue().getBytes().length;
        } else {
            CellData cellData = (CellData) cellDataList.get(0);
            CellDataTypeEnum type = cellData.getType();
            if (type == null) {
                return -1;
            } else {
                switch (type) {
                    case STRING:
                        return cellData.getStringValue().getBytes().length;
                    case BOOLEAN:
                        return cellData.getBooleanValue().toString().getBytes().length;
                    case NUMBER:
                        return cellData.getNumberValue().toString().getBytes().length;
                    default:
                        return -1;
                }
            }
        }
    }
}

controller导出代码:

    @PostMapping(value = "/export/trade-request")
    public void exportTradeRequest(@RequestBody TradeRequestRequest request, HttpServletResponse resource) {
        tradeRequestService.exportTradeRequest(request, resource);
    }

service代码

    @Override
    public void exportTradeRequest(TradeRequestRequest request, HttpServletResponse response) {
        BcmTrustTradeReqFlowBO bcmTrustTradeReqFlowBO = RequestConvert.CONVERT.convertTradeRequestRequest2BO(request);
        List<ExportTradeReqFlowBO> list = bcmTrustTradeReqFlowLogic.exportTradeRequest(bcmTrustTradeReqFlowBO);
        try {
            ExportExcle.export(response, list, ExportTradeReqFlowBO.class, DateUtils.sysdateToyyyyMMddHHmmss() + "交易导出申请");
        } catch (IOException e) {
            log.error("导出交易excle失败:", e);
            throw new BusinessException(ErrorEnums.BCM05020007);
        }
    }

 导出实体类 注意: 对象的所有字段都会展示, 就算没写注解也会在导出的Excel中展示

import com.alibaba.excel.annotation.ExcelProperty;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

/**
 * 认申购申请信息实体类
 *
 * @author makejava
 * @since 2021-06-24
 */
@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class ExportTradeReqFlowBO {

    /**
     * 交易申请日
     */
    @ExcelProperty(value = "交易申请日", index = 0)
    private String appDateStr;

    /**
     * 交易申请流水号
     */
    @ExcelProperty(value = "交易申请流水号", index = 1)
    private String appSerialNo;

    /**
     * 托管唯一代码
     */
    @ExcelProperty(value = "托管唯一代码", index = 2)
    private String jhPrdCode;

    /**
     * 交易账号
     */
    @ExcelProperty(value = "交易账号", index = 3)
    private String tradeAcco;

    /**
     * 账户名称
     */
    @ExcelProperty(value = "账户名称", index = 4)
    private String tradeAccoName;

    /**
     * 基金账号 基金账号未确认则默认为:NX9999
     */
    @ExcelProperty(value = "基金账号", index = 5)
    private String taAccountId;

    /**
     * 基金代码
     */
    @ExcelProperty(value = "基金代码", index = 6)
    private String fundCode;

    /**
     * 基金名称
     */
    @ExcelProperty(value = "基金名称", index = 7)
    private String fundName;

    /**
     * 业务类型
     */
    @ExcelProperty(value = "业务类型", index = 8)
    private String businessCodeStr;

    /**
     * 申请金额 单位:分
     */
    @ExcelProperty(value = "申请金额", index = 9)
    private String appMoneyStr;

    /**
     * 保管账号
     */
    @ExcelProperty(value = "保管账号", index = 10)
    private String bgAccNo;

    /**
     * 保管账户名称
     */
    @ExcelProperty(value = "保管账户名称", index = 11)
    private String bgAccName;

    @ExcelProperty(value = "订单状态", index = 12)
    private String orderStatusStr;

    @ExcelProperty(value = "资金状态", index = 13)
    private String capitalStatusStr;

    @ExcelProperty(value = "更新时间", index = 14)
    private String lastModifyTimeStr;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以使用 Apache POI 库来导出 Excel 文件,并通过自定义注解来添加序号。以下是一个示例代码: 首先,定义一个包含注解的 Java Bean 类,例如: ```java public class ExcelData { @ExcelColumn("序号") private int index; @ExcelColumn("姓名") private String name; @ExcelColumn("年龄") private int age; // 省略 getter 和 setter } ``` 其中,`@ExcelColumn` 注解用于标注 Excel 列的标题。 接下来,定义一个 Excel 工具类,例如: ```java public class ExcelUtils { public static <T> void export(List<T> dataList, OutputStream outputStream) throws Exception { Workbook workbook = new XSSFWorkbook(); Sheet sheet = workbook.createSheet("Sheet1"); // 写入表头 Row headerRow = sheet.createRow(0); Field[] fields = dataList.get(0).getClass().getDeclaredFields(); int columnIndex = 0; for (Field field : fields) { ExcelColumn column = field.getAnnotation(ExcelColumn.class); if (column != null) { Cell cell = headerRow.createCell(columnIndex); cell.setCellValue(column.value()); columnIndex++; } } // 写入数据 int rowIndex = 1; for (T data : dataList) { Row dataRow = sheet.createRow(rowIndex); columnIndex = 0; for (Field field : fields) { ExcelColumn column = field.getAnnotation(ExcelColumn.class); if (column != null) { Cell cell = dataRow.createCell(columnIndex); if ("序号".equals(column.value())) { // 添加序号列 cell.setCellValue(rowIndex); } else { field.setAccessible(true); Object value = field.get(data); if (value != null) { cell.setCellValue(value.toString()); } } columnIndex++; } } rowIndex++; } workbook.write(outputStream); } } ``` 最后,在使用时,可以这样调用: ```java List<ExcelData> dataList = new ArrayList<>(); // 添加数据到 dataList ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ExcelUtils.export(dataList, outputStream); ``` 这样就可以导出带有序号的 Excel 文件了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值