Springboot 之 使用POI導(dǎo)出Excel文件

本文章來自【知識(shí)林】

前面講述了使用POI導(dǎo)出Word文件讀取Excel文件霹肝,這兩個(gè)例子都相對(duì)簡(jiǎn)單估蹄,接下來要講述的使用POI導(dǎo)出Excel文件要復(fù)雜得多,內(nèi)容也會(huì)比較長(zhǎng)沫换。

  • 創(chuàng)建表頭信息

表頭信息用于自動(dòng)生成表頭結(jié)構(gòu)及排序

public class ExcelHeader implements Comparable<ExcelHeader>{
    /**
     * excel的標(biāo)題名稱
     */
    private String title;
    /**
     * 每一個(gè)標(biāo)題的順序
     */
    private int order;
    /**
     * 說對(duì)應(yīng)方法名稱
     */
    private String methodName;


    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public int getOrder() {
        return order;
    }
    public void setOrder(int order) {
        this.order = order;
    }
    public String getMethodName() {
        return methodName;
    }
    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }

    public int compareTo(ExcelHeader o) {
        return order>o.order?1:(order<o.order?-1:0);
    }
    public ExcelHeader(String title, int order, String methodName) {
        super();
        this.title = title;
        this.order = order;
        this.methodName = methodName;
    }
}
  • 表頭信息的Annotation
/**
 * 用來在對(duì)象的get方法上加入的annotation臭蚁,通過該annotation說明某個(gè)屬性所對(duì)應(yīng)的標(biāo)題
 * Created by 鐘述林 393156105@qq.com on 2016/10/29 0:14.
 */
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelResources {
    /**
     * 屬性的標(biāo)題名稱
     * @return
     */
    String title();
    /**
     * 在excel的順序
     * @return
     */
    int order() default 9999;
}
  • 創(chuàng)建數(shù)據(jù)實(shí)體
public class WebDto {

    //網(wǎng)站名稱
    private String name;

    //網(wǎng)址
    private String url;

    //用戶名
    private String username;

    //密碼
    private String password;

    //日均訪問量
    private Integer readCount;

    public WebDto(String name, String url, String username, String password, Integer readCount) {
        this.name = name;
        this.url = url;
        this.username = username;
        this.password = password;
        this.readCount = readCount;
    }

    public WebDto() {}

    @Override
    public String toString() {
        return "WebDto{" +
                "name='" + name + '\'' +
                ", url='" + url + '\'' +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", readCount=" + readCount +
                '}';
    }

    @ExcelResources(title="網(wǎng)站名稱",order=1)
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @ExcelResources(title="網(wǎng)址",order=2)
    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    @ExcelResources(title="用戶名",order=3)
    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    @ExcelResources(title="密碼",order=4)
    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @ExcelResources(title="日均訪問量",order=5)
    public Integer getReadCount() {
        return readCount;
    }

    public void setReadCount(Integer readCount) {
        this.readCount = readCount;
    }
}

注意:這里使用到了@ExcelResources來自動(dòng)識(shí)別表頭信息及序號(hào)

  • 獲取模板文件的工具類
public class TemplateFileUtil {

    public static FileInputStream getTemplates(String tempName) throws FileNotFoundException {
        return new FileInputStream(ResourceUtils.getFile("classpath:excel-templates/"+tempName));
    }
}

注意:從這里可以看出,所有的Excel模板文件都放在resources/excel-templates/目錄下讯赏。

  • 模板工具類

通過此類可以自動(dòng)復(fù)制表樣式等功能

/**
 * 該類實(shí)現(xiàn)了基于模板的導(dǎo)出
 * 如果要導(dǎo)出序號(hào)垮兑,需要在excel中定義一個(gè)標(biāo)識(shí)為sernums
 * 如果要替換信息,需要傳入一個(gè)Map漱挎,這個(gè)map中存儲(chǔ)著要替換信息的值系枪,在excel中通過#來開頭
 * 要從哪一行那一列開始替換需要定義一個(gè)標(biāo)識(shí)為datas
 * 如果要設(shè)定相應(yīng)的樣式,可以在該行使用styles完成設(shè)定磕谅,此時(shí)所有此行都使用該樣式
 * 如果使用defaultStyls作為表示私爷,表示默認(rèn)樣式,如果沒有defaultStyles使用datas行作為默認(rèn)樣式
 * Created by 鐘述林 393156105@qq.com on 2016/10/28 23:38.
 */
