Java POI selecciona dinámicamente la columna de campo exportada

Escenario comercial: el botón de exportación de una página, porque hay muchos campos y el cliente desea exportar diferentes campos para una fácil observación cada vez, por lo que es necesario seleccionar dinámicamente la columna de exportación de Excel

El método utilizado en este artículo se usa 自定义注解 + POI para implementarlo.
No hablemos mucho, veamos el efecto primero. Si no cumple con su efecto, simplemente elimínelo.

1. Visualización de representaciones

1,1 transferencia de parámetros frontales analógicos de cartero

Los siguientes valores de campo se pasan para representar las columnas que deben exportarse
inserte la descripción de la imagen aquí

1.2 Representaciones de Excel exportadas

inserte la descripción de la imagen aquí

Hablemos brevemente sobre la idea y el proceso del código:
1. Los campos que deben exportarse en la transferencia de parámetros front-end y los encabezados de Excel correspondientes a los campos
2. Los campos en el primer paso del ciclo, dibujar las celdas de cada fila de acuerdo con el conjunto de datos encontrado
3. La clave Paso 1: encuentre la relación correspondiente entre la transmisión de front-end y la participación en nuestro conjunto de datos (la lista de entidades de datos encontradas en mysql), y dibuje cada celda de acuerdo con esto paso.
En este artículo, el reflejo de la clase de entidad se usa para obtener la relación correspondiente. Para obtener detalles, consulte el código en "ExportExcel.getValues(Object rowData, String[] exportFieldArr)", ¡el código central!

2. Pantalla de código

2.1 Clase de entidad

2.1.1 dto para recibir front-end


/**
 * <p>@Description: 用于接收前端传参的dto</p >
 * <p>@param </p >
 */
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class DynamicExportRequest {
    
    

    //@ApiModelProperty("前端选择的需要导出的字段")
    private GoodsExportBean goodsExportBean;
    // 分页参数
    private int pageIndex;
    private int pageSize;
}

2.1.2 clase de entidad mysql


package com.lzq.learn.test.动态选择列导出excel;

import com.lzq.learn.anno.DynamicExport;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.math.BigDecimal;
import java.time.LocalDateTime;

/**
 * <p>@Description: 实体类</p >
 * <p>@date 18:58 18:58</p >
 * @author 吴巴格
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Goods {
    
    

    private Integer id;

    private String name;

    private BigDecimal price;

    private String type;

    private BigDecimal quantity;

    private LocalDateTime createTime;

}

2.1.3 dto utilizado para recibir campos front-end que deben exportarse

package com.lzq.learn.test.动态选择列导出excel.byExportBean;

import com.lzq.learn.anno.DynamicExport;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * <p>@Description: 用于接收前端哪些需要导出字段的dto</p >
 * <p>@date 9:28 9:28</p >
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class GoodsExportBean {
    
    


    @DynamicExport(sort = 1, name = "id")
    private String id;

    @DynamicExport(sort = 2, name = "姓名")
    private String name;

    @DynamicExport(sort = 3, name = "价格")
    private String price;

    @DynamicExport(sort = 4, name = "类型")
    private String type;

    @DynamicExport(sort = 5, name = "库存")
    private String quantity;

    @DynamicExport(sort = 6, name = "创建时间")
    private String createTime;
}

2.1.4 Entidades de campo opcionales para el front-end

package com.lzq.learn.test.动态选择列导出excel;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * <p>@Description: 用于返回给前端的可选择导出列 </p >
 * <p>@date 14:23 14:23</p >
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DynamicField {
    
    

    //("字段英文名")
    private String englishFiledName;

    //("excel显示表头中文名")
    private String chineseTitleName;

    public static DynamicField build(String englishFiledName, String chineseTitleName) {
    
    
        DynamicField dynamicField = new DynamicField();
        dynamicField.setEnglishFiledName(englishFiledName);
        dynamicField.setChineseTitleName(chineseTitleName);
        return dynamicField;
    }
}

2.2 Clases de herramientas y anotaciones

2.2.1 Anotaciones personalizadas

package com.lzq.learn.anno;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * <p>@Description: 动态导出字段, 将可选字段加上该注解</p >
 * <p>@date 10:26 10:26</p >
 */
