1. 程式人生 > >SpringBoot通過WorkBook快速實現對Excel的匯入和匯出(包括資料校驗)

SpringBoot通過WorkBook快速實現對Excel的匯入和匯出(包括資料校驗)

之前轉載過一篇對Excel基本操作相關的文章,這篇文章的瀏覽量迅速飆升,以至於在我部落格的熱門文章中排到了第三的位置,不過那篇轉載的文章實用性差並且講解不是很清晰,所以打算趁著今天休息,寫一篇關於SpringBoot通過WorkBook快速實現對Excel的匯入、匯出、資料校驗的文章,也是便於日後查閱。

1、引入依賴

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

 

2、Excel型別列舉

/**
 * @Description:Excel型別列舉
 * @Author:zhangzhixiang
 * @CreateDate:2018/08/31 13:59:48
 * @Version:1.0
 */
@Data
public enum ExcelTypeEnum {
    
    /**
     * 報備匯入
     */
    REPORT_TYPE(BatchImportConsts.EXCEL_REPORT_MODEL_TYPE, new BatchImportStruBO(BatchImportConsts.excel_report_titles, new ReportRecordCheck(), SpringHelper.getBeanByClass(ReportInsertServiceImpl.class))),
    /**
     * 線索匯入
     */
    CLUE_TYPE(BatchImportConsts.EXCEL_CLUE_MODEL_TYPE, new BatchImportStruBO(BatchImportConsts.excel_clue_titles, new ClueRecordCheck(), SpringHelper.getBeanByClass(ClueInsertServiceImpl.class)));

    private String type;
    private BatchImportStruBO struBO;

    ExcelTypeEnum(String type, BatchImportStruBO struBO) {
        this.type = type;
        this.struBO = struBO;
    }

    /**
     * 判斷key對應的列舉是否存在,若存在,返回此列舉;否則返回null
     *
     * @param key
     * @return
     */
    public static ExcelTypeEnum containKey(String key) {
        ExcelTypeEnum type = null;
        switch (key) {
            case "report":
                type = ExcelTypeEnum.REPORT_TYPE;
                break;
            case "clue":
                type = ExcelTypeEnum.CLUE_TYPE;
                break;
            default:
                type = null;
                break;
        }
        return type;
    }
}

3、批量匯入Excel資料結構

/**
 * @Description:批量匯入Excel資料結構資訊
 * @Author:zhangzhixiang
 * @CreateDate:2018/09/05 19:54:32
 * @Version:1.0
 */
@Data
public class BatchImportStruBO {
    
    /**
     * Excel欄位與db欄位關係
     */
    private List<BaseColumn> importTitles;
    /**
     * 記錄校驗器
     */
    private BaseRecordCheck recordCheck;
    /**
     * 入表處理器
     */
    private BaseInsertService insertHandle;

    public BatchImportStruBO(List<BaseColumn> importTitles, BaseRecordCheck recordCheck, BaseInsertService insertHandle) {
        this.importTitles = importTitles;
        this.recordCheck = recordCheck;
        this.insertHandle = insertHandle;
    }

}

4、Excel單元格

/**
 * @Description:Excel單元格實體
 * @Author:zhangzhixaing
 * @CreateDate:2018/08/31 16:39:45
 * @Version:1.0
 */
@Data
public class BaseColumn {
    
    /**
     * 常量定義
     */
    public static final Boolean TRUE = true;
    public static final Boolean FALSE = false;

    /**
     * Excel中對應的欄位名稱
     */
    protected String excelName;
    /**
     * Excel欄位值
     */
    protected String excelValue;
    /**
     * 是否必填
     */    
    protected Boolean isRequired;
    /**
     * 值得校驗是否成功,預設true
     */
    protected boolean checkIsSuccess = true;
    /**
     * 校驗結果資訊
     */
    protected String checkMessage;
    
    public BaseColumn() {
        super();
    }

    public BaseColumn(String excelName, Boolean isRequired) {
        super();
        this.excelName = excelName;
        this.isRequired = isRequired;
    }

    public BaseColumn(String excelName) {
        super();
        this.excelName = excelName;
    }
}

5、 Excel匯入相關配置

/**
 * Excel匯入相關配置
 *
 * @author zhangzhixiang
 * @data 2018/09/18 11:48:59
 */
public class BatchImportConsts {

    /**
     * Excel匯入模式
     */
    public static String EXCEL_CLUE_MODEL_TYPE = "clue";
    public static String EXCEL_REPORT_MODEL_TYPE = "report";
   
    /**
     * 報備批量匯入Excel標題對映資訊
     */    
    public static List<BaseColumn> excel_report_titles;
    /**
     * 線索批量匯入Excel標題對映資訊
     */     
    public static List<BaseColumn> excel_clue_titles;

