【(輕量級(jí)ExcelUtil)基于JAVA反射的Excel導(dǎo)入導(dǎo)出萬(wàn)能工具類】和【基于Sring Boot及Apache POI的Excel導(dǎo)入導(dǎo)出示例】冻晤。

前言

本文由作者三汪首發(fā)于簡(jiǎn)書漱办。

前幾天發(fā)了一篇文章你虹,提供了基于最新POI版本的Excel導(dǎo)出示例确憨,提供了網(wǎng)上各個(gè)現(xiàn)有代碼版本的deprecated警告的解決方案。今天來(lái)提供一個(gè)萬(wàn)能的導(dǎo)入導(dǎo)出工具類模板以及相應(yīng)示例。

工具類的思路和代碼骨架folk自素劍步輕塵啄栓,我個(gè)人基于實(shí)際需求對(duì)代碼進(jìn)行了重寫和優(yōu)化统屈,并補(bǔ)充完善了代碼注釋仑荐。查看工具類代碼已在開源中國(guó)上發(fā)布:獲取代碼戳這里码俩。
使用模板只需要將ExcelUtil.java和StringUtil.java復(fù)制到你的項(xiàng)目中即可。

【劃重點(diǎn):同步支持xls和xlsx版本扬霜。實(shí)現(xiàn)導(dǎo)入或者導(dǎo)出都只需要兩步操作定鸟。】

讀取Excel調(diào)用步驟:
1.定義需要讀取的表頭字段和表頭對(duì)應(yīng)的屬性字段
String keyValue ="手機(jī)名稱:phoneName,顏色:color,售價(jià):price";
2.讀取數(shù)據(jù)
List<PhoneModel> list = ExcelUtil.readExcel("test.xlsx",new FileInputStream("E://test.xlsx"),ExcelUtil.getMap(keyValue),"com.lkx.model.PhoneModel",1);
readExcel參數(shù)說(shuō)明:

/**
     * readExcel:根據(jù)傳進(jìn)來(lái)的map集合讀取Excel以及model讀取Excel文件
     * 
     * @author likaixuan,wolfgy
     * @version 1.1 2017年9月18日
     * @param fileName
     *            Excel文件名
     * @param inputStream 輸入流
     * @param map
     *            表頭和屬性的Map集合,其中Map中Key為Excel列的名稱著瓶,Value為反射類的屬性
     * @param classPath
     *            需要映射的model的路徑
     * @param rowNumIndex
     *               表頭所在行數(shù)(從1開始联予,即第一行對(duì)應(yīng)行數(shù)1)
     * @return List<T> 讀取到的數(shù)據(jù)集合
     * @throws Exception
     * @since JDK 1.7
     */

導(dǎo)出Excel調(diào)用步驟
1.定義需要讀取的表頭字段和表頭對(duì)應(yīng)的屬性字段
String keyValue ="手機(jī)名稱:phoneName,顏色:color,售價(jià):price";
2.導(dǎo)出
ExcelUtil.exportExcel("導(dǎo)出數(shù)據(jù)",new FileOutputStream("E://testOut.xls"), ExcelUtil.getMap(keyValue), list, "com.lkx.model.PhoneModel", null, null, null);
exportExcel參數(shù)說(shuō)明:

 /**
     * 
     * <p>
     * Description:Excel導(dǎo)出<br />
     * </p>
     * @author likaixuan,wolfgy
     * @version 1.1 2017年9月18日
     * @param titleText 標(biāo)題欄內(nèi)容
     * @param out 輸出流
     * @param map  表頭和屬性的Map集合,其中Map中Key為Excel列的名稱,Value為反射類的屬性
     * @param list 要輸出的對(duì)象集合
     * @param classPath 需要映射的model的路徑
     * @param titleStyle 標(biāo)題欄樣式蟹但。若為null則直接使用默認(rèn)樣式
     * @param headStyle 表頭樣式躯泰。若為null則直接使用默認(rèn)樣式
     * @param dataStyle 數(shù)據(jù)行樣式。若為null則直接使用默認(rèn)樣式
     * @throws Exception
     * @since JDK 1.7
     * void
     */

下面簡(jiǎn)單粗暴上項(xiàng)目結(jié)構(gòu)和代碼华糖。
有什么意見麦向、見解或疑惑,歡迎留言討論客叉。

