Jboot框架excel匯入匯出模板下載的簡單封裝
阿新 • • 發佈:2018-12-19
需要用到的的類
主控制器
package io.jboot.admin.controller.ImportController; import java.util.ArrayList; import java.util.List; import javax.validation.ConstraintViolationException; import org.apache.commons.lang3.StringUtils; import com.jfinal.plugin.activerecord.Page; import com.jfinal.upload.UploadFile; import io.jboot.admin.base.web.base.BaseController; import io.jboot.admin.excelutils.ExportExcel; import io.jboot.admin.excelutils.ImportExcel; import io.jboot.admin.service.api.UserService; import io.jboot.admin.service.entity.model.User; import io.jboot.core.rpc.annotation.JbootrpcService; import io.jboot.web.controller.annotation.RequestMapping; /** * Excel 匯入 Demo * @author Rlax * */ @RequestMapping("/url") public class DemoController extends BaseController { @JbootrpcService private UserService userService; public void downloadTemplate() { try { String fileName = "測試管理匯入模板.xlsx"; List<User> list = new ArrayList<User>(); User param = new User(); list.add(param); ExportExcel exportExcel = new ExportExcel("資訊資料", User.class, 1); ExportExcel dataList = exportExcel.setDataList(list); dataList.write(getResponse(), fileName).dispose(); renderNull(); } catch (Exception e) { System.err.print("匯入模板下載失敗!失敗資訊:"+e.getMessage()); e.printStackTrace(); } } public void exportFile() { try { String fileName = "測試標題" + ".xlsx"; int pageNumber = getParaToInt("pageNumber", 1); int pageSize = getParaToInt("pageSize", 30); User sysUser = new User(); sysUser.setName(getPara("name")); sysUser.setPhone(getPara("phone")); sysUser.setOffice(getParaToLong("office")); Page<User> userPage = userService.findPage(sysUser, pageNumber, pageSize); new ExportExcel("學員資訊", User.class).setDataList(userPage.getList()).write(getResponse(), fileName).dispose(); renderNull(); } catch (Exception e) { System.err.println("匯出資訊記錄失敗!失敗資訊:" + e.getMessage()); } } /** * 匯入Excel資料 * */ public void importFile() { UploadFile file = getFile(); try { int successNum = 0; int failureNum = 0; StringBuilder failureMsg = new StringBuilder(); ImportExcel ei = new ImportExcel(file.getFile(), 1, 0); List<User> dataList = ei.getDataList(User.class); //Long office = AuthUtils.getLoginUser().getOffice(); for (User u : dataList) { try { if (StringUtils.isBlank(u.getName()) && StringUtils.isBlank(u.getEmail()) && StringUtils.isBlank(u.getPhone())) { continue; } //如果存在該條資料,執行修改操作,否則儲存 successNum++; } catch (ConstraintViolationException ex) { failureNum++; } catch (Exception ex) { ex.printStackTrace(); failureNum++; } } if (failureNum > 0) { failureMsg.insert(0, ",失敗 " + failureNum + " 條資訊記錄。"); } setAttr("ok", "已成功匯入 " + successNum + " 條資訊記錄" + failureMsg); } catch (Exception e) { setAttr("flag", "匯入資訊失敗!失敗資訊:" + e.getMessage()); e.printStackTrace(); } renderJson("/匯入完成,開始重定向"); } }
excelutils
ExcelField.java
package io.jboot.admin.excelutils; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Excel註解定義 */ @Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface ExcelField { /** * 匯出欄位名(預設呼叫當前欄位的“get”方法,如指定匯出欄位為物件,請填寫“物件名.物件屬性”,例:“area.name”、“office.name”) */ String value() default ""; /** * 匯出欄位標題(需要新增批註請用“**”分隔,標題**批註,僅對匯出模板有效) */ String title(); /** * 欄位型別(0:匯出匯入;1:僅匯出;2:僅匯入) */ int type() default 0; /** * 匯出欄位對齊方式(0:自動;1:靠左;2:居中;3:靠右) */ int align() default 0; /** * 匯出欄位欄位排序(升序) */ int sort() default 0; /** * 如果是字典型別,請設定字典的type值 */ String dictType() default ""; /** * 反射型別 */ Class<?> fieldType() default Class.class; /** * 欄位歸屬組(根據分組匯出匯入) */ int[] groups() default {}; }
Exceptions.java
package io.jboot.admin.excelutils; import java.io.PrintWriter; import java.io.StringWriter; import javax.servlet.http.HttpServletRequest; /** * 關於異常的工具類. */ public class Exceptions { /** * 將CheckedException轉換為UncheckedException. */ public static RuntimeException unchecked(Exception e) { if (e instanceof RuntimeException) { return (RuntimeException) e; } else { return new RuntimeException(e); } } /** * 將ErrorStack轉化為String. */ public static String getStackTraceAsString(Throwable e) { if (e == null){ return ""; } StringWriter stringWriter = new StringWriter(); e.printStackTrace(new PrintWriter(stringWriter)); return stringWriter.toString(); } /** * 判斷異常是否由某些底層的異常引起. */ @SuppressWarnings("unchecked") public static boolean isCausedBy(Exception ex, Class<? extends Exception>... causeExceptionClasses) { Throwable cause = ex.getCause(); while (cause != null) { for (Class<? extends Exception> causeClass : causeExceptionClasses) { if (causeClass.isInstance(cause)) { return true; } } cause = cause.getCause(); } return false; } /** * 在request中獲取異常類 * @param request * @return */ public static Throwable getThrowable(HttpServletRequest request){ Throwable ex = null; if (request.getAttribute("exception") != null) { ex = (Throwable) request.getAttribute("exception"); } else if (request.getAttribute("javax.servlet.error.exception") != null) { ex = (Throwable) request.getAttribute("javax.servlet.error.exception"); } return ex; } }
ExportExcel.java
package io.jboot.admin.excelutils;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Comment;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 匯出Excel檔案(匯出“XLSX”格式,支援大資料量匯出 @see org.apache.poi.ss.SpreadsheetVersion)
*/
public class ExportExcel {
private static Logger log = LoggerFactory.getLogger(ExportExcel.class);
/**
* 工作薄物件
*/
private SXSSFWorkbook wb;
/**
* 工作表物件
*/
private SXSSFSheet sheet;
/**
* 樣式列表
*/
private Map<String, CellStyle> styles;
/**
* 當前行號
*/
private int rownum;
/**
* 註解列表(Object[]{ ExcelField, Field/Method })
*/
List<Object[]> annotationList = new ArrayList<Object[]>();
/**
* 建構函式
* @param title 表格標題,傳“空值”,表示無標題
* @param cls 實體物件,通過annotation.ExportField獲取標題
*/
public ExportExcel(String title, Class<?> cls){
this(title, cls, 1);
}
/**
* 建構函式
* @param title 表格標題,傳“空值”,表示無標題
* @param cls 實體物件,通過annotation.ExportField獲取標題
* @param type 匯出型別(1:匯出資料;2:匯出模板)
* @param groups 匯入分組
*/
public ExportExcel(String title, Class<?> cls, int type, int... groups){
// Get annotation field
Field[] fs = cls.getDeclaredFields();
for (Field f : fs){
ExcelField ef = f.getAnnotation(ExcelField.class);
if (ef != null && (ef.type()==0 || ef.type()==type)){
if (groups!=null && groups.length>0){
boolean inGroup = false;
for (int g : groups){
if (inGroup){
break;
}
for (int efg : ef.groups()){
if (g == efg){
inGroup = true;
annotationList.add(new Object[]{ef, f});
break;
}
}
}
}else{
annotationList.add(new Object[]{ef, f});
}
}
}
// Get annotation method
Method[] ms = cls.getDeclaredMethods();
for (Method m : ms){
ExcelField ef = m.getAnnotation(ExcelField.class);
if (ef != null && (ef.type()==0 || ef.type()==type)){
if (groups!=null && groups.length>0){
boolean inGroup = false;
for (int g : groups){
if (inGroup){
break;
}
for (int efg : ef.groups()){
if (g == efg){
inGroup = true;
annotationList.add(new Object[]{ef, m});
break;
}
}
}
}else{
annotationList.add(new Object[]{ef, m});
}
}
}
// Field sorting
Collections.sort(annotationList, new Comparator<Object[]>() {
public int compare(Object[] o1, Object[] o2) {
return new Integer(((ExcelField)o1[0]).sort()).compareTo(
new Integer(((ExcelField)o2[0]).sort()));
};
});
// Initialize
List<String> headerList = new ArrayList<String>();
for (Object[] os : annotationList){
String t = ((ExcelField)os[0]).title();
// 如果是匯出,則去掉註釋
if (type==1){
String[] ss = StringUtils.split(t, "**", 2);
if (ss.length==2){
t = ss[0];
}
}
headerList.add(t);
}
initialize(title, headerList);
}
/**
* 建構函式
* @param title 表格標題,傳“空值”,表示無標題
* @param headers 表頭陣列
*/
public ExportExcel(String title, String[] headers) {
initialize(title, Arrays.asList(headers));
}
/**
* 建構函式
* @param title 表格標題,傳“空值”,表示無標題
* @param headerList 表頭列表
*/
public ExportExcel(String title, List<String> headerList) {
initialize(title, headerList);
}
/**
* 初始化函式
* @param title 表格標題,傳“空值”,表示無標題
* @param headerList 表頭列表
*/
private void initialize(String title, List<String> headerList) {
this.wb = new SXSSFWorkbook(500);
this.sheet = (SXSSFSheet) wb.createSheet("Export");
this.styles = createStyles(wb);
// Create title
if (StringUtils.isNotBlank(title)){
Row titleRow = sheet.createRow(rownum++);
titleRow.setHeightInPoints(30);
Cell titleCell = titleRow.createCell(0);
titleCell.setCellStyle(styles.get("title"));
titleCell.setCellValue(title);
sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(),
titleRow.getRowNum(), titleRow.getRowNum(), headerList.size()-1));
}
// Create header
if (headerList == null){
throw new RuntimeException("headerList not null!");
}
Row headerRow = sheet.createRow(rownum++);
headerRow.setHeightInPoints(16);
//sheet.trackAllColumnsForAutoSizing();
for (int i = 0; i < headerList.size(); i++) {
Cell cell = headerRow.createCell(i);
cell.setCellStyle(styles.get("header"));
String[] ss = StringUtils.split(headerList.get(i), "**", 2);
if (ss.length==2){
cell.setCellValue(ss[0]);
Comment comment = this.sheet.createDrawingPatriarch().createCellComment(
new XSSFClientAnchor(0, 0, 0, 0, (short) 3, 3, (short) 5, 6));
comment.setString(new XSSFRichTextString(ss[1]));
cell.setCellComment(comment);
}else{
cell.setCellValue(headerList.get(i));
}
sheet.autoSizeColumn(i);
}
for (int i = 0; i < headerList.size(); i++) {
int colWidth = sheet.getColumnWidth(i)*2;
sheet.setColumnWidth(i, colWidth < 3000 ? 3000 : colWidth);
}
log.debug("Initialize success.");
}
/**
* 建立表格樣式
* @param wb 工作薄物件
* @return 樣式列表
*/
private Map<String, CellStyle> createStyles(Workbook wb) {
Map<String, CellStyle> styles = new HashMap<String, CellStyle>();
CellStyle style = wb.createCellStyle();
style.setAlignment(CellStyle.ALIGN_CENTER);
//style.setAlignment(HorizontalAlignment.CENTER);
style.setVerticalAlignment(CellStyle.VERTICAL_CENTER);
Font titleFont = wb.createFont();
titleFont.setFontName("Arial");
titleFont.setFontHeightInPoints((short) 16);
titleFont.setBoldweight(Font.BOLDWEIGHT_BOLD);
style.setFont(titleFont);
styles.put("title", style);
style = wb.createCellStyle();
style.setVerticalAlignment(CellStyle.VERTICAL_CENTER);
style.setBorderRight(CellStyle.BORDER_THIN);
style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
style.setBorderLeft(CellStyle.BORDER_THIN);
style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
style.setBorderTop(CellStyle.BORDER_THIN);
style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
style.setBorderBottom(CellStyle.BORDER_THIN);
style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
Font dataFont = wb.createFont();
dataFont.setFontName("Arial");
dataFont.setFontHeightInPoints((short) 10);
style.setFont(dataFont);
styles.put("data", style);
style = wb.createCellStyle();
style.cloneStyleFrom(styles.get("data"));
style.setAlignment(CellStyle.ALIGN_LEFT);
styles.put("data1", style);
style = wb.createCellStyle();
style.cloneStyleFrom(styles.get("data"));
style.setAlignment(CellStyle.ALIGN_CENTER);
styles.put("data2", style);
style = wb.createCellStyle();
style.cloneStyleFrom(styles.get("data"));
style.setAlignment(CellStyle.ALIGN_RIGHT);
styles.put("data3", style);
style = wb.createCellStyle();
style.cloneStyleFrom(styles.get("data"));
// style.setWrapText(true);
style.setAlignment(CellStyle.ALIGN_CENTER);
style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex());
style.setFillPattern(CellStyle.SOLID_FOREGROUND);
Font headerFont = wb.createFont();
headerFont.setFontName("Arial");
headerFont.setFontHeightInPoints((short) 10);
headerFont.setBoldweight(Font.BOLDWEIGHT_BOLD);
headerFont.setColor(IndexedColors.WHITE.getIndex());
style.setFont(headerFont);
styles.put("header", style);
return styles;
}
/**
* 新增一行
* @return 行物件
*/
public Row addRow(){
return sheet.createRow(rownum++);
}
/**
* 新增一個單元格
* @param row 新增的行
* @param column 新增列號
* @param val 新增值
* @return 單元格物件
*/
public Cell addCell(Row row, int column, Object val){
return this.addCell(row, column, val, 0, Class.class);
}
/**
* 新增一個單元格
* @param row 新增的行
* @param column 新增列號
* @param val 新增值
* @param align 對齊方式(1:靠左;2:居中;3:靠右)
* @return 單元格物件
*/
public Cell addCell(Row row, int column, Object val, int align, Class<?> fieldType){
Cell cell = row.createCell(column);
String cellFormatString = "@";
try {
if(val == null){
cell.setCellValue("");
}else if(fieldType != Class.class){
cell.setCellValue((String)fieldType.getMethod("setValue", Object.class).invoke(null, val));
}else{
if(val instanceof String) {
cell.setCellValue((String) val);
}else if(val instanceof Integer) {
cell.setCellValue((Integer) val);
cellFormatString = "0";
}else if(val instanceof Long) {
cell.setCellValue((Long) val);
cellFormatString = "0";
}else if(val instanceof Double) {
cell.setCellValue((Double) val);
cellFormatString = "0.00";
}else if(val instanceof Float) {
cell.setCellValue((Float) val);
cellFormatString = "0.00";
}else if(val instanceof Date) {
cell.setCellValue((Date) val);
cellFormatString = "yyyy-MM-dd HH:mm";
}else {
cell.setCellValue((String)Class.forName(this.getClass().getName().replaceAll(this.getClass().getSimpleName(),
"fieldtype."+val.getClass().getSimpleName()+"Type")).getMethod("setValue", Object.class).invoke(null, val));
}
}
if (val != null){
CellStyle style = styles.get("data_column_"+column);
if (style == null){
style = wb.createCellStyle();
style.cloneStyleFrom(styles.get("data"+(align>=1&&align<=3?align:"")));
style.setDataFormat(wb.createDataFormat().getFormat(cellFormatString));
styles.put("data_column_" + column, style);
}
cell.setCellStyle(style);
}
} catch (Exception ex) {
log.info("Set cell value ["+row.getRowNum()+","+column+"] error: " + ex.toString());
cell.setCellValue(val.toString());
}
return cell;
}
/**
* 新增資料(通過annotation.ExportField新增資料)
* @return list 資料列表
*/
public <E> ExportExcel setDataList(List<E> list){
for (E e : list){
int colunm = 0;
Row row = this.addRow();
StringBuilder sb = new StringBuilder();
for (Object[] os : annotationList){
ExcelField ef = (ExcelField)os[0];
Object val = null;
// Get entity value
try{
if (StringUtils.isNotBlank(ef.value())){
val = Reflections.invokeGetter(e, ef.value());
}else{
if (os[1] instanceof Field){
val = Reflections.invokeGetter(e, ((Field)os[1]).getName());
}else if (os[1] instanceof Method){
val = Reflections.invokeMethod(e, ((Method)os[1]).getName(), new Class[] {}, new Object[] {});
}
}
// If is dict, get dict label
// if (StringUtils.isNotBlank(ef.dictType())){
// val = DictUtils.getDictLabel(val==null?"":val.toString(), ef.dictType(), "");
// }
}catch(Exception ex) {
// Failure to ignore
log.info(ex.toString());
val = "";
}
this.addCell(row, colunm++, val, ef.align(), ef.fieldType());
sb.append(val + ", ");
}
log.debug("Write success: ["+row.getRowNum()+"] "+sb.toString());
}
return this;
}
/**
* 輸出資料流
* @param os 輸出資料流
*/
public ExportExcel write(OutputStream os) throws IOException{
wb.write(os);
return this;
}
/**
* 輸出到客戶端
* @param fileName 輸出檔名
*/
public ExportExcel write(HttpServletResponse response, String fileName) throws IOException{
response.reset();
response.setContentType("application/octet-stream; charset=utf-8");
response.setHeader("Content-Disposition", "attachment; filename="+Encodes.urlEncode(fileName));
write(response.getOutputStream());
return this;
}
/**
* 輸出到檔案
* @param fileName 輸出檔名
*/
public ExportExcel writeFile(String name) throws FileNotFoundException, IOException{
FileOutputStream os = new FileOutputStream(name);
this.write(os);
return this;
}
/**
* 清理臨時檔案
*/
public ExportExcel dispose(){
wb.dispose();
return this;
}
// /**
// * 匯出測試
// */
// public static void main(String[] args) throws Throwable {
//
// List<String> headerList = new ArrayList()();
// for (int i = 1; i <= 10; i++) {
// headerList.add("表頭"+i);
// }
//
// List<String> dataRowList = new ArrayList()();
// for (int i = 1; i <= headerList.size(); i++) {
// dataRowList.add("資料"+i);
// }
//
// List<List<String>> dataList = new ArrayList()();
// for (int i = 1; i <=1000000; i++) {
// dataList.add(dataRowList);
// }
//
// ExportExcel ee = new ExportExcel("表格標題", headerList);
//
// for (int i = 0; i < dataList.size(); i++) {
// Row row = ee.addRow();
// for (int j = 0; j < dataList.get(i).size(); j++) {
// ee.addCell(row, j, dataList.get(i).get(j));
// }
// }
//
// ee.writeFile("target/export.xlsx");
//
// ee.dispose();
//
// log.debug("Export success.");
//
// }
}
ImportExcel.java
package io.jboot.admin.excelutils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 匯入Excel檔案(支援“XLS”和“XLSX”格式)
*/
public class ImportExcel {
private static Logger log = LoggerFactory.getLogger(ImportExcel.class);
/**
* 工作薄物件
*/
private Workbook wb;
/**
* 工作表物件
*/
private Sheet sheet;
/**
* 標題行號
*/
private int headerNum;
/**
* 建構函式
* @param path 匯入檔案,讀取第一個工作表
* @param headerNum 標題行號,資料行號=標題行號+1
* @throws InvalidFormatException
* @throws IOException
*/
public ImportExcel(String fileName, int headerNum)
throws InvalidFormatException, IOException {
this(new File(fileName), headerNum);
}
/**
* 建構函式
* @param path 匯入檔案物件,讀取第一個工作表
* @param headerNum 標題行號,資料行號=標題行號+1
* @throws InvalidFormatException
* @throws IOException
*/
public ImportExcel(File file, int headerNum)
throws InvalidFormatException, IOException {
this(file, headerNum, 0);
}
/**
* 建構函式
* @param path 匯入檔案
* @param headerNum 標題行號,資料行號=標題行號+1
* @param sheetIndex 工作表編號
* @throws InvalidFormatException
* @throws IOException
*/
public ImportExcel(String fileName, int headerNum, int sheetIndex)
throws InvalidFormatException, IOException {
this(new File(fileName), headerNum, sheetIndex);
}
/**
* 建構函式
* @param path 匯入檔案物件
* @param headerNum 標題行號,資料行號=標題行號+1
* @param sheetIndex 工作表編號
* @throws InvalidFormatException
* @throws IOException
*/
public ImportExcel(File file, int headerNum, int sheetIndex)
throws InvalidFormatException, IOException {
this(file.getName(), new FileInputStream(file), headerNum, sheetIndex);
}
/**
* 建構函式
* @param file 匯入檔案物件
* @param headerNum 標題行號,資料行號=標題行號+1
* @param sheetIndex 工作表編號
* @throws InvalidFormatException
* @throws IOException
*//*
public ImportExcel(MultipartFile multipartFile, int headerNum, int sheetIndex)
throws InvalidFormatException, IOException {
this(multipartFile.getOriginalFilename(), multipartFile.getInputStream(), headerNum, sheetIndex);
}*/
/**
* 建構函式
* @param path 匯入檔案物件
* @param headerNum 標題行號,資料行號=標題行號+1
* @param sheetIndex 工作表編號
* @throws InvalidFormatException
* @throws IOException
*/
public ImportExcel(String fileName, InputStream is, int headerNum, int sheetIndex)
throws InvalidFormatException, IOException {
if (StringUtils.isBlank(fileName)){
throw new RuntimeException("匯入文件為空!");
}else if(fileName.toLowerCase().endsWith("xls")){
this.wb = new HSSFWorkbook(is);
}else if(fileName.toLowerCase().endsWith("xlsx")){
this.wb = new XSSFWorkbook(is);
}else{
throw new RuntimeException("文件格式不正確!");
}
if (this.wb.getNumberOfSheets()<sheetIndex){
throw new RuntimeException("文件中沒有工作表!");
}
this.sheet = this.wb.getSheetAt(sheetIndex);
this.headerNum = headerNum;
log.debug("Initialize success.");
}
/**
* 獲取行物件
* @param rownum
* @return
*/
public Row getRow(int rownum){
return this.sheet.getRow(rownum);
}
/**
* 獲取資料行號
* @return
*/
public int getDataRowNum(){
return headerNum+1;
}
/**
* 獲取最後一個數據行號
* @return
*/
public int getLastDataRowNum(){
return this.sheet.getLastRowNum()+headerNum;
}
/**
* 獲取最後一個列號
* @return
*/
public int getLastCellNum(){
return this.getRow(headerNum).getLastCellNum();
}
/**
* 獲取單元格值
* @param row 獲取的行
* @param column 獲取單元格列號
* @return 單元格值
*/
public Object getCellValue(Row row, int column){
Object val = "";
try{
Cell cell = row.getCell(column);
if (cell != null){
if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC){
// val = cell.getNumericCellValue();
DecimalFormat df = new DecimalFormat("0"); // 去掉科學計數法
val = df.format(cell.getNumericCellValue());
}else if (cell.getCellType() == Cell.CELL_TYPE_STRING){
val = cell.getStringCellValue();
}else if (cell.getCellType() == Cell.CELL_TYPE_FORMULA){
val = cell.getCellFormula();
}else if (cell.getCellType() == Cell.CELL_TYPE_BOOLEAN){
val = cell.getBooleanCellValue();
}else if (cell.getCellType() == Cell.CELL_TYPE_ERROR){
val = cell.getErrorCellValue();
}
}
}catch (Exception e) {
return val;
}
return val;
}
/**
* 獲取匯入資料列表
* @param cls 匯入物件型別
* @param groups 匯入分組
*/
public <E> List<E> getDataList(Class<E> cls, int... groups) throws InstantiationException, IllegalAccessException{
List<Object[]> annotationList = new ArrayList<Object[]>();
// Get annotation field
Field[] fs = cls.getDeclaredFields();
for (Field f : fs){
ExcelField ef = f.getAnnotation(ExcelField.class);
if (ef != null && (ef.type()==0 || ef.type()==2)){
if (groups!=null && groups.length>0){
boolean inGroup = false;
for (int g : groups){
if (inGroup){
break;
}
for (int efg : ef.groups()){
if (g == efg){
inGroup = true;
annotationList.add(new Object[]{ef, f});
break;
}
}
}
}else{
annotationList.add(new Object[]{ef, f});
}
}
}
// Get annotation method
Method[] ms = cls.getDeclaredMethods();
for (Method m : ms){
ExcelField ef = m.getAnnotation(ExcelField.class);
if (ef != null && (ef.type()==0 || ef.type()==2)){
if (groups!=null && groups.length>0){
boolean inGroup = false;
for (int g : groups){
if (inGroup){
break;
}
for (int efg : ef.groups()){
if (g == efg){
inGroup = true;
annotationList.add(new Object[]{ef, m});
break;
}
}
}
}else{
annotationList.add(new Object[]{ef, m});
}
}
}
// Field sorting
Collections.sort(annotationList, new Comparator<Object[]>() {
public int compare(Object[] o1, Object[] o2) {
return new Integer(((ExcelField)o1[0]).sort()).compareTo(
new Integer(((ExcelField)o2[0]).sort()));
};
});
//log.debug("Import column count:"+annotationList.size());
// Get excel data
List<E> dataList = new ArrayList<E>();
for (int i = this.getDataRowNum(); i < this.getLastDataRowNum(); i++) {
E e = (E)cls.newInstance();
int column = 0;
Row row = this.getRow(i);
StringBuilder sb = new StringBuilder();
for (Object[] os : annotationList){
Object val = this.getCellValue(row, column++);
if (val != null){
ExcelField ef = (ExcelField)os[0];
// If is dict type, get dict value
if (StringUtils.isNotBlank(ef.dictType())){
// val = DictUtils.getDictValue(val.toString(), ef.dictType(), "");
//log.debug("Dictionary type value: ["+i+","+colunm+"] " + val);
}
// Get param type and type cast
Class<?> valType = Class.class;
if (os[1] instanceof Field){
valType = ((Field)os[1]).getType();
}else if (os[1] instanceof Method){
Method method = ((Method)os[1]);
if ("get".equals(method.getName().substring(0, 3))){
valType = method.getReturnType();
}else if("set".equals(method.getName().substring(0, 3))){
valType = ((Method)os[1]).getParameterTypes()[0];
}
}
//log.debug("Import value type: ["+i+","+column+"] " + valType);
try {
if (valType == String.class){
String s = String.valueOf(val.toString());
if(StringUtils.endsWith(s, ".0")){
val = StringUtils.substringBefore(s, ".0");
}else{
val = String.valueOf(val.toString());
}
}else if (valType == Integer.class){
val = Double.valueOf(val.toString()).intValue();
}else if (valType == Long.class){
val = Double.valueOf(val.toString()).longValue();
}else if (valType == Double.class){
val = Double.valueOf(val.toString());
}else if (valType == Float.class){
val = Float.valueOf(val.toString());
}else if (valType == Date.class){
val = DateUtil.getJavaDate((Double)val);
}else{
if (ef.fieldType() != Class.class){
val = ef.fieldType().getMethod("getValue", String.class).invoke(null, val.toString());
}else{
val = Class.forName(this.getClass().getName().replaceAll(this.getClass().getSimpleName(),
"fieldtype."+valType.getSimpleName()+"Type")).getMethod("getValue", String.class).invoke(null, val.toString());
}
}
} catch (Exception ex) {
log.info("Get cell value ["+i+","+column+"] error: " + ex.toString());
val = null;
}
// set entity value
if (os[1] instanceof Field){
Reflections.invokeSetter(e, ((Field)os[1]).getName(), val);
}else if (os[1] instanceof Method){
String mthodName = ((Method)os[1]).getName();
if ("get".equals(mthodName.substring(0, 3))){
mthodName = "set"+StringUtils.substringAfter(mthodName, "get");
}
Reflections.invokeMethod(e, mthodName, new Class[] {valType}, new Object[] {val});
}
}
sb.append(val+", ");
}
dataList.add(e);
log.debug("Read success: ["+i+"] "+sb.toString());
}
return dataList;
}
// /**
// * 匯入測試
// */
// public static void main(String[] args) throws Throwable {
//
// ImportExcel ei = new ImportExcel("target/export.xlsx", 1);
//
// for (int i = ei.getDataRowNum(); i < ei.getLastDataRowNum(); i++) {
// Row row = ei.getRow(i);
// for (int j = 0; j < ei.getLastCellNum(); j++) {
// Object val = ei.getCellValue(row, j);
// System.out.print(val+", ");
// }
// System.out.print("\n");
// }
//
// }
}
Reflections.java
package io.jboot.admin.excelutils;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 反射工具類.
* 提供呼叫getter/setter方法, 訪問私有變數, 呼叫私有方法, 獲取泛型型別Class, 被AOP過的真實類等工具函式.
*/
@SuppressWarnings("rawtypes")
public class Reflections {
private static final String SETTER_PREFIX = "set";
private static final String GETTER_PREFIX = "get";
private static final String CGLIB_CLASS_SEPARATOR = "$$";
private static Logger logger = LoggerFactory.getLogger(Reflections.class);
/**
* 呼叫Getter方法.
* 支援多級,如:物件名.物件名.方法
*/
public static Object invokeGetter(Object obj, String propertyName) {
Object object = obj;
for (String name : StringUtils.split(propertyName, ".")){
String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name);
object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
}
return object;
}
/**
* 呼叫Setter方法, 僅匹配方法名。
* 支援多級,如:物件名.物件名.方法
*/
public static void invokeSetter(Object obj, String propertyName, Object value) {
Object object = obj;
String[] names = StringUtils.split(propertyName, ".");
for (int i=0; i<names.length; i++){
if(i<names.length-1){
String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
}else{
String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
invokeMethodByName(object, setterMethodName, new Object[] { value });
}
}
}
/**
* 直接讀取物件屬性值, 無視private/protected修飾符, 不經過getter函式.
*/
public static Object getFieldValue(final Object obj, final String fieldName) {
Field field = getAccessibleField(obj, fieldName);
if (field == null) {
throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
}
Object result = null;
try {
result = field.get(obj);
} catch (IllegalAccessException e) {
logger.error("不可能丟擲的異常{}", e.getMessage());
}
return result;
}
/**
* 直接設定物件屬性值, 無視private/protected修飾符, 不經過setter函式.
*/
public static void setFieldValue(final Object obj, final String fieldName, final Object value) {
Field field = getAccessibleField(obj, fieldName);
if (field == null) {
throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
}
try {
field.set(obj, value);
} catch (IllegalAccessException e) {
logger.error("不可能丟擲的異常:{}", e.getMessage());
}
}
/**
* 直接呼叫物件方法, 無視private/protected修飾符.
* 用於一次性呼叫的情況,否則應使用getAccessibleMethod()函式獲得Method後反覆呼叫.
* 同時匹配方法名+引數型別,
*/
public static Object invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes,
final Object[] args) {
Method method = getAccessibleMethod(obj, methodName, parameterTypes);
if (method == null) {
throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]");
}
try {
return method.invoke(obj, args);
} catch (Exception e) {
throw convertReflectionExceptionToUnchecked(e);
}
}
/**
* 直接呼叫物件方法, 無視private/protected修飾符,
* 用於一次性呼叫的情況,否則應使用getAccessibleMethodByName()函式獲得Method後反覆呼叫.
* 只匹配函式名,如果有多個同名函式呼叫第一個。
*/
public static Object invokeMethodByName(final Object obj, final String methodName, final Object[] args) {
Method method = getAccessibleMethodByName(obj, methodName);
if (method == null) {
throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]");
}
try {
return method.invoke(obj, args);
} catch (Exception e) {
throw convertReflectionExceptionToUnchecked(e);
}
}
/**
* 迴圈向上轉型, 獲取物件的DeclaredField, 並強制設定為可訪問.
*
* 如向上轉型到Object仍無法找到, 返回null.
*/
public static Field getAccessibleField(final Object obj, final String fieldName) {
Validate.notNull(obj, "object can't be null");
Validate.notBlank(fieldName, "fieldName can't be blank");
for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
try {
Field field = superClass.getDeclaredField(fieldName);
makeAccessible(field);
return field;
} catch (NoSuchFieldException e) {//NOSONAR
// Field不在當前類定義,繼續向上轉型
continue;// new add
}
}
return null;
}
/**
* 迴圈向上轉型, 獲取物件的DeclaredMethod,並強制設定為可訪問.
* 如向上轉型到Object仍無法找到, 返回null.
* 匹配函式名+引數型別。
*
* 用於方法需要被多次呼叫的情況. 先使用本函式先取得Method,然後呼叫Method.invoke(Object obj, Object... args)
*/
public static Method getAccessibleMethod(final Object obj, final String methodName,
final Class<?>... parameterTypes) {
Validate.notNull(obj, "object can't be null");
Validate.notBlank(methodName, "methodName can't be blank");
for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
try {
Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
makeAccessible(method);
return method;
} catch (NoSuchMethodException e) {
// Method不在當前類定義,繼續向上轉型
continue;// new add
}
}
return null;
}
/**
* 迴圈向上轉型, 獲取物件的DeclaredMethod,並強制設定為可訪問.
* 如向上轉型到Object仍無法找到, 返回null.
* 只匹配函式名。
*
* 用於方法需要被多次呼叫的情況. 先使用本函式先取得Method,然後呼叫Method.invoke(Object obj, Object... args)
*/
public static Method getAccessibleMethodByName(final Object obj, final String methodName) {
Validate.notNull(obj, "object can't be null");
Validate.notBlank(methodName, "methodName can't be blank");
for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
Method[] methods = searchType.getDeclaredMethods();
for (Method method : methods) {
if (method.getName().equals(methodName)) {
makeAccessible(method);
return method;
}
}
}
return null;
}
/**
* 改變private/protected的方法為public,儘量不呼叫實際改動的語句,避免JDK的SecurityManager抱怨。
*/
public static void makeAccessible(Method method) {
if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
&& !method.isAccessible()) {
method.setAccessible(true);
}
}
/**
* 改變private/protected的成員變數為public,儘量不呼叫實際改動的語句,避免JDK的SecurityManager抱怨。
*/
public static void makeAccessible(Field field) {
if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) || Modifier
.isFinal(field.getModifiers())) && !field.isAccessible()) {
field.setAccessible(true);
}
}
/**
* 通過反射, 獲得Class定義中宣告的泛型引數的型別, 注意泛型必須定義在父類處
* 如無法找到, 返回Object.class.
* eg.
* public UserDao extends HibernateDao<User>
*
* @param clazz The class to introspect
* @return the first generic declaration, or Object.class if cannot be determined
*/
@SuppressWarnings("unchecked")
public static <T> Class<T> getClassGenricType(final Class clazz) {
return getClassGenricType(clazz, 0);
}
/**
* 通過反射, 獲得Class定義中宣告的父類的泛型引數的型別.
* 如無法找到, 返回Object.class.
*
* 如public UserDao extends HibernateDao<User,Long>
*
* @param clazz clazz The class to introspect
* @param index the Index of the generic ddeclaration,start from 0.
* @return the index generic declaration, or Object.class if cannot be determined
*/
public static Class getClassGenricType(final Class clazz, final int index) {
Type genType = clazz.getGenericSuperclass();
if (!(genType instanceof ParameterizedType)) {
logger.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType");
return Object.class;
}
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
if (index >= params.length || index < 0) {
logger.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: "
+ params.length);
return Object.class;
}
if (!(params[index] instanceof Class)) {
logger.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
return Object.class;
}
return (Class) params[index];
}
public static Class<?> getUserClass(Object instance) {
Class clazz = instance.getClass();
if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) {
Class<?> superClass = clazz.getSuperclass();
if (superClass != null && !Object.class.equals(superClass)) {
return superClass;
}
}
return clazz;
}
/**
* 將反射時的checked exception轉換為unchecked exception.
*/
public static RuntimeException convertReflectionExceptionToUnchecked(Exception e) {
if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException
|| e instanceof NoSuchMethodException) {
return new IllegalArgumentException(e);
} else if (e instanceof InvocationTargetException) {
return new RuntimeException(((InvocationTargetException) e).getTargetException());
} else if (e instanceof RuntimeException) {
return (RuntimeException) e;
}
return new RuntimeException("Unexpected Checked Exception.", e);
}
}
Encodes.java
package io.jboot.admin.excelutils;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringEscapeUtils;
/**
* 封裝各種格式的編碼解碼工具類.
* 1.Commons-Codec的 hex/base64 編碼
* 2.自制的base62 編碼
* 3.Commons-Lang的xml/html escape
* 4.JDK提供的URLEncoder
*/
public class Encodes {
private static final String DEFAULT_URL_ENCODING = "UTF-8";
private static final char[] BASE62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray();
/**
* Hex編碼.
*/
public static String encodeHex(byte[] input) {
return new String(Hex.encodeHex(input));
}
/**
* Hex解碼.
*/
public static byte[] decodeHex(String input) {
try {
return Hex.decodeHex(input.toCharArray());
} catch (DecoderException e) {
throw Exceptions.unchecked(e);
}
}
/**
* Base64編碼.
*/
public static String encodeBase64(byte[] input) {
return new String(Base64.encodeBase64(input));
}
/**
* Base64編碼.
*/
public static String encodeBase64(String input) {
try {
return new String(Base64.encodeBase64(input.getBytes(DEFAULT_URL_ENCODING)));
} catch (UnsupportedEncodingException e) {
return "";
}
}
// /**
// * Base64編碼, URL安全(將Base64中的URL非法字元'+'和'/'轉為'-'和'_', 見RFC3548).
// */
// public static String encodeUrlSafeBase64(byte[] input) {
// return Base64.encodeBase64URLSafe(input);
// }
/**
* Base64解碼.
*/
public static byte[] decodeBase64(String input) {
return Base64.decodeBase64(input.getBytes());
}
/**
* Base64解碼.
*/
public static String decodeBase64String(String input) {
try {
return new String(Base64.decodeBase64(input.getBytes()), DEFAULT_URL_ENCODING);
} catch (UnsupportedEncodingException e) {
return "";
}
}
/**
* Base62編碼。
*/
public static String encodeBase62(byte[] input) {
char[] chars = new char[input.length];
for (int i = 0; i < input.length; i++) {
chars[i] = BASE62[((input[i] & 0xFF) % BASE62.length)];
}
return new String(chars);
}
/**
* Html 轉碼.
*/
public static String escapeHtml(String html) {
return StringEscapeUtils.escapeHtml4(html);
}
/**
* Html 解碼.
*/
public static String unescapeHtml(String htmlEscaped) {
return StringEscapeUtils.unescapeHtml4(htmlEscaped);
}
/**
* Xml 轉碼.
*/
public static String escapeXml(String xml) {
return StringEscapeUtils.escapeXml10(xml);
}
/**
* Xml 解碼.
*/
public static String unescapeXml(String xmlEscaped) {
return StringEscapeUtils.unescapeXml(xmlEscaped);
}
/**
* URL 編碼, Encode預設為UTF-8.
*/
public static String urlEncode(String part) {
try {
return URLEncoder.encode(part, DEFAULT_URL_ENCODING);
} catch (UnsupportedEncodingException e) {
throw Exceptions.unchecked(e);
}
}
/**
* URL 解碼, Encode預設為UTF-8.
*/
public static String urlDecode(String part) {
try {
return URLDecoder.decode(part, DEFAULT_URL_ENCODING);
} catch (UnsupportedEncodingException e) {
throw Exceptions.unchecked(e);
}
}
}
引入jar包
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.9</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.9</version><!-- 3.9 -->
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml-schemas -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>3.9</version>
</dependency>
注意點:jboot框架內 Bean物件的get set 方法是 return get(‘xxx’)和set(‘xxx’, xxx),spring框架的話是return xxx和this.xxx=xxx
所以在ExportExcel.java中的 新增一個單元格addCell()內的反射賦值做對應處理。
Jboot框架內Bean裡方法上的註解不能寫到基類內,否則不生效(具體沒明白為什麼);
public void setName(java.lang.String name) {
set("name", name);
}
@ExcelField(title="姓名", align=2, sort=20)
public java.lang.String getName() {
return getStr("name");
}
匯出效果
下載模板效果