    /**
     * 報備匯入Excel標題
     */    
    public static final String EXCEL_REPORT_RECORD_COLUMN_PROVINCE = "省";
    public static final String EXCEL_REPORT_RECORD_COLUMN_CITY = "市";
    public static final String EXCEL_REPORT_RECORD_COLUMN_AREA = "區";
    public static final String EXCEL_REPORT_RECORD_COLUMN_CUSTOMER_SOURCE = "客戶來源(單位名稱)";
    public static final String EXCEL_REPORT_RECORD_COLUMN_ITEM = "專案歸屬";
    public static final String EXCEL_REPORT_RECORD_COLUMN_DATA_CONTENT_DESC = "資料內容描述";
    public static final String EXCEL_REPORT_RECORD_COLUMN_DATA_NUM = "資料數量";
    public static final String EXCEL_REPORT_RECORD_COLUMN_DATA_PURPOSE = "資料用途";

    /**
     * 線索匯入Excel標題
     */
    public static final String EXCEL_CLUE_RECORD_COLUMN_CLUE_SOURCE = "線索來源地";
    public static final String EXCEL_CLUE_RECORD_COLUMN_ITEM = "歸屬專案";
    public static final String EXCEL_CLUE_RECORD_COLUMN_TAG = "線索標籤";
    public static final String EXCEL_CLUE_RECORD_COLUMN_NAME = "線索名稱";
    public static final String EXCEL_CLUE_RECORD_COLUMN_DESC = "線索內容";
    public static final String EXCEL_CLUE_RECORD_COLUMN_CLUE_REMARK = "線索備註";
    public static final String EXCEL_CLUE_RECORD_COLUMN_PERSON_NUM = "人數";
    public static final String EXCEL_CLUE_RECORD_COLUMN_PERSON_NAME = "姓名";
    public static final String EXCEL_CLUE_RECORD_COLUMN_ID_CARD = "身份證號";
    public static final String EXCEL_CLUE_RECORD_COLUMN_IPHONE = "手機號";
    public static final String EXCEL_CLUE_RECORD_COLUMN_SEX = "性別";
    public static final String EXCEL_CLUE_RECORD_COLUMN_NATION = "名族";
    
    /**
     * 報備配置(標題頭+是否必填)
     */
    static {
        excel_report_titles = new ArrayList<>();
        excel_report_titles.add(new BaseColumn(EXCEL_REPORT_RECORD_COLUMN_PROVINCE, BaseColumn.TRUE));
        excel_report_titles.add(new BaseColumn(EXCEL_REPORT_RECORD_COLUMN_CITY, BaseColumn.FALSE));
        excel_report_titles.add(new BaseColumn(EXCEL_REPORT_RECORD_COLUMN_AREA, BaseColumn.FALSE));
        excel_report_titles.add(new BaseColumn(EXCEL_REPORT_RECORD_COLUMN_CUSTOMER_SOURCE, BaseColumn.TRUE));
        excel_report_titles.add(new BaseColumn(EXCEL_REPORT_RECORD_COLUMN_ITEM, BaseColumn.TRUE));
        excel_report_titles.add(new BaseColumn(EXCEL_REPORT_RECORD_COLUMN_DATA_CONTENT_DESC, BaseColumn.TRUE));
        excel_report_titles.add(new BaseColumn(EXCEL_REPORT_RECORD_COLUMN_DATA_NUM, BaseColumn.FALSE));
        excel_report_titles.add(new BaseColumn(EXCEL_REPORT_RECORD_COLUMN_DATA_PURPOSE, BaseColumn.FALSE));
    }

    /**
     * 線索配置(標題頭+是否必填)
     */
    static {
        excel_clue_titles = new ArrayList<>();
        excel_clue_titles.add(new BaseColumn(EXCEL_CLUE_RECORD_COLUMN_CLUE_SOURCE, BaseColumn.FALSE));
        excel_clue_titles.add(new BaseColumn(EXCEL_CLUE_RECORD_COLUMN_ITEM, BaseColumn.FALSE));
        excel_clue_titles.add(new BaseColumn(EXCEL_CLUE_RECORD_COLUMN_TAG, BaseColumn.FALSE));
        excel_clue_titles.add(new BaseColumn(EXCEL_CLUE_RECORD_COLUMN_NAME, BaseColumn.FALSE));
        excel_clue_titles.add(new BaseColumn(EXCEL_CLUE_RECORD_COLUMN_DESC, BaseColumn.FALSE));
        excel_clue_titles.add(new BaseColumn(EXCEL_CLUE_RECORD_COLUMN_CLUE_REMARK, BaseColumn.FALSE));
        excel_clue_titles.add(new BaseColumn(EXCEL_CLUE_RECORD_COLUMN_PERSON_NUM, BaseColumn.FALSE));
        excel_clue_titles.add(new BaseColumn(EXCEL_CLUE_RECORD_COLUMN_PERSON_NAME, BaseColumn.FALSE));
        excel_clue_titles.add(new BaseColumn(EXCEL_CLUE_RECORD_COLUMN_ID_CARD, BaseColumn.TRUE));
        excel_clue_titles.add(new BaseColumn(EXCEL_CLUE_RECORD_COLUMN_IPHONE, BaseColumn.FALSE));
        excel_clue_titles.add(new BaseColumn(EXCEL_CLUE_RECORD_COLUMN_SEX, BaseColumn.FALSE));
        excel_clue_titles.add(new BaseColumn(EXCEL_CLUE_RECORD_COLUMN_NATION, BaseColumn.FALSE));
    }
}