項(xiàng)目結(jié)構(gòu)

util層:ExcelUtil.java,StringUtil.java 實(shí)現(xiàn)導(dǎo)入導(dǎo)出Excel的工具類及其依賴的String工具類
web層:AssociationController.java 接口類
service層:StudentService.java 業(yè)務(wù)類
domain層:Student.java 學(xué)生實(shí)體

代碼展示

ExcelUtil.java

/**
 * Project Name:excelutil
 * File Name:ExcelUtil.java
 * Package Name:com.lkx.util
 * Date:2017年6月7日上午9:44:58
 * Copyright (c) 2017~2020, likaixuan@test.com.cn All Rights Reserved.
 *
*/

package com.wolfgy.util;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;




public class ExcelUtil implements Serializable{
    /**
     * serialVersionUID
     */
    private static final long serialVersionUID = 1L;
    
    
    private static final Logger LOGGER = LoggerFactory
            .getLogger(ExcelUtil.class);
    //設(shè)置Excel讀取最大行數(shù)
    private static final int MAX_ROW = 20000;

    /**
     * getMap:(將傳進(jìn)來(lái)的表頭和表頭對(duì)應(yīng)的屬性存進(jìn)Map集合诵竭,表頭字段為key,屬性為value)
     *
     * @author likaixuan,wolfgy
     * @version 1.1 2017年9月18日
     * @param 把傳進(jìn)指定格式的字符串解析到Map中
     *            形如: String keyValue = "手機(jī)名稱:phoneName,顏色:color,售價(jià):price";
     * @return Map<String, String> 轉(zhuǎn)換好的Map集合
     * @since JDK 1.7
     */
    public static Map<String, String> getMap(String keyValue) {
        Map<String, String> map = new HashMap<>();
        if (keyValue != null) {
            String[] str = keyValue.split(",");
            for (String element : str) {
                String[] str2 = element.split(":");
                map.put(str2[0], str2[1]);
            }
        }
        return map;
    }