public class ExcelTemplate {

    /**
     * 數(shù)據(jù)行標(biāo)識(shí)
     */
    public final static String DATA_LINE = "datas";
    /**
     * 默認(rèn)樣式標(biāo)識(shí)
     */
    public final static String DEFAULT_STYLE = "defaultStyles";
    /**
     * 行樣式標(biāo)識(shí)
     */
    public final static String STYLE = "styles";
    /**
     * 插入序號(hào)樣式標(biāo)識(shí)
     */
    public final static String SER_NUM = "sernums";
    private static ExcelTemplate et = new ExcelTemplate();
    private Workbook wb;
    private Sheet sheet;
    /**
     * 數(shù)據(jù)的初始化列數(shù)
     */
    private int initColIndex;
    /**
     * 數(shù)據(jù)的初始化行數(shù)
     */
    private int initRowIndex;
    /**
     * 當(dāng)前列數(shù)
     */
    private int curColIndex;
    /**
     * 當(dāng)前行數(shù)
     */
    private int curRowIndex;
    /**
     * 當(dāng)前行對(duì)象
     */
    private Row curRow;
    /**
     * 最后一行的數(shù)據(jù)
     */
    private int lastRowIndex;
    /**
     * 默認(rèn)樣式
     */
    private CellStyle defaultStyle;
    /**
     * 默認(rèn)行高
     */
    private float rowHeight;
    /**
     * 存儲(chǔ)某一方所對(duì)于的樣式
     */
    private Map<Integer,CellStyle> styles;
    /**
     * 序號(hào)的列
     */
    private int serColIndex;
    private ExcelTemplate(){

    }
    public static ExcelTemplate getInstance() {
        return et;
    }