6、行校驗介面

/**
 * @Description:行校驗介面
 * @Author:zhangzhixiang
 * @CreateDate:2018/08/31 21:56:32
 * @Version:1.0
 */
public interface BaseRecordCheck {

    /**
     * 記錄校驗
     *
     * @param cells
     * @return 
     * @throws Exception
     */
    List<BaseColumn> valueCheck(List<BaseColumn> cells) throws Exception;

}

7、線索行校驗實現

/**
 * @Description:線索行校驗
 * @Author:zhangzhixiang
 * @CreateDate:2018/08/31 12:59:48
 * @Version:1.0
 */
public class ClueRecordCheck implements BaseRecordCheck {
    
    @Override
    public List<BaseColumn> valueCheck(List<BaseColumn> cells) throws Exception {
        //欄位校驗
        for (BaseColumn column : cells) {
            switch (column.getExcelName()) {
                case BatchImportConsts.EXCEL_CLUE_RECORD_COLUMN_NAME:
                    new BaseCheck().valueCheck(column);
                    break;
                case BatchImportConsts.EXCEL_CLUE_RECORD_COLUMN_ID_CARD:
                    new ClueIdcardCheck().valueCheck(column);
                    break;
                case BatchImportConsts.EXCEL_CLUE_RECORD_COLUMN_IPHONE:
                    new CluePhoneCheck().valueCheck(column);
                    break;
                case BatchImportCONsts.EXCEL_CLUE_RECORD_COLUMN_SEX:
                    new ClueSexCheck().valueCheck(column);
                    break;
                default:
                    break;
            }
        }
        return cells;
    }
}

8、列校驗介面

/**
 * @Description:列校驗介面
 * @Author:zhangzhixiang
 * @CreateDate:2018/08/31 21:56:34
 * @Version:1.0
 */
public interface BaseColumnCheck {
    
    /**
     * 校驗欄位值
     * 
     * @param cell
     * @return
     * @throws Exception
     */
    BaseColumn valueCheck(BaseColumn cell) throws Exception;

    /**
     * 多欄位聯合校驗
     * 
     * @param cells
     * @return
     * @throws Exception
     */
    List<BaseColumn> valueCheck(List<BaseColumn> cells) throws Exception;

}

9、線索列校驗實現(基礎非空校驗)

/**
 * @Description:基礎非空校驗
 * @Author:zhangzhixiang
 * @CreateDate:2018/08/31 21:59:43
 * @Version:1.0
 */
public class BaseCheck implements BaseColumnCheck {

    private static final String EMPTY_MESSAGE = "不能為空;"

    @Override
    public BaseColumn valueCheck(BaseColumn cell) throws Exception {
        if (StringUtils.isBlank(cell.getExcelValue())) {
            cell.setCheckIsSuccess(false);
            cell.setCheckMessage((cell.getCheckMessage() == null ? "" : cell.getCheckMessage()) + cell.getExcelName() + EMPTY_MESSAGE);
        } else {
            cell.setCheckIsSuccess(true);
        }
        return cell;
    }

    @Override
    public List<BaseColumn> valueCheck(List<BaseColumn> cells) throws Exception {
        return null;
    }
}

10、線索列校驗實現(身份證號校驗)

/**
 * @Description:身份證號校驗
 * @Author:zhangzhixiang
 * @CreateDate:2018/08/31 21:59:43
 * @Version:1.0
 */
public class ClueIdcardCheck implements BaseColumnCheck {

    private static final String EMPTY_MESSAGE = "不能為空;"

    private static final String WRONG_MESSAGE = "格式不對;"

    @Override
    public BaseColumn valueCheck(BaseColumn cell) throws Exception {
        if(cell.getRequired() || (!cell.getRequired() && StringHelper,isNotBlankAnyWay(cell.getExcelValue()))) {
            cell.setCheckIsSuccess(false);
            cell.setCheckMessage((cell.getCheckMessage() == null ? "" : cell.getCheckMessage()) + cell.getExcelName() + EMPTY_MESSAGE);
        } else {
            //校驗身份證號合法性
            String reg = "^\\d{15}$|^\\d{17}[0-9Xx]$";
            if(!cell.getExcelValue.matches(reg)) {
                cell.setCheckIsSuccess(false);
                cell.setCheckMessage((cell.getCheckMessage() == null ? "" : cell.getCheckMessage()) + cell.getExcelName() + WRONG_MESSAGE);
            }
        }
        return cell;
    }