    /**
     * readExcel:根據(jù)傳進(jìn)來(lái)的map集合讀取Excel以及model讀取Excel文件
     * 
     * @author likaixuan,wolfgy
     * @version 1.1 2017年9月18日
     * @param fileName
     *            Excel文件名
     * @param inputStream 輸入流
     * @param map
     *            表頭和屬性的Map集合,其中Map中Key為Excel列的名稱话告,Value為反射類的屬性
     * @param classPath
     *            需要映射的model的路徑
     * @param rowNumIndex
     *               表頭所在行數(shù)(從1開始,即第一行對(duì)應(yīng)行數(shù)1)
     * @return List<T> 讀取到的數(shù)據(jù)集合
     * @throws Exception
     * @since JDK 1.7
     */
    @SuppressWarnings({ "resource", "unchecked" })
    public static <T> List<T> readExcel(String fileName, InputStream inputStream,  Map<String,String>  map,
            String classPath, int rowNumIndex) throws Exception {
        // 返回表頭字段名和屬性字段名Map集合中鍵的集合(Excel列的名稱集合)
        Set<String> keySet = map.keySet();

        //反射用
        Class<?> demo = null;
        Object obj = null;
        List<Object> list = new ArrayList<Object>();
        demo = Class.forName(classPath);
        //獲取文件名后綴判斷文件類型
        String fileType = fileName.substring(fileName.lastIndexOf(".") + 1,
                fileName.length());
        
        //根據(jù)文件類型及文件輸入流新建工作簿對(duì)象
        Workbook wb = null;
        if (fileType.equals("xls")) {
            wb = new HSSFWorkbook(inputStream);
        } else if (fileType.equals("xlsx")) {
            wb = new XSSFWorkbook(inputStream);
        } else {
            LOGGER.error("您輸入的excel格式不正確");
            throw new Exception("您輸入的excel格式不正確");
        }
        // 遍歷每個(gè)Sheet表
        for (int sheetNum = 0; sheetNum < 1; sheetNum++) {
            // 表頭成功讀取標(biāo)志位卵慰。當(dāng)表頭成功讀取后沙郭,rowNum_x值為表頭實(shí)際行數(shù)
            int rowNum_x = -1;
            // 存放每一個(gè)field字段對(duì)應(yīng)所在的列的序號(hào)
            Map<String, Integer> cellmap = new HashMap<String, Integer>();
            // 存放所有的表頭字段信息
            List<String> headlist = new ArrayList<>();
            // 獲取當(dāng)前Sheet表
            Sheet hssfSheet = wb.getSheetAt(sheetNum);

            //設(shè)置默認(rèn)最大行數(shù),當(dāng)超出最大行數(shù)時(shí)返回異常
            if(hssfSheet != null && hssfSheet.getLastRowNum()>MAX_ROW){
                throw new Exception("Excel 數(shù)據(jù)超過(guò)20000行,請(qǐng)檢查是否有空行,或分批導(dǎo)入");
            }
            
            // 遍歷Excel中的每一行
            for (int rowNum = 0; rowNum <= hssfSheet.getLastRowNum(); rowNum++) {
                // 當(dāng)表頭成功讀取標(biāo)志位rowNum_x為-1時(shí),說(shuō)明還未開始讀取數(shù)據(jù)裳朋。此時(shí)病线,如果傳值指定讀取其實(shí)行,就從指定行尋找鲤嫡,否則自動(dòng)尋找送挑。
                if (rowNum_x == -1) {
                    //判斷指定行是否為空
                    Row hssfRow = hssfSheet.getRow(rowNumIndex);
                    if (hssfRow == null) {
                        throw new RuntimeException("指定的行為空,請(qǐng)檢查");
                    }
                    //設(shè)置當(dāng)前行為指定行
                    rowNum = rowNumIndex - 1;
                }
                
                //獲取當(dāng)前行
                Row hssfRow = hssfSheet.getRow(rowNum);
                //當(dāng)前行為空時(shí)暖眼,跳出本次循環(huán)進(jìn)入下一行
                if (hssfRow == null) continue;

                //當(dāng)前行數(shù)據(jù)為空時(shí)惕耕,跳出本次循環(huán)進(jìn)入下一行
                boolean flag = false;
                for (int i = 0; i < hssfRow.getLastCellNum(); i++) {
                    if (hssfRow.getCell(i) != null && !("").equals(hssfRow.getCell(i).toString().trim())) {
                        flag = true;
                    }
                }
                if (!flag) continue;

                
                //獲取表頭內(nèi)容
                if (rowNum_x == -1) {                    
                    // 循環(huán)列Cell
                    for (int cellNum = 0; cellNum <= hssfRow
                            .getLastCellNum(); cellNum++) {

                        Cell hssfCell = hssfRow.getCell(cellNum);
                        //當(dāng)前cell為空時(shí),跳出本次循環(huán)诫肠,進(jìn)入下一列司澎。
                        if (hssfCell == null) {
                            continue;
                        }
                        //獲取當(dāng)前cell的值(String類型)
                        String tempCellValue = hssfSheet.getRow(rowNum)
                                .getCell(cellNum).getStringCellValue();
                        //去除空格,空格ASCII碼為160
                        tempCellValue = StringUtils.remove(tempCellValue,
                                (char) 160);
                        tempCellValue = tempCellValue.trim();
                        //將表頭內(nèi)容放入集合
                        headlist.add(tempCellValue);

                        //遍歷表頭字段名和屬性字段名Map集合中鍵的集合(Excel列的名稱集合)
                        Iterator<String> it = keySet.iterator();
                        while (it.hasNext()) {
                            Object key = it.next();
                            if (StringUtils.isNotBlank(tempCellValue)
                                    && StringUtils.equals(tempCellValue,
                                            key.toString())) {
                                //將rowNum_x設(shè)為實(shí)際的表頭行數(shù)
                                rowNum_x = rowNum;
                                //獲取表頭每一個(gè)field字段對(duì)應(yīng)所在的列的序號(hào)
                                cellmap.put(map.get(key).toString(), cellNum);
                            }
                        }
                        //當(dāng)rowNum_x為-1時(shí),說(shuō)明沒有在表頭找到對(duì)應(yīng)的字段或者對(duì)應(yīng)字段行上面含有不為空白的行字段栋豫,返回異常挤安。
                        if (rowNum_x == -1) {
                            LOGGER.error("沒有找到對(duì)應(yīng)的字段或者對(duì)應(yīng)字段行上面含有不為空白的行字段");
                            throw new Exception("沒有找到對(duì)應(yīng)的字段或者對(duì)應(yīng)字段行上面含有不為空白的行字段");
                        }
                    }

                } else {
                    //實(shí)例化反射類對(duì)象
                    obj = demo.newInstance();
                    //遍歷并取出所需要的每個(gè)屬性值
                    Iterator<String> it = keySet.iterator();
                    while (it.hasNext()) {
                        //Excel列名
                        Object key = it.next();
                        //獲取屬性對(duì)應(yīng)列數(shù)
                        Integer cellNum_x = cellmap
                                .get(map.get(key).toString());
                        //當(dāng)屬性對(duì)應(yīng)列為空時(shí),結(jié)束本次循環(huán)笼才,進(jìn)入下次循環(huán)漱受,繼續(xù)獲取其他屬性值
                        if (cellNum_x == null || hssfRow.getCell(cellNum_x) == null) {
                            continue;
                        }
                        //得到屬性名
                        String attrName = map.get(key).toString();
                        //得到屬性類型
                        Class<?> attrType = BeanUtils.findPropertyType(attrName,
                                new Class[] { obj.getClass() });
                        //得到屬性值
                        Cell cell = hssfRow.getCell(cellNum_x);
                        Object val = getValue(cell, obj, attrName, attrType, rowNum, cellNum_x,
                                key);
                        setter(obj, attrName, val, attrType, rowNum, cellNum_x, key);

                    }
                    //將實(shí)例化好并設(shè)置完屬性的對(duì)象放入要返回的list中
                    list.add(obj);
                }

            }
        }
        wb.close();
        inputStream.close();
       
        return (List<T>) list;
    }

 
    /**
     * 
     * <p>
     * Description:setter(反射set方法給屬性賦值)<br />
     * </p>
     * @author likaixuan,wolfgy
     * @version 1.1 2017年9月18日
     * @param obj 反射類對(duì)象
     * @param attrName 屬性名
     * @param attrValue 屬性值
     * @param attrType 屬性類型
     * @param row 當(dāng)前數(shù)據(jù)在Excel中的具體行數(shù)
     * @param column 當(dāng)前數(shù)據(jù)在Excel中的具體列數(shù)
     * @param key 當(dāng)前數(shù)據(jù)對(duì)應(yīng)的Excel列名
     * @since JDK 1.7
     * @throws Exception
     * void
     */
    public static void setter(Object obj, String attrName, Object attrValue,
            Class<?> attrType, int row, int column, Object key) throws Exception {
        try {
            //獲取反射的方法名
            Method method = obj.getClass().getMethod(
                    "set" + StringUtil.toUpperCaseFirstOne(attrName), attrType);
            //進(jìn)行反射
            method.invoke(obj, attrValue);
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error("第" + (row + 1) + " 行  " + (column + 1) + "列   屬性:" + key
                    + " 賦值異常  " + e.getStackTrace());
            throw new Exception("第" + (row + 1) + " 行  " + (column + 1) + "列   屬性:"
                    + key + " 賦值異常  ");
        }

    }