@Target({
    
    TYPE, FIELD, METHOD})
@Retention(RUNTIME)
public @interface DynamicExport {
    
    

    int sort() default 0;

    String name() default "";
}

2.2.2 Clase de herramienta de columna de campo dinámico

package com.lzq.learn.test.动态选择列导出excel;

import com.lzq.learn.anno.DynamicExport;

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

/**
 * <p>@Description: 可选择动态字段列工具类</p >
 * <p>@date 14:26 14:26</p >
 */
public class DynamicFieldUtil {
    
    

    /**
     * <p>@Description: 带有 @DynamicExport 注解的实体类,利用反射返回可选择动态列</p >
     * <p>@param [object]</p >
     * <p>@return java.util.List<com.hjza.environment.response.export.DynamicField></p >
     * <p>@throws </p >
     */
    public static <T> List<DynamicField> exportPageListDynamicFieldList(Class<T> objectClass){
    
    
        Field[] declaredFields = objectClass.getDeclaredFields();
        List<DynamicField> dynamicFieldList = new ArrayList<>();
        for (Field declaredField : declaredFields) {
    
    
            declaredField.setAccessible(true);
            DynamicExport dynamicExportAnnotation = declaredField.getAnnotation(DynamicExport.class);
            String chineseTitle = dynamicExportAnnotation.name();
            dynamicFieldList.add(DynamicField.build(declaredField.getName(), chineseTitle));
        }
        return dynamicFieldList;
    }

}

2.2.3 Herramientas principales de puntos de interés

package com.lzq.learn.test.动态选择列导出excel.byExportBean;

import cn.hutool.core.util.StrUtil;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * <p>@Description: 将 Apache POI 的一些常用api进行封装</p >
 */
public class ExportExcel {
    
    



    /**
     * <p>@Description: 根据 所选动态列,以及数据集进行导出excel</p >
     * <p>@param [exportBeanFrom, dataList, fileName]</p >
     * <p>@return void</p >
     * <p>@throws </p >
     */
    public static <T> void exportByTitleAndData(Object exportBeanFrom, List<T> dataList, String fileName) {
    
    
        // 处理参数: 需要导出的英文字段名 exportFieldArr, 中文表头 title
        Map<String, Object> beanExportFieldMap = ExportExcelSortUtil.filterAndSort(exportBeanFrom);
        Map<String, String[]> fieldAndTitleMap = ExportExcelSortUtil.getExportFieldAndExportTitle(beanExportFieldMap);
        String[] title = ExportExcelSortUtil.getExportTitleArr(fieldAndTitleMap);
        String[] exportFieldArr = ExportExcelSortUtil.getExportFieldArr(fieldAndTitleMap);
        // 根据参数 生成工作簿,并写入文件流
        if (title.length > 0 && exportFieldArr.length > 0) {
    
    
            Workbook workbook = ExportExcel.getWorkbook(dataList, exportFieldArr, title);
            ExportExcel.writeToResponse(workbook, fileName);
        }
    }