    @Override
    public List<BaseColumn> valueCheck(List<BaseColumn> cells) throws Exception {
        return null;
    }
}

11、線索列校驗實現(手機號校驗)

/**
 * @Description:手機號校驗
 * @Author:zhangzhixiang
 * @CreateDate:2018/08/31 21:59:43
 * @Version:1.0
 */
public class CluePhoneCheck implements BaseColumnCheck {

    private static final String EMPTY_MESSAGE = "不能為空;"

    private static final String WRONG_MESSAGE = "格式不對;"

    private Pattern p = Pattern.compile("^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$");

    @Override
    public BaseColumn valueCheck(BaseColumn cell) throws Exception {
        if(cell.getRequired() || (!cell.getRequired() && StringHelper,isNotBlankAnyWay(cell.getExcelValue()))) {
            cell.setCheckIsSuccess(false);
            cell.setCheckMessage((cell.getCheckMessage() == null ? "" : cell.getCheckMessage()) + cell.getExcelName() + EMPTY_MESSAGE);
        } else {
            //校驗手機號合法性
            Matcher m = p.matcher(cell.getExcelValue());
            if(!m.matches()) {
                cell.setCheckIsSuccess(false);
                cell.setCheckMessage((cell.getCheckMessage() == null ? "" : cell.getCheckMessage()) + cell.getExcelName() + WRONG_MESSAGE);
            }
        }
        return cell;
    }

    @Override
    public List<BaseColumn> valueCheck(List<BaseColumn> cells) throws Exception {
        return null;
    }
}

12、線索列校驗實現(性別校驗)

/**
 * @Description:性別校驗
 * @Author:zhangzhixiang
 * @CreateDate:2018/08/31 21:59:43
 * @Version:1.0
 */
public class ClueSexCheck implements BaseColumnCheck {

    private static final String EMPTY_MESSAGE = "不能為空;"

    private static final String WRONG_MESSAGE = "格式不對;"

    private String man = "男";

    private String women = "女";

    @Override
    public BaseColumn valueCheck(BaseColumn cell) throws Exception {
        if(cell.getRequired() || (!cell.getRequired() && StringHelper,isNotBlankAnyWay(cell.getExcelValue()))) {
            cell.setCheckIsSuccess(false);
            cell.setCheckMessage((cell.getCheckMessage() == null ? "" : cell.getCheckMessage()) + cell.getExcelName() + EMPTY_MESSAGE);
        } else {
            //校驗手機號合法性
            Matcher m = p.matcher(cell.getExcelValue());
            if(!m.matches()) {
                if(!(man.equals(cell.getExcelValue()) || women.equals(cell.getExcelValue()))) {
                    cell.setCheckIsSuccess(false);
                    cell.setCheckMessage((cell.getCheckMessage == null ? "" : cell.getCheckMessage()) + cell.getExcelName() + WRONG_MESSAGE);
                }
            }
        }
        return cell;
    }

    @Override
    public List<BaseColumn> valueCheck(List<BaseColumn> cells) throws Exception {
        return null;
    }
}

13、Excel入庫介面

/**
 * @Description:Excel入庫介面
 * @Author:zhangzhixiang
 * @CreateDate:2018/08/31 21:59:43
 * @Version:1.0
 */
public interface BaseInsertService {

    /**
     * Excel資料入庫
     *
     * @param rows Excle資料
     * @param isSuccess
     * @author zhangzhixiang
     * @data 2018/09/19 18:56:43
     */
    void insertDB(List<List<BaseColumn>> rows, Boolean isSuccess) throws Exception;
     
}

14、Excel入庫實現(線索)

/**
 * @Description:Excel線索入庫介面
 * @Author:zhangzhixiang
 * @CreateDate:2018/08/31 21:59:43
 * @Version:1.0
 */
@Service
public class ClueInsertServiceImpl implements BaseInsertService {

    @Autowired
    public ClueInfoDAO clueInfoDAO;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertDB(List<List<BaseColumn>> rows, Boolean isSuccess) throws Exception {
        //線索自定義入庫程式碼
    }

}

15、Excel公共服務介面(OSS)

/**
 * @Description:Excel服務介面(OSS)
 * @Author:zhangzhixiang
 * @CreateDate:2018/08/31 21:59:43
 * @Version:1.0
 */
public interface ExcelOperateService {
    
    /**
     * Excel檔案匯入
     * @param fileName 原檔名
     * @param code 檔案唯一標示
     * @param model Excel型別標識
     * @return 解析結果
     * @throws Exception
     */
    ExcelParseResultBO excelImport(String code, String model) throws Exception;