    /**
     * <p>
     * Description:getter(反射get方法得到屬性值)<br />
     * </p>
     * @author likaixuan,wolfgy
     * @version 1.1 2017年9月18日
     * @param obj
     *            反射類對(duì)象
     * @param attrName
     *            屬性名
     * @throws Exception
     * @since JDK 1.7
     */
    public static Object getter(Object obj, String attrName)
            throws Exception {
        try {
            //獲取反射的方法名
            Method method = obj.getClass().getMethod("get" + StringUtil.toUpperCaseFirstOne(attrName));
            Object value = new Object();
            //進(jìn)行反射并獲取返回值
            value = method.invoke(obj);
            return value;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }


    /**
     * 
     * <p>
     * Description:讀取當(dāng)前單元格的值<br />
     * </p>
     * @author likaixuan,wolfgy
     * @version 1.1 2017年9月18日
     * @param cell 單元格對(duì)象
     * @param obj 反射類對(duì)象
     * @param attrName 屬性名
     * @param attrType 屬性類型
     * @param row 當(dāng)前數(shù)據(jù)在Excel中的具體行數(shù)
     * @param col 當(dāng)前數(shù)據(jù)在Excel中的具體列數(shù)
     * @param key 當(dāng)前數(shù)據(jù)對(duì)應(yīng)的Excel列名
     * @throws Exception
     * @since JDK 1.7
     * @return val 當(dāng)前單元格的值
     */
    public static Object getValue(Cell cell, Object obj, String attrName,
            Class<?> attrType, int row, int column, Object key) throws Exception {
        //新建當(dāng)前單元格值對(duì)象
        Object val = null;
        //判斷當(dāng)前單元格數(shù)據(jù)類型并取值
        if (cell.getCellTypeEnum() == CellType.BOOLEAN) {
            val = cell.getBooleanCellValue();

        } else if (cell.getCellTypeEnum() == CellType.NUMERIC) {
            if (DateUtil.isCellDateFormatted(cell)) {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                try {
                    if (attrType == String.class) {
                        val = sdf.format(DateUtil
                                .getJavaDate(cell.getNumericCellValue()));
                    } else {
                        val = StringUtil.dateConvertFormat(
                                sdf.format(DateUtil.getJavaDate(
                                        cell.getNumericCellValue())));
                    }
                } catch (ParseException e) {
                    LOGGER.error("日期格式轉(zhuǎn)換錯(cuò)誤");
                    throw new Exception("第" + (row + 1) + " 行  " + (column + 1)
                            + "列   屬性:" + key + " 日期格式轉(zhuǎn)換錯(cuò)誤  ");
                }
            } else {
                if (attrType == String.class) {
                    cell.setCellType(CellType.STRING);
                    val = cell.getStringCellValue();
                } else if (attrType == BigDecimal.class) {
                    val = new BigDecimal(cell.getNumericCellValue());
                } else if (attrType == long.class) {
                    val = (long) cell.getNumericCellValue();
                } else if (attrType == Double.class) {
                    val = cell.getNumericCellValue();
                } else if (attrType == Float.class) {
                    val = (float) cell.getNumericCellValue();
                } else if (attrType == int.class || attrType == Integer.class) {
                    val = (int) cell.getNumericCellValue();
                } else if (attrType == Short.class) {
                    val = (short) cell.getNumericCellValue();
                } else {
                    val = cell.getNumericCellValue();
                }
            }

        } else if (cell.getCellTypeEnum() == CellType.STRING) {
            val = cell.getStringCellValue();
        }
        return val;
        
    }

    /**
     * 
     * <p>
     * Description:Excel導(dǎo)出<br />
     * </p>
     * @author likaixuan,wolfgy
     * @version 1.1 2017年9月18日
     * @param titleText 標(biāo)題欄內(nèi)容
     * @param out 輸出流
     * @param map  表頭和屬性的Map集合,其中Map中Key為Excel列的名稱络凿,Value為反射類的屬性
     * @param list 要輸出的對(duì)象集合
     * @param classPath 需要映射的model的路徑
     * @param titleStyle 標(biāo)題欄樣式骡送。若為null則直接使用默認(rèn)樣式
     * @param headStyle 表頭樣式。若為null則直接使用默認(rèn)樣式
     * @param dataStyle 數(shù)據(jù)行樣式絮记。若為null則直接使用默認(rèn)樣式
     * @throws Exception
     * @since JDK 1.7
     * void
     */
    public static void exportExcel(String titleText,OutputStream out, Map<String,String> map,List<?> list, String classPath,HSSFCellStyle titleStyle,HSSFCellStyle headStyle,HSSFCellStyle dataStyle) throws Exception {

        //創(chuàng)建單元格并設(shè)置單元格內(nèi)容
        Set<String> keySet = map.keySet();// 返回鍵的集合
        Iterator<String> it = keySet.iterator(); 
        // 創(chuàng)建HSSFWorkbook對(duì)象(excel的文檔對(duì)象)
        HSSFWorkbook workbook = new HSSFWorkbook();
        // 建立新的sheet對(duì)象(excel的表單)
        HSSFSheet sheet = workbook.createSheet("數(shù)據(jù)導(dǎo)出");
        
        // 設(shè)置默認(rèn)列寬為15
        sheet.setDefaultColumnWidth(15);
        // 合并標(biāo)題欄單元格
        sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, keySet.size() - 1));
        // 當(dāng)傳入的標(biāo)題欄樣式為空時(shí)摔踱,創(chuàng)建默認(rèn)標(biāo)題欄樣式
        if (titleStyle == null) {           
            HSSFCellStyle style = workbook.createCellStyle();
            style.setFillForegroundColor(HSSFColorPredefined.SKY_BLUE.getIndex());
            style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
            style.setBorderBottom(BorderStyle.THIN);
            style.setBorderLeft(BorderStyle.THIN);
            style.setBorderRight(BorderStyle.THIN);
            style.setBorderTop(BorderStyle.THIN);
            style.setAlignment(HorizontalAlignment.CENTER);
            style.setVerticalAlignment(VerticalAlignment.CENTER);
            HSSFFont font = workbook.createFont(); 
            font.setColor(HSSFColorPredefined.VIOLET.getIndex());
            font.setFontHeightInPoints((short) 18);
            style.setFont(font);
            titleStyle = style;
        }
        // 當(dāng)傳入的表頭樣式為空時(shí),創(chuàng)建默認(rèn)表頭樣式
        if (headStyle == null) {
            HSSFCellStyle style2 = workbook.createCellStyle();
            style2.setFillForegroundColor(HSSFColorPredefined.GREEN.getIndex());
            style2.setFillPattern(FillPatternType.SOLID_FOREGROUND);
            style2.setBorderBottom(BorderStyle.THIN);
            style2.setBorderLeft(BorderStyle.THIN);
            style2.setBorderRight(BorderStyle.THIN);
            style2.setBorderTop(BorderStyle.THIN);
            style2.setAlignment(HorizontalAlignment.CENTER);
            style2.setVerticalAlignment(VerticalAlignment.CENTER);
            HSSFFont font2 = workbook.createFont();
            font2.setFontHeightInPoints((short) 12);
            style2.setFont(font2);
            headStyle = style2;
        }
        // 當(dāng)傳入的數(shù)據(jù)行樣式為空時(shí)怨愤,創(chuàng)建默認(rèn)數(shù)據(jù)行樣式
        if (dataStyle == null) {
            HSSFCellStyle style3 = workbook.createCellStyle();
            style3.setFillForegroundColor(HSSFColorPredefined.LIGHT_YELLOW.getIndex());
            style3.setFillPattern(FillPatternType.SOLID_FOREGROUND);
            style3.setBorderBottom(BorderStyle.THIN);
            style3.setBorderLeft(BorderStyle.THIN);
            style3.setBorderRight(BorderStyle.THIN);
            style3.setBorderTop(BorderStyle.THIN);
            style3.setAlignment(HorizontalAlignment.CENTER);
            style3.setVerticalAlignment(VerticalAlignment.CENTER);
            dataStyle = style3;
        }
        
