SpringBoot 使用POI 实现 excel 导出带有下拉框格式的表头文件的工具类

497 阅读4分钟

springboot使用POI导出带下拉框的excel的工具类

1、导入依赖

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

2、标题注解

该注解主要用于类的属性上。

  package com.xxx.common.annotations;
  ​
  import java.lang.annotation.*;
  ​
  /**
   * @Auther: xzg
   * @Date: 2023/8/17 14:12
   * @Description:
   */
  @Target({ElementType.FIELD})
  @Retention(RetentionPolicy.RUNTIME)
  public @interface ExcelFiledName {
  ​
  ​
      /*
      表头名称
       */
      String value() default "";
  ​
      /*
      排序字段
       */
      int order() default -1;
  ​
      /*
      表明该列是否为下拉框,默认是false。
       */
      boolean dropDownBox() default false;
  }
  ​
  
  package com.xxx.common.bean.pojo;
  ​
  /**
   * @Author: xzg
   * @Date: 2023/8/17 11:03
   * @Description:
   */
  public class PoiHeaderPojo {
  ​
      //表头是否是下拉框,默认是false
      private boolean whetherDropDownBox = false;
  ​
      //表头内容
      private String headerContent;
  ​
      //下拉框数据
      private String[] dropDownBoxList;
  ​
      //属性名称
      private String fieldName;
  ​
      public boolean getWhetherDropDownBox() {
          return whetherDropDownBox;
      }
  ​
      public void setWhetherDropDownBox(boolean whetherDropDownBox) {
          this.whetherDropDownBox = whetherDropDownBox;
      }
  ​
      public String getHeaderContent() {
          return headerContent;
      }
  ​
      public void setHeaderContent(String headerContent) {
          this.headerContent = headerContent;
      }
  ​
      public boolean isWhetherDropDownBox() {
          return whetherDropDownBox;
      }
  ​
      public String[] getDropDownBoxList() {
          return dropDownBoxList;
      }
  ​
      public void setDropDownBoxList(String[] dropDownBoxList) {
          this.dropDownBoxList = dropDownBoxList;
      }
  ​
      public String getFieldName() {
          return fieldName;
      }
  ​
      public void setFieldName(String fieldName) {
          this.fieldName = fieldName;
      }
  }
  ​