    /**
     * Excel檔案匯出
     * @param fileName 原檔名
     * @param code 檔案唯一標示
     * @param model Excel型別標識
     * @return 解析結果
     * @throws Exception
     */
    void excelExport(HttpServletResponse response, List<List<String>> rows, String fileName, String sheetName) throws Exception;
}

16、Excel公共服務實現(OSS)

/**
 * @Description:Excel公共服務實現(OSS)
 * @Author:zhangzhixiang
 * @CreateDate:2018/08/31 21:59:43
 * @Version:1.0
 */
@Service
public class ExcelOperateServiceImpl implements ExcelOperateService {

    private static final Logger logger = LoggerFactory.getLogger(ExcelOperateServiceImpl.class);
    
    private static final String SERVICE_ERROR_MESSAGE = "批量匯入失敗";

    /**
     * Excel檔案匯入
     *
     * @param code OSS檔案唯一標示
     * @param model 業務型別(clue、report)
     * @return 解析結果
     * @throws Exception
     */
    @Override
    public ExcelOperateBO excelImport(String code, String model) {
        FileClient client = ClientFactory.createClientByType(BootstrapConsts.file_client_type);
        ExcelOperateBO resultBO = null;
        //1、獲取Excel資料
        List<List<String>> excelDatas = null;
        excelDatas = ExcelRead.getSheetDataWithTitle(client.getFileStream(code), code, null);
        if(null == excelDatas || excelDatas.size() < SimpleConsts.TWO) {
            message = "檔案無有效資料";
            resultBO = new ExcelOperateBO();
            resultBO.setFileOK(false);
            resultBO.setMessage(message);
            return resultVO;
        }
        logger.info("記錄數量:" + excelDatas.size());

         //2、校驗標題合法性
        resultBO = excelTitleCheck(excelDatas.get(0), model);
        if(!resultBO.getFileOK) {
            return resultBO;
        }

        //3、將Excel中的每列資料與title名稱繫結
        List<List<BaseColumn>> excelRows = null;
        excelRows = getExcelData(excelDatas, model);
        if(null == excelRows || excelRows.size() == 0) {
            resultBO = new ExcelOperateBO();
            resultBO.setTotalNum(0);
            resultBO.setSuccessNum(0);
            resultBO.setFailNum(0);
            resultBO.setFileOK(true);
            return resultVO;
        }

        //4、Excel資料校驗
        List<List<BaseColumn>> successRows = new ArrayList<>();
        List<List<BaseColumn>> failRows = new ArrayList<>();
        rowsCheck(excelRows, model, successRows, failRows);

        //5、入庫
        if(successRows.size() > 0) {
            insertdb(successRows, model, true);
        }
        if(failRows.size() > 0) {
            insertdb(failRows, model, false);
        }
    } 

    /**
     * Excel檔案匯出
     *
     * @param response
     * @param rows 匯出檔案內容(包括標題)
     * @param fileName 匯出檔名
     * @param sheetName sheet名稱
     * @return 解析結果
     * @throws Exception
     */
    @Override
    public void excelExport(HttpServletResponse response, List<List<String>> rows, String fileName, String sheetName) throws Exception {
        ExcelWrite.exportExcle(response, rows, fileName, sheetName);
    }

    /**
     * 資料入庫
     *
     * @param rows 待寫入的資料
     * @param model 業務型別(clue、report)
     * @param isSuccess 是否成功
     */
    private void insertdb(List<List<BaseColumn>> rows, String model, Boolean isSuccess) throws Exception {
        BatchImportStruBO struBO = ExcelTypeEnum.containKey(model).getStruBO();
        BaseInsertService insertHandle = struBO.getInsertHandle();
        insertHandle.insertDB(rows, isSuccess);
    }   

    /**
     * Excek資料校驗
     *
     * @param excelRows 待校驗資料
     * @param model 業務型別(clue、report)
     * @param successRows 校驗成功的資料
     * @param failRows 校驗失敗的資料
     */
    private void rowsCheck(List<List<BaseColumn>> rows, String model, List<List<BaseColumn>> successRows, List<List<BaseColumn>> failRows) throws Exception {
        BaseRecordCheck recordCheck = ExcelTypeEnum.containKey(model).getStruBO().getRecordCheck();
        List<BaseCOlumn> checkedRow = null;
        boolean isSuccessCheck = true;
        for (List<BaseColumn> rowData : excelRows) {
            checkedRow = recordCheck.valueCheck(rowData);
            if(checkedRow == null || checkedRow.size() == 0) {
                continue;
            }
            for (BaseColumn cell : checkedRow) {
                if (!cell.isCheckIsSuccess()) {
                    isSuccessCheck = cell.isCheckIsSuccess();
                    break;
                }
            }
            if(!isSuccessCheck) {
                failRows.add(checkRow);
            } else {
                successRows.add(checkedRow);
            }
            isSuccessCheck = true;
        }
    }   