        // 創(chuàng)建行派敷、單元格對(duì)象
        HSSFRow row = null;
        HSSFCell cell = null;
        // 寫入標(biāo)題行
        row = sheet.createRow(0);
        row.setHeightInPoints(25);
        cell = row.createCell(0);
        cell.setCellStyle(titleStyle);
        HSSFRichTextString textTitle = new HSSFRichTextString(titleText);
        cell.setCellValue(textTitle);
        
            
        //寫入表頭
        row = sheet.createRow(1);//參數(shù)為行索引(excel的行),可以是0~65535之間的任何一個(gè)
        Map<String,String> attrMap = new HashMap<>();
        int index = 0;      
        while(it.hasNext()){ 
            String key = it.next().toString();
            cell = row.createCell(index);
            cell.setCellValue(key);
            cell.setCellStyle(headStyle);
            attrMap.put(Integer.toString(index++), map.get(key).toString());
        } 
        //寫入數(shù)據(jù)行
        for(int i=2;i<list.size();i++){
            row = sheet.createRow(i);
            for(int j=0;j<map.size();j++){
                //調(diào)用getter獲取要寫入單元格的數(shù)據(jù)值
                Object value = getter(list.get(i), attrMap.get(Integer.toString(j)));
                cell = row.createCell(j);
                cell.setCellValue(value.toString());
                cell.setCellStyle(dataStyle);
            }
        }
        