3、编写工具类

  
  package com.xxx.common.util;
  ​
  import com.xxx.util.StringUtils;
  import com.xxx.common.annotations.ExcelFiledName;
  import com.xxx.common.bean.pojo.PoiHeaderPojo;
  import org.apache.poi.ss.usermodel.*;
  import org.apache.poi.ss.util.CellRangeAddressList;
  import org.apache.poi.xssf.usermodel.XSSFDataValidationConstraint;
  import org.apache.poi.xssf.usermodel.XSSFWorkbook;
  ​
  import javax.servlet.http.HttpServletRequest;
  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.net.URLEncoder;
  import java.text.SimpleDateFormat;
  import java.util.*;
  ​
  /**
   * @Author: xzg
   * @Date: 2022/1/4 16:40
   * @Description:
   */
  public class PoiUtil<T> {
  ​
  ​
  ​
      private static final int XLS_MAX_ROW = 65535; //0开始
  ​
  ​
      private static PoiUtil instance;
  ​
      private PoiUtil() {
      }
  ​
      public static PoiUtil getInstance(){
          if (instance == null){
              synchronized (PoiUtil.class){
                  if (instance == null){
                      instance = new PoiUtil();
                  }
              }
          }
          return instance;
      }
  ​
  ​
      
  ​
  ​
      public Workbook exportExcel(String sheetName, List<T> dataList,T t){
          return getInstance().initSheet(sheetName, dataList,t, null);
      }
  ​
  ​
      public void convertPoiHeaderPojo(List<PoiHeaderPojo> headerPojos, T pojo){
  ​
          Map<Integer, Field> customFiledMap = new TreeMap<>();
  ​
          Class<?> aClass = pojo.getClass();
          Field[] declaredFields = aClass.getDeclaredFields();
          for (Field field : declaredFields) {
              ExcelFiledName annotation = field.getAnnotation(ExcelFiledName.class);
              if (annotation == null){
                  continue;
              }
              int order = annotation.order();
  ​
              if (customFiledMap.containsKey(order)) {
                  throw new RuntimeException("order值不允许重复");
              }
              customFiledMap.put(order, field);
          }
          for (Integer integer : customFiledMap.keySet()) {
              Field field = customFiledMap.get(integer);
  ​
              PoiHeaderPojo headerPojo = new PoiHeaderPojo();
              headerPojos.add(headerPojo);
              ExcelFiledName annotation = field.getAnnotation(ExcelFiledName.class);
              headerPojo.setFieldName(field.getName());
              headerPojo.setHeaderContent(annotation.value());
              headerPojo.setWhetherDropDownBox(annotation.dropDownBox());
              try {
                  field.setAccessible(true);
                  Object o = field.get(pojo);
                  if (o instanceof String){
                      String var = (String) o;
  ​
                      String[] split = var.split(",");
  ​
                      headerPojo.setDropDownBoxList(split);
                  }
  ​
              } catch (IllegalAccessException e) {
                  e.printStackTrace();
              }
          }
  ​
      }
  ​
  ​
      /**
       * 初始化表格
       *
       * @param sheetName
       * @param headerPojos
       * @param dataList
       * @param dateFormat
       */
      private Workbook initSheet(String sheetName, List<T> dataList,
                                 T t, String dateFormat){
          if (sheetName == null){
              sheetName = "sheet1";
          }
         
          List<PoiHeaderPojo> headerPojos = new ArrayList<>();

          convertPoiHeaderPojo(headerPojos,t);

  ​
          //如果headersName为空 则调用getEntityFieldName方法得到相应对象的field名作为表头行
          //getEntityFieldName(headerPojos,dataList);
  ​
          if (dateFormat == null) {
              dateFormat = "yyyy-MM-dd HH:mm:ss";
          }
  ​
  ​
          Workbook wb = new XSSFWorkbook();
          Sheet sheet = wb.createSheet(sheetName);
          //表头样式
          CellStyle headerStyle = wb.createCellStyle();
          headerStyle.setAlignment(HorizontalAlignment.CENTER); // 创建一个居中格式
          
          // 设置的背景颜色
          headerStyle.setFillForegroundColor(IndexedColors.YELLOW.getIndex());
          // 填充效果(全景填充)
          headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);

          // 设置字体
          Font font = wb.createFont();
          // 加粗
          font.setBold(true);
          headerStyle.setFont(font);

          headerStyle.setBorderBottom(BorderStyle.THIN); //下边框
          headerStyle.setBorderLeft(BorderStyle.THIN);//左边框
          headerStyle.setBorderTop(BorderStyle.THIN);//上边框
          headerStyle.setBorderRight(BorderStyle.THIN);//右边框

  ​
  ​
          //生成sheet1内容
          Row row = sheet.createRow(0);//第一个sheet的第一行为标题
          sheet.createFreezePane(0, 1, 0, 1); //冻结第一行
          //写标题
          for (int i = 0; i < headerPojos.size(); i++) {
              Cell cell = row.createCell(i); //获取第一行的每个单元格
              sheet.setColumnWidth(i, 4000); //设置每列的列宽
              cell.setCellStyle(style); //加样式
              //cell.setCellType(CellType.STRING);
  ​
              PoiHeaderPojo poiHeaderPojo = headerPojos.get(i);
              String headerContent = poiHeaderPojo.getHeaderContent();
  ​
              cell.setCellValue(headerContent); //往单元格里写数据
  ​
              if (poiHeaderPojo.getWhetherDropDownBox()){
                  setDropDownBox(sheet,i,poiHeaderPojo);
              }
          }
  ​
          if (dataList == null || dataList.size() == 0){
              return wb;
          }
          
          
           //内容样式
           CellStyle contentStyle = wb.createCellStyle();

  ​
          //按headersId过滤dtoList中的数据 set进xls
          for (int i = 0; i < dataList.size(); i++) {
              row = sheet.createRow(i + 1);
              T dtoT = dataList.get(i);
  ​
              //列号
              int k = 0;
              for (PoiHeaderPojo headerPojo : headerPojos) {
                  String fieldName = headerPojo.getFieldName();
                  String getMethodName = "get"
                          + fieldName.substring(0, 1).toUpperCase()
                          + fieldName.substring(1);//拿到属性的get方法
                  Class dtoCls = dtoT.getClass();//拿到JavaBean对象
                  //通过JavaBean对象拿到该属性的get方法,从而进行操控
                  try {
                      Method getMethod = dtoCls.getMethod(getMethodName, new Class[]{});
                      Object val = getMethod.invoke(dtoT, new Object[]{});//操控该对象属性的get方法,从而拿到属性值
                      String textVal = null;
                      if (val != null) {
                          if (val instanceof Date) {//如果值的原类型为Date 则按dateFormat方式格式化为String类型
                              Date date = (Date) val;
                              SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
                              textVal = sdf.format(date);
                          } else {
                              textVal = String.valueOf(val);//转化成String
                          }
                      } else {
                          textVal = null;
                      }
                      Cell hCell = row.createCell(k);//创建单元格
                      hCell.setCellStyle(contentStyle);//设置数据单元格样式
                      hCell.setCellValue(textVal);//set单元格数据
                  } catch (NoSuchMethodException e) {
                      e.printStackTrace();
                  } catch (InvocationTargetException e) {
                      e.printStackTrace();
                  } catch (IllegalAccessException e) {
                      e.printStackTrace();
                  } finally {
                      k++;
                  }
              }
  ​
  ​
          }
  ​
          return wb;
      }
  ​
      
      public static void setDropDownBox(Sheet sheet,int i,PoiHeaderPojo poiHeaderPojo){
          // 为标题添加下拉框
          DataValidationHelper dvHelper = sheet.getDataValidationHelper();
  ​
          //创建一个隐藏的sheet作为下拉框的数据来源
          createHiddenSheet(sheet,poiHeaderPojo);
  ​
          //DataValidationConstraint dvConstraint = dvHelper.createExplicitListConstraint(poiHeaderPojo.getDropDownBoxList());
          String strFormula = poiHeaderPojo.getFieldName() +"!$A$1:$A$" + poiHeaderPojo.getDropDownBoxList().length;
          XSSFDataValidationConstraint dvConstraint = new XSSFDataValidationConstraint(DataValidationConstraint.ValidationType.LIST,strFormula);
          CellRangeAddressList addressList = new CellRangeAddressList(1, XLS_MAX_ROW, i, i);
          DataValidation validation = dvHelper.createValidation(dvConstraint, addressList);
          validation.setSuppressDropDownArrow(true);
          validation.setEmptyCellAllowed(true);
          validation.setShowPromptBox(true);
          validation.setShowErrorBox(true);
          validation.createErrorBox("Error", "请选择下拉框中的数据");
          validation.createPromptBox("提示", "只能选择下拉框里面的数据");
          sheet.addValidationData(validation);
      }
  ​
  ​
      public static void createHiddenSheet(Sheet sheet,PoiHeaderPojo poiHeaderPojo) {
          Workbook workbook = sheet.getWorkbook();
          String fieldName = poiHeaderPojo.getFieldName();
          Sheet hiddenSheet = workbook.createSheet(fieldName);
          //设置隐藏sheet
          workbook.setSheetHidden(workbook.getSheetIndex(hiddenSheet),true);
  ​
          String[] dropDownBoxList = poiHeaderPojo.getDropDownBoxList();
          for (int i = 0; i < dropDownBoxList.length; i++) {
              Row row = hiddenSheet.createRow(i);
  ​
              Cell cell = row.createCell(0);
              String var = dropDownBoxList[i];
              cell.setCellValue(var);
          }
      }
  ​
  ​
  ​
  //    public static void main(String[] args) {
  //
  //        List<PoiHeaderPojo> headerPojoList = new ArrayList<>();
  //
  //        Workbook workbook = getInstance().exportExcel(null,null);
  //
  //
  //
  //        try (FileOutputStream outputStream = new FileOutputStream("/home/excel.xlsx")) {
  //            workbook.write(outputStream);
  //        } catch (IOException e) {
  //            e.printStackTrace();
  //        }
  //    }
  }
  ​