    /**
     * 從classpath路徑下讀取相應(yīng)的模板文件
     * @param path
     * @return
     */
    public ExcelTemplate readTemplateByClasspath(String path) {
        try {
            wb = new HSSFWorkbook(TemplateFileUtil.getTemplates(path));
            initTemplate();
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("讀取模板不存在膊夹!請(qǐng)檢查");
        }
        return this;
    }
    /**
     * 將文件寫到相應(yīng)的路徑下
     * @param filepath
     */
    public void writeToFile(String filepath) {
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(filepath);
            wb.write(fos);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            throw new RuntimeException("寫入的文件不存在");
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("寫入數(shù)據(jù)失敗:"+e.getMessage());
        } finally {
            try {
                if(fos!=null) fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 將文件寫到某個(gè)輸出流中
     * @param os
     */
    public void wirteToStream(OutputStream os) {
        try {
            wb.write(os);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("寫入流失敗:"+e.getMessage());
        }
    }
    /**
     * 從某個(gè)路徑來讀取模板
     * @param path
     * @return
     */
    public ExcelTemplate readTemplateByPath(String path) {
        try {
            wb = new HSSFWorkbook(TemplateFileUtil.getTemplates(path));
            initTemplate();
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("讀取模板不存在衬浑!請(qǐng)檢查");
        }
        return this;
    }

    /**
     * 創(chuàng)建相應(yīng)的元素,基于String類型
     * @param value
     */
    public void createCell(String value) {
        Cell c = curRow.createCell(curColIndex);
        setCellStyle(c);
        c.setCellValue(value);
        curColIndex++;
    }
    public void createCell(int value) {
        Cell c = curRow.createCell(curColIndex);
        setCellStyle(c);
        c.setCellValue((int)value);
        curColIndex++;
    }
    public void createCell(Date value) {
        Cell c = curRow.createCell(curColIndex);
        setCellStyle(c);
        c.setCellValue(value);
        curColIndex++;
    }
    public void createCell(double value) {
        Cell c = curRow.createCell(curColIndex);
        setCellStyle(c);
        c.setCellValue(value);
        curColIndex++;
    }
    public void createCell(boolean value) {
        Cell c = curRow.createCell(curColIndex);
        setCellStyle(c);
        c.setCellValue(value);
        curColIndex++;
    }

    public void createCell(Calendar value) {
        Cell c = curRow.createCell(curColIndex);
        setCellStyle(c);
        c.setCellValue(value);
        curColIndex++;
    }
    public void createCell(BigInteger value) {
        Cell c = curRow.createCell(curColIndex);
        setCellStyle(c);
        c.setCellValue(value==null?0:value.intValue());
        curColIndex++;
    }
    /**
     * 設(shè)置某個(gè)元素的樣式
     * @param c
     */
    private void setCellStyle(Cell c) {
        if(styles.containsKey(curColIndex)) {
            c.setCellStyle(styles.get(curColIndex));
        } else {
            c.setCellStyle(defaultStyle);
        }
    }
    /**
     * 創(chuàng)建新行放刨,在使用時(shí)只要添加完一行工秩,需要調(diào)用該方法創(chuàng)建
     */
    public void createNewRow() {
        if(lastRowIndex>curRowIndex&&curRowIndex!=initRowIndex) {
            sheet.shiftRows(curRowIndex, lastRowIndex, 1,true,true);
            lastRowIndex++;
        }
        curRow = sheet.createRow(curRowIndex);
        curRow.setHeightInPoints(rowHeight);
        curRowIndex++;
        curColIndex = initColIndex;
    }

    /**
     * 插入序號(hào),會(huì)自動(dòng)找相應(yīng)的序號(hào)標(biāo)示的位置完成插入
     */
    public void insertSer() {
        int index = 1;
        Row row = null;
        Cell c = null;
        for(int i=initRowIndex;i<curRowIndex;i++) {
            row = sheet.getRow(i);
            c = row.createCell(serColIndex);
            setCellStyle(c);
            c.setCellValue(index++);
        }
    }
    /**
     * 根據(jù)map替換相應(yīng)的常量,通過Map中的值來替換#開頭的值
     * @param datas
     */
    public void replaceFinalData(Map<String,String> datas) {
        if(datas==null) return;
        for(Row row:sheet) {
            for(Cell c:row) {
//                if(c.getCellType()!=Cell.CELL_TYPE_STRING) continue;
                String str = c.getStringCellValue().trim();
                if(str.startsWith("#")) {
                    if(datas.containsKey(str.substring(1))) {
                        c.setCellValue(datas.get(str.substring(1)));
                    }
                }
            }
        }
    }
    /**
     * 基于Properties的替換助币,依然也是替換#開始的
     * @param prop
     */
    public void replaceFinalData(Properties prop) {
        if(prop==null) return;
        for(Row row:sheet) {
            for(Cell c:row) {
//                if(c.getCellType()!=Cell.CELL_TYPE_STRING) continue;
                String str = c.getStringCellValue().trim();
                if(str.startsWith("#")) {
                    if(prop.containsKey(str.substring(1))) {
                        c.setCellValue(prop.getProperty(str.substring(1)));
                    }
                }
            }
        }
    }

    private void initTemplate() {
        sheet = wb.getSheetAt(0);
        initConfigData();
        lastRowIndex = sheet.getLastRowNum();
        curRow = sheet.createRow(curRowIndex);
    }
    /**
     * 初始化數(shù)據(jù)信息
     */
    private void initConfigData() {
        boolean findData = false;
        boolean findSer = false;
        for(Row row:sheet) {
            if(findData) break;
            for(Cell c:row) {
//                if(c.getCellType()!=Cell.CELL_TYPE_STRING) continue;
                String str = c.getStringCellValue().trim();
                if(str.equals(SER_NUM)) {
                    serColIndex = c.getColumnIndex();
                    findSer = true;
                }
                if(str.equals(DATA_LINE)) {
                    initColIndex = c.getColumnIndex();
                    initRowIndex = row.getRowNum();
                    curColIndex = initColIndex;
                    curRowIndex = initRowIndex;
                    findData = true;
                    defaultStyle = c.getCellStyle();
                    rowHeight = row.getHeightInPoints();
                    initStyles();
                    break;
                }
            }
        }
        if(!findSer) {
            initSer();
        }
    }
    /**
     * 初始化序號(hào)位置
     */
    private void initSer() {
        for(Row row:sheet) {
            for(Cell c:row) {
//                if(c.getCellType()!=Cell.CELL_TYPE_STRING) continue;
                String str = c.getStringCellValue().trim();
                if(str.equals(SER_NUM)) {
                    serColIndex = c.getColumnIndex();
                }
            }
        }
    }
    /**
     * 初始化樣式信息
     */
    private void initStyles() {
        styles = new HashMap<Integer, CellStyle>();
        for(Row row:sheet) {
            for(Cell c:row) {
//                if(c.getCellType()!=Cell.CELL_TYPE_STRING) continue;
                String str = c.getStringCellValue().trim();
                if(str.equals(DEFAULT_STYLE)) {
                    defaultStyle = c.getCellStyle();
                }
                if(str.equals(STYLE)) {
                    styles.put(c.getColumnIndex(), c.getCellStyle());
                }
            }
        }
    }
}
  • 操作工具類
/**
 * 該類實(shí)現(xiàn)了將一組對(duì)象轉(zhuǎn)換為Excel表格浪听,并且可以從Excel表格中讀取到一組List對(duì)象中
 * 該類利用了BeanUtils框架中的反射完成
 * 使用該類的前提,在相應(yīng)的實(shí)體對(duì)象上通過ExcelReources來完成相應(yīng)的注解
 * Created by 鐘述林 393156105@qq.com on 2016/10/29 0:15.
 */
public class ExcelUtil {
    private static ExcelUtil eu = new ExcelUtil();
    private ExcelUtil(){}

    public static ExcelUtil getInstance() {
        return eu;
    }
    /**
     * 處理對(duì)象轉(zhuǎn)換為Excel
     * @param template
     * @param objs
     * @param clz
     * @param isClasspath
     * @return
     */
    private ExcelTemplate handlerObj2Excel (String template, List objs, Class clz, boolean isClasspath)  {
        ExcelTemplate et = ExcelTemplate.getInstance();
        try {
            if(isClasspath) {
                et.readTemplateByClasspath(template);
            } else {
                et.readTemplateByPath(template);
            }
            List<ExcelHeader> headers = getHeaderList(clz);
            Collections.sort(headers);
            //輸出標(biāo)題
            et.createNewRow();
            for(ExcelHeader eh:headers) {
                et.createCell(eh.getTitle());
            }
            //輸出值
            for(Object obj:objs) {
                et.createNewRow();
                for(ExcelHeader eh:headers) {
                    //              Method m = clz.getDeclaredMethod(mn);
                    //              Object rel = m.invoke(obj);
                    et.createCell(BeanUtils.getProperty(obj,getMethodName(eh)));
                }
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return et;
    }
    /**
     * 根據(jù)標(biāo)題獲取相應(yīng)的方法名稱
     * @param eh
     * @return
     */
    private String getMethodName(ExcelHeader eh) {
        String mn = eh.getMethodName().substring(3);
        mn = mn.substring(0,1).toLowerCase()+mn.substring(1);
        return mn;
    }
    /**
     * 將對(duì)象轉(zhuǎn)換為Excel并且導(dǎo)出奠支,該方法是基于模板的導(dǎo)出馋辈,導(dǎo)出到流
     * @param datas 模板中的替換的常量數(shù)據(jù)
     * @param template 模板路徑
     * @param os 輸出流
     * @param objs 對(duì)象列表
     * @param clz 對(duì)象的類型
     * @param isClasspath 模板是否在classPath路徑下
     */
    public void exportObj2ExcelByTemplate(Map<String,String> datas, String template, OutputStream os, List objs, Class clz, boolean isClasspath) {
        try {
            ExcelTemplate et = handlerObj2Excel(template, objs, clz, isClasspath);
            et.replaceFinalData(datas);
            et.wirteToStream(os);
            os.flush();
            os.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 將對(duì)象轉(zhuǎn)換為Excel并且導(dǎo)出抚芦,該方法是基于模板的導(dǎo)出倍谜,導(dǎo)出到一個(gè)具體的路徑中
     * @param datas 模板中的替換的常量數(shù)據(jù)
     * @param template 模板路徑
     * @param outPath 輸出路徑
     * @param objs 對(duì)象列表
     * @param clz 對(duì)象的類型
     * @param isClasspath 模板是否在classPath路徑下
     */
    public void exportObj2ExcelByTemplate(Map<String,String> datas,String template,String outPath,List objs,Class clz,boolean isClasspath) {
        ExcelTemplate et = handlerObj2Excel(template, objs, clz, isClasspath);
        et.replaceFinalData(datas);
        et.writeToFile(outPath);
    }

    /**
     * 將對(duì)象轉(zhuǎn)換為Excel并且導(dǎo)出,該方法是基于模板的導(dǎo)出叉抡,導(dǎo)出到流,基于Properties作為常量數(shù)據(jù)
     * @param prop 基于Properties的常量數(shù)據(jù)模型
     * @param template 模板路徑
     * @param os 輸出流
     * @param objs 對(duì)象列表
     * @param clz 對(duì)象的類型
     * @param isClasspath 模板是否在classPath路徑下
     */
    public void exportObj2ExcelByTemplate(Properties prop, String template, OutputStream os, List objs, Class clz, boolean isClasspath) {
        ExcelTemplate et = handlerObj2Excel(template, objs, clz, isClasspath);
        et.replaceFinalData(prop);
        et.wirteToStream(os);
    }
    /**
     * 將對(duì)象轉(zhuǎn)換為Excel并且導(dǎo)出尔崔,該方法是基于模板的導(dǎo)出,導(dǎo)出到一個(gè)具體的路徑中,基于Properties作為常量數(shù)據(jù)
     * @param prop 基于Properties的常量數(shù)據(jù)模型
     * @param template 模板路徑
     * @param outPath 輸出路徑
     * @param objs 對(duì)象列表
     * @param clz 對(duì)象的類型
     * @param isClasspath 模板是否在classPath路徑下
     */
    public void exportObj2ExcelByTemplate(Properties prop,String template,String outPath,List objs,Class clz,boolean isClasspath) {
        ExcelTemplate et = handlerObj2Excel(template, objs, clz, isClasspath);
        et.replaceFinalData(prop);
        et.writeToFile(outPath);
    }

    private Workbook handleObj2Excel(List objs, Class clz) {
        Workbook wb = new HSSFWorkbook();
        try {
            Sheet sheet = wb.createSheet();
            Row r = sheet.createRow(0);
            List<ExcelHeader> headers = getHeaderList(clz);
            Collections.sort(headers);
            //寫標(biāo)題
            for(int i=0;i<headers.size();i++) {
                r.createCell(i).setCellValue(headers.get(i).getTitle());
            }
            //寫數(shù)據(jù)
            Object obj = null;
            for(int i=0;i<objs.size();i++) {
                r = sheet.createRow(i+1);
                obj = objs.get(i);
                for(int j=0;j<headers.size();j++) {
                    r.createCell(j).setCellValue(BeanUtils.getProperty(obj, getMethodName(headers.get(j))));
                }
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return wb;
    }
    /**
     * 導(dǎo)出對(duì)象到Excel褥民,不是基于模板的季春,直接新建一個(gè)Excel完成導(dǎo)出,基于路徑的導(dǎo)出
     * @param outPath 導(dǎo)出路徑
     * @param objs 對(duì)象列表
     * @param clz 對(duì)象類型
     */
    public void exportObj2Excel(String outPath,List objs,Class clz) {
        Workbook wb = handleObj2Excel(objs, clz);
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(outPath);
            wb.write(fos);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(fos!=null) fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 導(dǎo)出對(duì)象到Excel消返,不是基于模板的载弄,直接新建一個(gè)Excel完成導(dǎo)出,基于流
     * @param os 輸出流
     * @param objs 對(duì)象列表
     * @param clz 對(duì)象類型
     */
    public void exportObj2Excel(OutputStream os,List objs,Class clz) {
        try {
            Workbook wb = handleObj2Excel(objs, clz);
            wb.write(os);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 從類路徑讀取相應(yīng)的Excel文件到對(duì)象列表
     * @param path 類路徑下的path
     * @param clz 對(duì)象類型
     * @param readLine 開始行撵颊,注意是標(biāo)題所在行
     * @param tailLine 底部有多少行宇攻,在讀入對(duì)象時(shí),會(huì)減去這些行
     * @return
     */
    public List<Object> readExcel2ObjsByClasspath(String path,Class clz,int readLine,int tailLine) {
        Workbook wb = null;
        try {
            wb = new HSSFWorkbook(TemplateFileUtil.getTemplates(path));
            return handlerExcel2Objs(wb, clz, readLine,tailLine);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 從文件路徑讀取相應(yīng)的Excel文件到對(duì)象列表
     * @param path 文件路徑下的path
     * @param clz 對(duì)象類型
     * @param readLine 開始行倡勇,注意是標(biāo)題所在行
     * @param tailLine 底部有多少行逞刷,在讀入對(duì)象時(shí),會(huì)減去這些行
     * @return
     */
    public List<Object> readExcel2ObjsByPath(String path,Class clz,int readLine,int tailLine) {
        Workbook wb = null;
        try {
            wb = new HSSFWorkbook(TemplateFileUtil.getTemplates(path));
            return handlerExcel2Objs(wb, clz, readLine,tailLine);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 從類路徑讀取相應(yīng)的Excel文件到對(duì)象列表妻熊,標(biāo)題行為0夸浅,沒有尾行
     * @param path 路徑
     * @param clz 類型
     * @return 對(duì)象列表
     */
    public List<Object> readExcel2ObjsByClasspath(String path,Class clz) {
        return this.readExcel2ObjsByClasspath(path, clz, 0,0);
    }
    /**
     * 從文件路徑讀取相應(yīng)的Excel文件到對(duì)象列表,標(biāo)題行為0扔役,沒有尾行
     * @param path 路徑
     * @param clz 類型
     * @return 對(duì)象列表
     */
    public List<Object> readExcel2ObjsByPath(String path,Class clz) {
        return this.readExcel2ObjsByPath(path, clz,0,0);
    }

    private String getCellValue(Cell c) {
        String o = null;
        switch (c.getCellType()) {
            case Cell.CELL_TYPE_BLANK:
                o = ""; break;
            case Cell.CELL_TYPE_BOOLEAN:
                o = String.valueOf(c.getBooleanCellValue()); break;
            case Cell.CELL_TYPE_FORMULA:
                o = String.valueOf(c.getCellFormula()); break;
            case Cell.CELL_TYPE_NUMERIC:
                o = String.valueOf(c.getNumericCellValue()); break;
            case Cell.CELL_TYPE_STRING:
                o = c.getStringCellValue(); break;
            default:
                o = null;
                break;
        }
        return o;
    }

    private List<Object> handlerExcel2Objs(Workbook wb,Class clz,int readLine,int tailLine) {
        Sheet sheet = wb.getSheetAt(0);
        List<Object> objs = null;
        try {
            Row row = sheet.getRow(readLine);
            objs = new ArrayList<Object>();
            Map<Integer,String> maps = getHeaderMap(row, clz);
            if(maps==null||maps.size()<=0) throw new RuntimeException("要讀取的Excel的格式不正確帆喇,檢查是否設(shè)定了合適的行");
            for(int i=readLine+1;i<=sheet.getLastRowNum()-tailLine;i++) {
                row = sheet.getRow(i);
                Object obj = clz.newInstance();
                for(Cell c:row) {
                    int ci = c.getColumnIndex();
                    String mn = maps.get(ci).substring(3);
                    mn = mn.substring(0,1).toLowerCase()+mn.substring(1);
                    BeanUtils.copyProperty(obj,mn, this.getCellValue(c));
                }
                objs.add(obj);
            }
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return objs;
    }

    private List<ExcelHeader> getHeaderList(Class clz) {
        List<ExcelHeader> headers = new ArrayList<ExcelHeader>();
        Method[] ms = clz.getDeclaredMethods();
        for(Method m:ms) {
            String mn = m.getName();
            if(mn.startsWith("get")) {
                if(m.isAnnotationPresent(ExcelResources.class)) {
                    ExcelResources er = m.getAnnotation(ExcelResources.class);
                    headers.add(new ExcelHeader(er.title(),er.order(),mn));
                }
            }
        }
        return headers;
    }

    private Map<Integer,String> getHeaderMap(Row titleRow,Class clz) {
        List<ExcelHeader> headers = getHeaderList(clz);
        Map<Integer,String> maps = new HashMap<Integer, String>();
        for(Cell c:titleRow) {
            String title = c.getStringCellValue();
            for(ExcelHeader eh:headers) {
                if(eh.getTitle().equals(title.trim())) {
                    maps.put(c.getColumnIndex(), eh.getMethodName().replace("get","set"));
                    break;
                }
            }
        }
        return maps;
    }
}
  • Excel模板文件

創(chuàng)建一個(gè)模板文件,如下圖:

POI導(dǎo)出Excel的模板文件
  • 測(cè)試類
@SpringBootTest
@RunWith(SpringRunner.class)
public class ExportExcelTest {

    @Test
    public void test() throws Exception {
        List<WebDto> list = new ArrayList<WebDto>();
        list.add(new WebDto("知識(shí)林", "http://www.zslin.com", "admin", "111111", 555));
        list.add(new WebDto("權(quán)限系統(tǒng)", "http://basic.zslin.com", "admin", "111111", 111));
        list.add(new WebDto("校園網(wǎng)", "http://school.zslin.com", "admin", "222222", 333));

        Map<String, String> map = new HashMap<String, String>();
        map.put("title", "網(wǎng)站信息表");
        map.put("total", list.size()+" 條");
        map.put("date", getDate());

        ExcelUtil.getInstance().exportObj2ExcelByTemplate(map, "web-info-template.xls", new FileOutputStream("D:/temp/out.xls"),
                list, WebDto.class, true);
    }

    private String getDate() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
        return sdf.format(new Date());
    }
}

執(zhí)行測(cè)試方法后亿胸,查看D:/temp/out.xls文件后可以看到如下圖的內(nèi)容:

POI導(dǎo)出Excel結(jié)果圖

示例代碼:https://github.com/zsl131/spring-boot-test/tree/master/study16

本文章來自【知識(shí)林】

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末番枚,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子损敷,更是在濱河造成了極大的恐慌葫笼,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拗馒,死亡現(xiàn)場(chǎng)離奇詭異路星,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門洋丐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來呈昔,“玉大人,你說我怎么就攤上這事友绝〉涛玻” “怎么了?”我有些...
    開封第一講書人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵迁客,是天一觀的道長(zhǎng)郭宝。 經(jīng)常有香客問我,道長(zhǎng)掷漱,這世上最難降的妖魔是什么粘室? 我笑而不...
    開封第一講書人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮卜范,結(jié)果婚禮上衔统,老公的妹妹穿的比我還像新娘。我一直安慰自己海雪,他們只是感情好锦爵,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著奥裸,像睡著了一般险掀。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上刺彩,一...
    開封第一講書人閱讀 51,541評(píng)論 1 305
  • 那天迷郑,我揣著相機(jī)與錄音,去河邊找鬼创倔。 笑死嗡害,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的畦攘。 我是一名探鬼主播霸妹,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼知押!你這毒婦竟也來了叹螟?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤台盯,失蹤者是張志新(化名)和其女友劉穎罢绽,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體静盅,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡良价,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片明垢。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蚣常,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出痊银,到底是詐尸還是另有隱情抵蚊,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布溯革,位于F島的核電站贞绳,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏鬓照。R本人自食惡果不足惜熔酷,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一孤紧、第九天 我趴在偏房一處隱蔽的房頂上張望豺裆。 院中可真熱鬧,春花似錦号显、人聲如沸臭猜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蔑歌。三九已至,卻和暖如春揽碘,著一層夾襖步出監(jiān)牢的瞬間次屠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工雳刺, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留劫灶,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓掖桦,卻偏偏與公主長(zhǎng)得像本昏,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子枪汪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容