        // 輸出Excel文件
        try {  
            workbook.write(out);  
            out.flush();
            out.close(); 
            workbook.close();
            LOGGER.info("導(dǎo)出成功!");  
        } catch (IOException e) {  
            LOGGER.info("IOException!導(dǎo)出失斪础篮愉!");  
            e.printStackTrace();  
        }  
        
    }
 

}

StringUtil.java

/**
 * Project Name:excelutil
 * File Name:StringUtil.java
 * Package Name:com.lkx.util
 * Date:2017年6月7日上午9:47:06
 * Copyright (c) 2017~2020, likaixuan@test.com.cn All Rights Reserved.
 *
*/

package com.wolfgy.util;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * ClassName:StringUtil
 * Function: TODO ADD FUNCTION.
 * Reason: TODO ADD REASON.
 * Date:     2017年6月7日 上午9:47:06
 * @author   likaixuan
 * @version  V1.0
 * @since    JDK 1.7
 * @see
 */
public class StringUtil {
    /**
     * 首字母轉(zhuǎn)小寫
     *
     * @param s
     * @return
     */
    public static String toLowerCaseFirstOne(String s) {
        if (Character.isLowerCase(s.charAt(0))) {
            return s;
        } else {
            return (new StringBuilder())
                    .append(Character.toLowerCase(s.charAt(0)))
                    .append(s.substring(1)).toString();
        }
    }