4、web导出示例

编写实体类

  
  package com.xxx.common.bean;
  ​
  import com.xxx.common.annotations.ExcelFiledName;
  ​
  import java.math.BigDecimal;
  ​
  /**
   * @Author: xzg
   * @Date: 2023/8/16 14:12
   * @Description:
   */
  public class ExportEntity {
  ​
      //姓名
      @ExcelFiledName(value = "姓名",order = 1)
      private String userName;
      
      //性别
      @ExcelFiledName(value = "性别",order = 2,dropDownBox = true)
      private String sex;
      
      //地址
      @ExcelFiledName(value = "地址",order = 3)
      private String address;
      
      //setter/getter方法
      
  }
  ​
/**
      导出模板接口
      * @param request
       * @param response
       * @return
       */     
  @GetMapping("/exportTemplate")
  public void exportTemplate(HttpServletRequest request, HttpServletResponse response){
  ​
      OutputStream os = null;
      try{

          ExportEntity exportEntity = new ExportEntity();
          exportEntity.setUserName("姓名");
          exportEntity.setSex("男,女");
          exportEntity.setAddress("上海");
          
 
          String fileName = String.valueOf(System.currentTimeMillis());
          os = PoiUtil.getOutputStream(fileName,request,response);
  ​
          PoiUtil.getInstance().exportExcel(null,null,exportEntity).write(os);
  ​
          os.flush();
      }catch (Exception e){
          e.printStackTrace();
      }finally {
  ​
          try {
              os.close();
          } catch (IOException e) {
              e.printStackTrace();
          }
      }
  }