    /**
     * 獲取Excel有效資料(將title與Excel資料繫結)
     *
     * @param excelRows Excel資料
     * @return
     * @throws Exception
     */  
    private List<List<BaseColumn>> getExcelData(List<List<String>> excelDatas, String model) throws Exception {
        BatchImportStruBO batchImportStruBO = ExcelTypeEnum.containKey(model).getStruBO();
        List<BaseColumn> titles = batchImportStruBO.getImportTitles();
        excelDatas.remove(0);
        for(int i = 0; i<excelDatas.size(); i++) {
            List<String> row = valueTrim(excelDatas.get(i));
            excelDatas.set(i, row);
        }
        List<List<BaseColumn>> excelRows = excelDataTidy(titles, excelDatas);
        if (null == excelRows) {
            throw new Exception("excelDatas資料轉為excelRows資料報錯");
        }
        return excelRows;
    }

    /**
     * 將標題和具體的資料組合
     * 
     * @param titles 標題資訊
     * @param rowList 記錄資料,其中記錄的欄位索引與對應的標題索引一致
     * @return
     */
    private List<List<BaseColumn>> excelDataTidy(List<BaseColumn> titles, List<List<String>> rowList) {
        List<List<BaseColumn>> datas = new ArrayList<>();
        List<BaseColumn> rowData = null;
        BaseColumn cellData = null;
        List<String> excelRow = null;
        for(int i = 0; i < rowList.size(); i++) {
            rowData = new ArrayList<>();
            excelRow = rowList.get(i);
            for(int j = 0; j < excelRow.size(); j++) {
                String excelCellValue = excelRow.get(j);
                String title = null;
                if(j < titles.size()) {
                    title = titles.get(j).getExcelName();
                } else {
                    break;
                }
                cellData = new BaseColumn();
                cellData.setExcelName(title);
                cellData.setRequired(titles.get(j).getRequired());
                cellData.setExcelValue(excelCellValue);
                rowData.add(cellData);
            }
            datas.add(rowData);
        }
        return datas;
    }

    /**
     * 校驗標題是否合規
     * 
     * @param titles 標題資訊
     * @param model 業務型別(clue、report)
     * @return
     */
    private ExcelOperateBO excelTitleCheck(List<String> titles, String model) throws Exception {
        BatchImprtStruBO batchImportStruBO = ExcelTypeEnum.containKey(model).getStruBO();
        String message = "解析標題報錯";
        titles = valueTrim(titles);
        List<BaseColumn> orderTitles = batchImportStruBO.getImportTitles();
        boolean  titleCheck = titleCheck(titles, orderTitles);
        if (!titleCheck) {
            throw new Exception(message);
        }
        ExcelOperateBO resultBO= new ExcelOperateBO();
        resultBO.setFileOK(true);
        return resultBO;
    }