    /**
     * 首字母轉(zhuǎn)大寫
     *
     * @param s
     * @return
     */
    public static String toUpperCaseFirstOne(String s) {
        if (Character.isUpperCase(s.charAt(0))) {
            return s;
        } else {
            return (new StringBuilder())
                    .append(Character.toUpperCase(s.charAt(0)))
                    .append(s.substring(1)).toString();
        }
    }

    /**
     * replace:(替換字符串函數(shù))
     * 
     * @param strSource
     *            源字符串
     * @param strFrom
     *            要替換的子串
     * @param strTo
     *            替換為的字符串
     * @return
     * @since JDK 1.7
     */
    public static String replace(String strSource, String strFrom,
            String strTo) {
        // 如果要替換的子串為空,則直接返回源串
        if (strFrom == null || strFrom.equals(""))
            return strSource;
        String strDest = "";
        // 要替換的子串長(zhǎng)度
        int intFromLen = strFrom.length();
        int intPos;
        // 循環(huán)替換字符串
        while ((intPos = strSource.indexOf(strFrom)) != -1) {
            // 獲取匹配字符串的左邊子串
            strDest = strDest + strSource.substring(0, intPos);
            // 加上替換后的子串
            strDest = strDest + strTo;
            // 修改源串為匹配子串后的子串
            strSource = strSource.substring(intPos + intFromLen);
        }
        // 加上沒有匹配的子串
        strDest = strDest + strSource;
        // 返回
        return strDest;
    }
    
    /**
     * String類型日期轉(zhuǎn)為Date類型
     *
     * @param dateStr
     * @return
     * @throws ParseException
     * @throws Exception
     */
    public static Date dateConvertFormat(String dateStr) throws ParseException {
        Date date = new Date();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        date = format.parse(dateStr);
        return date;
    }
}

Student.java

package com.wolfgy.domain;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

import org.hibernate.annotations.GenericGenerator;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Entity
@NoArgsConstructor
@Getter
@Setter
public class Student implements Serializable{

    /** 
     * @fields serialVersionUID 
     */ 
    
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(generator = "idGenerator")
    @GenericGenerator(name = "idGenerator", strategy = "uuid")
    private String id;
    private String sName;
}

StudentService.java

//其余代碼略差导,只貼出導(dǎo)入導(dǎo)出相關(guān)方法