    /**
     * <p>@Description: 将文件流写会回 response 中</p >
     * <p>@param [workbook, fileName]</p >
     * <p>@return void</p >
     * <p>@throws </p >
     */
    public static void writeToResponse(Workbook workbook, String fileName) {
    
    
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletResponse response = attributes.getResponse();
        response.setContentType("application/vnd.ms-excel;charset=UTF-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
        OutputStream outputStream = null;
        try {
    
    
            outputStream = response.getOutputStream();
            workbook.write(outputStream);
            outputStream.flush();
            outputStream.close();
        } catch (IOException e) {
    
    
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
    }


    /**
     * <p>@Description: 根据 数据集、导出列、表头汉字 创建工作簿</p >
     * <p>@param [dataSet 数据集, exportFieldArr 需要导出的字段列, titles 导出列对应的中文表头]</p >
     * <p>@return org.apache.poi.xssf.usermodel.XSSFWorkbook</p >
     * <p>@date 15:19 15:19</p >
     */
    public static <T> XSSFWorkbook getWorkbook(Collection<T> dataSet, String[] exportFieldArr, String[] titles) {
    
    
        // 校验变量和预期输出excel列数是否相同
        if (exportFieldArr.length != titles.length) {
    
    
            return null;
        }
        // 存储每一行的数据
        List<String[]> list = new ArrayList<>();
        for (Object obj : dataSet) {
    
    
            // 获取到每一行的属性值数组
            list.add(getValues(obj, exportFieldArr));
        }
        return getWorkbook(titles, list);
    }

    public static XSSFWorkbook getWorkbook(String[] titles, List<String[]> list) {
    
    
        // 定义表头
        String[] title = titles;
        // 创建excel工作簿
        XSSFWorkbook workbook = new XSSFWorkbook();
        // 创建工作表sheet
        XSSFSheet sheet = workbook.createSheet();
        // 创建第一行
        XSSFRow row = sheet.createRow(0);
        XSSFCell cell = null;
        // 插入第一行数据的表头
        row.setHeight((short) (24 * 20));
        CellStyle headerCommonStyle = getHeaderCommonStyle(workbook);
        for (int i = 0; i < title.length; i++) {
    
    
            cell = row.createCell(i);
            cell.setCellValue(title[i]);
            cell.setCellStyle(headerCommonStyle);
        }
        // 数据行渲染
        CellStyle bodyStyle = getBodyStyle(workbook);
        int idx = 1;
        for (String[] strings : list) {
    
    
            XSSFRow nrow = sheet.createRow(idx++);
            XSSFCell ncell = null;
            for (int i = 0; i < strings.length; i++) {
    
    
                ncell = nrow.createCell(i);
                ncell.setCellValue(strings[i]);
                ncell.setCellStyle(bodyStyle);
            }
        }
        // 设置固定列宽
        setColumnWidth(titles, sheet);
        return workbook;
    }

    // 设置固定列宽
    public static void setColumnWidth(String[] titles, Sheet sheet) {
    
    
        for (int i = 0; i < titles.length; i++) {
    
    
            sheet.setColumnWidth(i, 20 * 256);
        }
    }

    private static CellStyle getHeaderCommonStyle(Workbook workbook) {
    
    
        CellStyle header = workbook.createCellStyle();
        Font font = workbook.createFont();
        font.setBold(Boolean.TRUE);
        font.setFontHeightInPoints((short) 14);
        font.setFontName("宋体");
        header.setFont(font);
        header.setBorderTop(BorderStyle.THIN);
        header.setBorderLeft(BorderStyle.THIN);
        header.setBorderBottom(BorderStyle.THIN);
        header.setBorderRight(BorderStyle.THIN);
        header.setAlignment(HorizontalAlignment.CENTER);
        header.setVerticalAlignment(VerticalAlignment.CENTER);
        header.setFillPattern(FillPatternType.SOLID_FOREGROUND);
//        header.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
        return header;
    }
    private static CellStyle getBodyStyle(Workbook workbook) {
    
    
        CellStyle body = workbook.createCellStyle();
        Font font = workbook.createFont();
        font.setFontHeightInPoints((short) 12);
        font.setFontName("宋体");
        body.setFont(font);
        body.setWrapText(Boolean.TRUE);
        body.setBorderTop(BorderStyle.THIN);
        body.setBorderLeft(BorderStyle.THIN);
        body.setBorderBottom(BorderStyle.THIN);
        body.setBorderRight(BorderStyle.THIN);
        body.setAlignment(HorizontalAlignment.LEFT);
        body.setVerticalAlignment(VerticalAlignment.CENTER);
        body.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        body.setFillForegroundColor(IndexedColors.WHITE.getIndex());
        return body;
    }

    /**
     * <p>@Description: object就是每一行的数据</p >
     * <p>@param [rowData, exportFieldArr]</p >
     * <p>@return java.lang.String[]</p >
     * <p>@throws </p >
     */
    public static String[] getValues(Object rowData, String[] exportFieldArr) {
    
    
        String[] values = new String[exportFieldArr.length];
        try {
    
    
            for (int i = 0; i < exportFieldArr.length; i++) {
    
    

                Field field = null;

                try {
    
    
                    field = rowData.getClass().getDeclaredField(exportFieldArr[i]);
                } catch (Exception e) {
    
    
                    field = rowData.getClass().getField(exportFieldArr[i]);
                }
                // 设置访问权限为true
                field.setAccessible(true);
                values[i] = setCellValue(field, rowData);
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
        return values;
    }

    public static String setCellValue(Field field, Object data) {
    
    
        Class<?> fieldType = field.getType();
        String result = "";
        try {
    
    
            Method method = data.getClass().getMethod(getMethodNameByCamel("get", field.getName()));
            Object fieldValue = method.invoke(data);
            if (fieldType == String.class) {
    
    
                result = (method.invoke(data) == null ? null : method.invoke(data).toString());
            } else if (fieldType == Short.class) {
    
    
                result = returnStringFromNumber(fieldValue);
            } else if (fieldType == Integer.class) {
    
    
                result = returnStringFromNumber(fieldValue);
            } else if (fieldType == Long.class) {
    
    
                result = returnStringFromNumber(fieldValue);
            } else if (fieldType == Float.class) {
    
    
                result = returnStringFromNumber(fieldValue);
            } else if (fieldType == Double.class) {
    
    
                result = returnStringFromNumber(fieldValue);
            } else if (fieldType == BigDecimal.class) {
    
    
                result = returnStringFromNumber(fieldValue);
            } else if (fieldType == Boolean.class) {
    
    
                result = returnStringFromNumber(fieldValue);
            } else if (fieldType == LocalDate.class) {
    
    
                String pattern = "yyyy-MM-dd";
                LocalDate date = method.invoke(data) == null ? null : (LocalDate) method.invoke(data);
                if (date != null) {
    
    
                    result = (date.format(DateTimeFormatter.ofPattern(pattern)));
                }
            } else if (fieldType == LocalDateTime.class) {
    
    
                String pattern = "yyyy-MM-dd HH:mm:ss";
                LocalDateTime date = method.invoke(data) == null ? null : (LocalDateTime) method.invoke(data);
                if (date != null) {
    
    
                    result = (date.format(DateTimeFormatter.ofPattern(pattern)));
                }
            } else {
    
    
                result = (method.invoke(data) == null ? null : method.invoke(data).toString());
            }
            return result;
        } catch (NoSuchMethodException e) {
    
    
            e.printStackTrace();
        } catch (IllegalAccessException e) {
    
    
            e.printStackTrace();
        } catch (InvocationTargetException e) {
    
    
            e.printStackTrace();
        }
        return result;
    }

    // 将数字转换为 保留两位小数的字符串
    public static String returnStringFromNumber(Object data) {
    
    
        if (data == null || StrUtil.isBlank(data.toString())) {
    
    
            return "";
        }
        Double aDouble = Double.valueOf(data.toString());
        DecimalFormat decimalFormat = new DecimalFormat("0.00");
        String result = decimalFormat.format(aDouble);
        return result;
    }


    /**
     * <p>@Description: 拼接前缀以及方法名,驼峰形式</p >
     * <p>@param [prefix, fieldName]</p >
     * <p>@return java.lang.String</p >
     * <p>@throws </p >
     */
    private static String getMethodNameByCamel(String prefix, String fieldName) {
    
    
        StringBuilder builder = new StringBuilder()
                .append(prefix)
                .append(fieldName.substring(0, 1).toUpperCase())
                .append(fieldName.substring(1));
        return builder.toString();
    }
}

2.3 Capa de llamadas comerciales

2.3.1 controlador



import com.lzq.learn.domain.CommonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * @author 吴巴哥
 */
@RestController
@RequestMapping("/dynamic")
public class TestDynamicExcelController {
    
    


    @Autowired
    private DynamicExportService dynamicExportService;

    // 方式一:通过注解的形式,动态导出excel
    @PostMapping("/exportByFields")
    public void exportByFields(@RequestBody DynamicExportRequest  dynamicExportRequest) {
    
    
        dynamicExportService.exportByFields(dynamicExportRequest , "1.xlsx");
    }


    //("返回给前端的导出Excel的动态列")
    @GetMapping("/getDynamicFields")
    public CommonResult getDynamicFields() {
    
    
        List<DynamicField> dynamicFieldList = dynamicExportService.getDynamicFields();
        return CommonResult.success(dynamicFieldList, "获取成功");
    }

}

2.3.2 código de servicio


import com.lzq.learn.test.动态选择列导出excel.byExportBean.ExportExcel;
import com.lzq.learn.test.动态选择列导出excel.byExportBean.GoodsExportBean;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class DynamicExportService {
    
    



    // 模拟从 mysql 获取数据
    public List getDataList() {
    
    
        ArrayList<Goods> goodsList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
    
    
            BigDecimal quantity = BigDecimal.TEN.add(BigDecimal.valueOf(i));
            Goods goods = new Goods(i, "商品"+i, BigDecimal.valueOf(i), "类型"+i, quantity, LocalDateTime.now());
            goodsList.add(goods);
        }
        return goodsList;
    }



    public void exportStaticsByReflect(DynamicExportRequest dynamicExportRequest, String fileName) {
    
    

    }

    public void exportByFields(DynamicExportRequest dynamicExportRequest, String fileName) {
    
    
        List<Goods> dataList = this.getDataList();
        GoodsExportBean goodsExportBean = dynamicExportRequest.getGoodsExportBean();
        ExportExcel.exportByTitleAndData(goodsExportBean, dataList, fileName);
    }

    public List<DynamicField> getDynamicFields() {
    
    
        List<DynamicField> dynamicFieldList = DynamicFieldUtil.exportPageListDynamicFieldList(GoodsExportBean.class);
        return dynamicFieldList;
    }
}

3. Ejemplo de llamada de interfaz de cartero

3.1 Obtener columnas de campo de exportación opcionales

Dirección de la interfaz: localhost:8089/dynamic/getDynamicFields
El valor de retorno de la interfaz es el siguiente

{
    
    
	"code": 200,
	"message": "获取成功",
	"data": [
		{
    
    
			"englishFiledName": "id",
			"chineseTitleName": "id"
		},
		{
    
    
			"englishFiledName": "name",
			"chineseTitleName": "姓名"
		},
		{
    
    
			"englishFiledName": "price",
			"chineseTitleName": "价格"
		},
		{
    
    
			"englishFiledName": "type",
			"chineseTitleName": "类型"
		},
		{
    
    
			"englishFiledName": "quantity",
			"chineseTitleName": "库存"
		},
		{
    
    
			"englishFiledName": "createTime",
			"chineseTitleName": "创建时间"
		}
	]
}

3.2 Exportar Excel después de seleccionar campos

Dirección de la interfaz: localhost:8089/dynamic/exportByFields
post request, el formato de paso de parámetros es el siguiente

{
    
    
    "goodsExportBean":{
    
    
        //"id":"主键",
        "name":"商品名称",
        "price":"价格",
        //"type":"类型",
        "quantity":"库存哦"
        //"createTime":"上架时间"
    }
}

Finalmente, cuando el texto no sea reflexivo, espero que puedan proporcionar comentarios activamente, ¡lo aceptaré con humildad y lo corregiré a tiempo!

Supongo que te gusta

Origin blog.csdn.net/lzq2357639195/article/details/131644196
Recomendado
Clasificación