1. 程式人生 > 其它 >java匯出xlsx格式的excel

java匯出xlsx格式的excel

優化了下以前寫的工具類。

優點:

  1. 標題支援從實體類中直接取值
  2. 資料列表支援List自定義類與List String
  3. 工具類採用可變引數,不會過多限制資料數量與資料格式

程式碼:

工具類:

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.core.annotation.AnnotationUtils;

import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Slf4j
public class MyExcelUtil {

    /**
     * 生成xlsx格式的Excel表格
     *
     * @param sheetName sheet名稱
     * @param titleList 標題列表
     * @param data      資料列表,支援List<自定義類>與List<String>
     * @return XSSFWorkbook
     */
    public static XSSFWorkbook getXSSFWorkbook(String sheetName,
                                               List<String> titleList, List<?>... data) throws IllegalAccessException {
        //建立HSSFWorkbook物件
        XSSFWorkbook wb = new XSSFWorkbook();
        //建立sheet物件
        XSSFSheet sheet = wb.createSheet(sheetName);
        //在sheet裡建立第一行,這裡即是表頭
        XSSFRow rowTitle = sheet.createRow(0);

        //寫入表頭的每一個列
        for (int i = 0; i < titleList.size(); i++) {
            //建立單元格
            rowTitle.createCell(i).setCellValue(titleList.get(i));
        }

        //寫入每一行的記錄
        int col = 1;
        for (List<?> dataList : data) {
            if (CollectionUtils.isEmpty(dataList)){
                continue;
            }else if (dataList.get(0) instanceof String) {
                List<?> list = MyExcelUtil.castList(dataList, String.class);
                //建立新的一行,遞增
                XSSFRow rowData = sheet.createRow(col++);
                for (int j = 0, le = list.size(); j < le; j++) {
                    //建立單元格
                    Object obj = list.get(j);
                    if (obj == null)
                        continue;
                    if (obj instanceof Date) {
                        rowData.createCell(j).setCellValue(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(obj));
                    } else {
                        rowData.createCell(j).setCellValue(String.valueOf(obj));
                    }
                }
            } else {
                for (Object o : dataList) {
                    //建立新的一行,遞增
                    XSSFRow rowData = sheet.createRow(col++);
                    {
                        Class<?> cl = o.getClass();
                        Field[] fields = cl.getDeclaredFields();
                        for (int j = 0, le = fields.length; j < le; j++) {
                            //設定欄位可見,否則會報錯,禁止訪問
                            fields[j].setAccessible(true);
                            //建立單元格
                            Object obj = fields[j].get(o);
                            if (obj == null)
                                continue;
                            if (obj instanceof Date) {
                                rowData.createCell(j).setCellValue(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(obj));
                            } else {
                                rowData.createCell(j).setCellValue(String.valueOf(obj));
                            }
                        }
                    }
                }
            }
        }
        return wb;
    }

    /**
     * 用反射獲取Desc註釋值,來生成標題列表titleList
     *
     * @param titleClass
     * @param <T>
     * @return
     */
    public static <T> List<String> getTitleListByClass(Class<T> titleClass) {
        List<String> titleList = new ArrayList<>();
        Field[] titleFields = titleClass.getDeclaredFields();
        for (Field field : titleFields) {
            Desc desc = AnnotationUtils.findAnnotation(field, Desc.class);
            if (desc != null) {
                titleList.add(desc.value());
            }
        }
        return titleList;
    }

    /**
     * 將List格式的object轉換為List
     *
     * @param obj
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> List<T> castList(Object obj, Class<T> clazz) {
        List<T> result = new ArrayList<T>();
        if (obj instanceof List<?>) {
            for (Object o : (List<?>) obj) {
                result.add(clazz.cast(o));
            }
            return result;
        }
        return null;
    }
}

註釋類:

@Retention(RetentionPolicy.RUNTIME)
public @interface Desc {
    String value();
}

自義定實體類例子:

@Data
public class ExportResp {

    @Desc("編號")
    private Integer id;

    @Desc("標題")
    private String title;

    @Desc("狀態")
    private String status;
}

介面例子:

@RestController
@RequestMapping
public class TestController {
    @GetMapping("/getExcel")
    public void getExcel(HttpServletResponse response){
        ServletOutputStream out = null;
        try {
            // 隨便創幾個資料
            List<String> contents = new ArrayList<>();
            for (int i = 0; i < 10; i++){
                contents.add("test");
            }
            ExportResp resp = new ExportResp();
            resp.setId(1);
            resp.setTitle("標題");
            resp.setStatus("熱門");
            List<ExportResp> respList = new ArrayList<>();
            respList.add(resp);
            respList.add(resp);

            String fileName = URLEncoder.encode("預設標題.xlsx", "UTF-8");
            out = response.getOutputStream();
            response.reset();
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            // filename*=utf-8''支援中文標題
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ";" + "filename*=utf-8''" + fileName);
            MyExcelUtil.getXSSFWorkbook("bug記錄", MyExcelUtil.getTitleListByClass(BugExportResp.class), contents, respList).write(out);
        } catch (Exception e) {
            System.out.println(e);
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e1) {
                    System.out.println("關閉流報錯:"+ e1);
                }
            }
        }
    }
}

呼叫介面:

http://localhost:8080/excel/getExcel