@Override
   public void exportExcel(String[] ids, OutputStream out) {

       String keyValue="學(xué)生ID:id,學(xué)生姓名:sName";
       List<Student> list = new ArrayList<>();
       for (int i = 0; i < ids.length; i++) {
           Student student = repository.findOne(ids[i]);
           
           list.add(student);
       }
       try {
           ExcelUtil.exportExcel("學(xué)生數(shù)據(jù)導(dǎo)出", out, ExcelUtil.getMap(keyValue), list, "com.wolfgy.domain.Student", null, null, null);
           logger.info("導(dǎo)出成功!");
       } catch (Exception e) {
           e.printStackTrace();
           logger.info("導(dǎo)出失敗!");
       }
   }


   @Override
   public void importExcel(String fileName,InputStream in) {
       logger.info("導(dǎo)入"+fileName+"開始");
       String keyValue="學(xué)生ID:id,學(xué)生姓名:sName";
       List<Student> list = null;
       try {
           //readExcel參數(shù)列表
           //fileName Excel文件名
           //inputStream 輸入流
           //map 表頭和屬性的Map集合,其中Map中Key為Excel列的名稱试躏,Value為反射類的屬性
           //classPath 需要映射的model的路徑
           //rowNumIndex 表頭所在行數(shù)
           list = ExcelUtil.readExcel("student.xlsx",in,ExcelUtil.getMap(keyValue),
                   "com.wolfgy.domain.Student",1);
           logger.info(" 導(dǎo)入成功!");
       } catch (Exception e) {
           logger.error("導(dǎo)入失敗!");
       }
       for (Student student : list) {
           logger.info("-------------");
           logger.info("name:"+student.getSName());
       
           
       }
       logger.info(" 導(dǎo)入結(jié)束!");
   }

AssociationController.java

//其余代碼略,只貼出導(dǎo)入導(dǎo)出相關(guān)方法

    @RequestMapping(value = "/student/export" , method = RequestMethod.GET)
    public void exporMemberFormExcel(@RequestParam(value = "ids", defaultValue = "", required = false) String[] ids, HttpServletResponse res) throws IOException {
        logger.info("---------------導(dǎo)出列表到Excel--------------------");
        res.setContentType("application/msexcel;charset=UTF-8");
        res.addHeader("Content-Disposition", "attachment;filename=members.xls");
        OutputStream out = res.getOutputStream();
        studentService.exportExcel(ids, out);       
    }
    
    
     @RequestMapping(value="/studen/ajaxUpload.do",method=RequestMethod.POST) 
     public void ajaxUploadExcel(@RequestParam("file") MultipartFile file) throws Exception{
         if(!file.isEmpty()){       
                InputStream in = file.getInputStream();
                String fileName = file.getName();
                studentService.importExcel(fileName,in);    
                
            }else{
                throw new BizException("上傳失敗设褐,因?yàn)槲募强盏?);
            }
        
         
     }

以上颠蕴。
希望我的文章對(duì)你能有所幫助泣刹。
我不能保證文中所有說(shuō)法的百分百正確,但我能保證它們都是我的理解和感悟以及拒絕復(fù)制黏貼犀被。
有什么意見椅您、見解或疑惑,歡迎留言討論寡键。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末掀泳,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子西轩,更是在濱河造成了極大的恐慌开伏,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件遭商,死亡現(xiàn)場(chǎng)離奇詭異固灵,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)劫流,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門巫玻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人祠汇,你說(shuō)我怎么就攤上這事仍秤。” “怎么了可很?”我有些...
    開封第一講書人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵诗力,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我我抠,道長(zhǎng)苇本,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任菜拓,我火速辦了婚禮瓣窄,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘纳鼎。我一直安慰自己俺夕,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開白布贱鄙。 她就那樣靜靜地躺著劝贸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪逗宁。 梳的紋絲不亂的頭發(fā)上映九,一...
    開封第一講書人閱讀 52,156評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音疙剑,去河邊找鬼氯迂。 笑死践叠,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的嚼蚀。 我是一名探鬼主播禁灼,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼轿曙!你這毒婦竟也來(lái)了弄捕?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤导帝,失蹤者是張志新(化名)和其女友劉穎守谓,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體您单,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡斋荞,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了虐秦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片平酿。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖悦陋,靈堂內(nèi)的尸體忽然破棺而出蜈彼,到底是詐尸還是另有隱情,我是刑警寧澤俺驶,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布幸逆,位于F島的核電站,受9級(jí)特大地震影響暮现,放射性物質(zhì)發(fā)生泄漏还绘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一送矩、第九天 我趴在偏房一處隱蔽的房頂上張望蚕甥。 院中可真熱鬧哪替,春花似錦栋荸、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至帅霜,卻和暖如春匆背,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背身冀。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工钝尸, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留括享,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓珍促,卻偏偏與公主長(zhǎng)得像铃辖,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子猪叙,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359

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