    /**
     * 校驗Excel中標題是否包含所需要的標題
     * 
     * @param titles 標題資訊
     * @param orderTitles 要求的標題資訊
     * @return
     */
    private boolean titleCheck(List<String> titles, List<BaseColumn> orderTitles) {
        if (null == titles || titles.size() == 0) {
            return false;
        }
        if(null == orderTitles || orderTitles.size() == 0) {
            return false;
        }
        List<String> names = new ArrayList<>();
        for (BaseColumn column : orderTitles) {
            names.add(column.getExcelName());
        }
        for (String name : names) {
            if(!titles.contains(name)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 去除首尾無效空格
     * 
     * @param values 要去空格的字串
     * @return
     */
    private List<String> valueTrim(List<String> values) {
        if(null == values || values.size() == 0) {
            return values;
        }
        for(int i=0; i < values.size(); i++) {
            if(StringUtils.isBlank(values.get(i))) {
                values.set(i, null);
                continue;
            } else {
                values.set(i, values.get(i).trim());
            }
        }
        return values;
    }
}

17、Excel基礎操作

/**
 * @Description:Excel基礎操作
 * @Author:zhangzhixiang
 * @CreateDate:2018/08/31 21:59:43
 * @Version:1.0
 */
public class ExcelBaseOperate {
    
    pricate static final Logger logger = LoggerFactory.getLogger(ExcelBaseOperate.class);

    private static final String SUFFIX_XLS = "xls";
    private static final String SUFFIX_XLSX = "xlsx";

    /**
     * 獲取Excel操作類
     *
     * @param inputStream
     * @param name
     * @return
     * @throws Exception
     */
    public static Workbook getWorkbook(InputStream inputStream, String name) throws Exception {
        Workbook wb = null;
        if (name.endsWith(SUFFIX_XLSX)) {
            wb = new XSSWorkbook(OPCPackage.open(inputStream));
        } else if (name.endsWith(SUFFIX_XLS)) {
            wb = (HSSFWorkbook)WorkbookFactory.create(inputStream);
        } else {
            String errorMessage = "無法識別的檔案型別。檔名稱:" + name;
            logger.error(errorMessage);
            throw new Exception(errorMessage);
        }
        return wb;
    }

}

18、Excel讀取操作

/**
 * @Description:Excel讀取操作
 * @Author:zhangzhixiang
 * @CreateDate:2018/08/31 21:59:43
 * @Version:1.0
 */
public class ExcelRead {

    private static final Logger logger = LoggerFactory.getLogger(ExcelRead.class);

    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * 獲取sheet頁標題
     *
     * @param inputStream Excel檔案流
     * @param excelName Excel檔名
     * @param sheetName sheet頁名稱。不輸入則預設取第一個sheet
     * @return
     */
    public static List<String> getSheetTitle(InputStream inputStream, String excelName, String sheetName) throws Exception {
        Workbook workbook = ExcelBaseOperate.getWorkbook(inputStream, excelName);
        //沒有輸入sheetname,則預設第一個sheet
        if (StringUtils.isBlank(sheetName)) {
            sheetName = workbook.getSheetAt(0).getSheetName();
        }
        List<List<String>> sheetData = parseSheet(workbook, sheetName, 0, 0);
        if(null == sheetData || sheetData.size() == 0) {
            return null;
        }
        return sheetData.get(0);
    }

    /**
     * 獲取帶標題的sheet頁資料
     *
     * @param inputStream Excel檔案流
     * @param excelName Excel檔名
     * @param sheetName sheet頁名稱。不輸入則預設取第一個sheet
     * @return
     */
    public static List<String> getSheetTitle(InputStream inputStream, String excelName, String sheetName) throws Exception {
        Workbook workbook = ExcelBaseOperate.getWorkbook(inputStream, excelName);
        //沒有輸入sheetname,則預設第一個sheet
        if (StringUtils.isBlank(sheetName)) {
            sheetName = workbook.getSheetAt(0).getSheetName();
        }
        List<List<String>> sheetData = parseSheet(workbook, sheetName, 0, workbook.getSheet(sheetName).getPhysicalNumberOfRows());
        return sheetData;
    }

    /**
     * 解析sheet頁資料
     *
     * @param wb Excel檔案
     * @param sheetName sheet頁名稱
     * @param startIndex 解析的起始row,從0開始,包含此row
     * @param endIndex 解析的終止row,從0開始,包含此row
     * @return 第一層list:row;第二層list:cell
     */
    private static List<List<String>> parseSheet(Workbook wb, String sheetName, int start
Index, int endIndex) throws Exception {
        String message = null;
        Sheet sheet = wb.getSheet(sheetName);
        if(null == sheet) {
            message = sheetName + ",此sheet頁不存在";
            throw new Exception(message);
        }
        int lastRowNum = sheet.getPhysicalNumberOfRows();
        if(startIndex < 0 || endIndex > lastRowNum || startIndex > endIndex) {
            message = "輸入的解析row範圍錯誤。startIndex:" + startIndex + ",endIndex:" + endIndex;
            throw new Exception(message);
        }
        List<List<String>> sheetData = new ArrayList<>();
        int cellCount = -1;
        //row list
        for (int i = startIndex; i < endIndex; i++) {
            Row row = sheet.getRow(i);
            if(null == row) {
                continue;
            }
            List<String> rowData = new ArrayList<>();
            cellCount = row.getLastCellNum();
            //cell list
            for(int j = 0; j < cellCount; j++) {
                Cell cell = row.getCell(j);
                if(null == cell) {
                    rowData.add(null);
                    continue;
                }
                rowData.add(getCellValue(cell));
            }
            sheetData.add(rowData);
        }
        return sheetData;
    }
    
    /**
     * 獲取cell值
     *
     * @param cell
     * @return
     */
    private static String getCellValue(Cell cell) {
        CellType type = cell.getCellTypeEnum();
        String value = null;
        if(CellType.NUMERIC.equals(type)) {
            if(DateUtil.isCellDateFormatted(cell)) {
                Date date = cell.getDateCellValue();
                value = sdf.format(date);
            } else {
                cell.setCellType(CellType.STRING);
                value = String.valueOf(cell.getStringCellValue());
            }
        } else if(CellType.BOOLEAN.equals(type)) {
            value = String.valueOf(cell.getBooleanCellValue());
        } else if(CellType.BLANK.equals(type)) {
            value = null;
        } else {
            value = String.valueOf(cell.getStringCellValue());
        }
        return value;
    } 
}

19、Excel寫入操作

/**
 * @Description:Excel讀取操作
 * @Author:zhangzhixiang
 * @CreateDate:2018/08/31 21:59:43
 * @Version:1.0
 */
public class ExcelWrite {

    private static final Logger logger = LoggerFactory.getLogger(ExcelWrite.class);

    public static final String SUFFIX = "xlsx";

    /**
     * 匯出Excel
     * 
     * @param
     * @return void 
     * @author zhangzhixiang
     * @data 2018/09/10 13:59:43
     */
    public static void exportExcel(HttpServletResponse response, List<List<String>> rows, String fileName, String sheetName) {
        Workbook workbook = createWb();
        try(OutputStream out = response.getOutputStream()) {
            Sheet sheet = workbook.createSheet(sheetName);
            sheetAppendData(rows, sheet);
            response.setContentType("application/ms-excel;charset=UTF-8");
            response.setHeader("Content-Disposition", "attachment;filename="
                .concat(String.valueOf(URLEncoder.encode(fileName, "UTF-8"))));
            workbook.write(out);
        } catch(Exception e) {
            logger.error("ExcelWrite--exportExcel throw Exception.fileName:{}", fileName, e);
        }
    }

    /**
     * 生成Excel檔案流
     *
     * @param rows
     * @param name
     * @return java.io.ByteArrayOutputStream
     * @author zhangzhixiang
     * @date 2018/09/10 20:54:46
     */
    public static ByteArrayOutputStream writeData(List<List<String>> rows, String name) {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        Workbook workbook = createWb();
        Sheet sheet= workbook.createSheet(name);
        sheetAppendData(rows, sheet);
        try {
            workbook.write(out);
            out.flush();
            return out;
        } catch(Exception e) {
            logger.error("ExcelWrite-->writeData throw Exception.name:{}.", name, e);
            return null;
        }
    }

    /**
     * sheet頁填充資料
     *
     * @param rows
     * @param sheet
     * @return org.apache.poi.ss.usermodel.Sheet
     * @author zhangzhixiang
     * @date 2018/09/10 10:59:48
     */
    public static Sheet sheetAppendData(List<List<String>> rows, Sheet sheet) {
        int lastRowNum = sheet.getPhysicalNumberOfRows();
        if(null == rows || rows.size == 0) {
            return sheet;
        }
        Row row = null;
        if(List<String> rowData : rows) {
            row = sheet.creatRow(lastRowNum);
            rowCreateData(rowData, row);
            lastRowNum = lastRowNum + 1;
        }
        return sheet;
    }

    /**
     * 生成row    
     *
     * @param datas
     * @param row
     * @return org.apache.poi.ss.usermodel.Row
     * @author zhangzhixiang
     * @date 2018/09/10 20:35:46
     */
    private static Row rowCreateData(List<String> datas, Row row) {
        Cell cell = null;
        for(int i = 0; i < datas.size(); i++) {
            cell = row.createCell(i);
            cell.setCellType(CellType.STRING);
            cell.setCellValue(datas.get(i));
        }
        return row;
    }

    /**
     * 建立workbook
     *
     * @param
     * @return org.apache.poi.ss.usermodel.Workbook
     * @author zhangzhixiang
     * @date 2018/09/10 20:35:42
     */
    public static Workbook createWb() {
        Workbook wb = null;
        if(SimpleConsts.EXCEL_EXT.equals(SUFFIX)) {
            wb = new XSSFWorkbook();
        } else {
            wb = new HSSFWorkbook();
        }
        return wb;
    }
}

20、常量類定義

/**
 * @Description:簡單常亮定義
 * @Author:zhangzhixiang
 * @CreateDate:2018/08/31 11:34:56
 * @Version:1.0
 */
public class SimpleConsts {
    
    public static final String EXCEL_EXT = "xlsx";
 
}

21、controller層

/**
 * @Description:公共服務介面-controller
 * @Author:zhangzhixiang
 * @CreateDate:2018/08/31 11:34:56
 * @Version:1.0
 */
@RestController
@RequestMapping("/api/ops/common")
public class CommonController extends ExceptionHandlerAdvice {
    
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private ExcelOperateService excelOperateService;

    @RequestMapping(value = "/excelImport", method = RequestMethod.POST)
    public ResponseResult excelImport(@RequestBody ExcelImportBO excelImportBO) throw Exception {
        Boolean flag = paramCheckModule(excelImportBO.getModule());
        ExcelOperateResultBO data = excelOperateService.excelImport(excelImportBO.getCode());
        return new ResponseResult().setSuccess(true).setData(data).setMessage(ResultCode.SUCCESS.getMessage);
    }

    @RequestMapping(value = "/excelExport", method = RequestMethod.GET)
    public void excelImport(@RequestBody List<List<String>> rows, String fileName, String sheetName, HttpServletResponse response) throw Exception {
        excelOperateService.excelExport(response, rows, fileName, sheetName);
    }

    private boolean paramCheckModule(String module) throws Exception {
        ExcelTypeEnum type = ExcelTypeEnum.containKey(module);
        if(null == type) {
            logger.error("********************No specified module was found.module:{}**********************", module);
            return false;
        }
        return true;
    }
 
}

全篇文章完全純手打,如果覺得對您有幫助,記得加關注給好評喲~~