簡單封裝POI匯出excel
阿新 • • 發佈:2019-01-10
1) 匯出excel的樣式、資料配置檔案
匯出excel時,主要邏輯無非是將資料填充到excel單元格中,再設定單元格樣式,封裝POI對excel單元格的操作,只需要定義預先約定的配置檔案,封裝類再解析配置檔案,得到被匯出excel每行、每個單元格的資料,操作單元格,最後生成excel檔案,返回給使用者。
下面是約定的簡單配置
<?xml version="1.0" encoding="UTF-8"?> <excel name="export.xls"> <sheet data-list="data1" desc="" field="examName"> <title desc="" field="examName" border="thin" height="40" background-color="41" align="center" v-align="center" wrap="true" bold="bold" font-size="25" font-color="12" font-name="黑體"></title> <headers border="thin" height="25" background-color="43" align="center" v-align="center" wrap="true" bold="bold" font-size="20" font-name="宋體" > <column header="名稱" field="examName" type="String" border="thin" width="30" height="20" background-color="" align="center" v-align="top" wrap="true" bold="" font-size="18" font-name="宋體"></column> <column header="測試1" field="schoolYear" type="String" border="thin" width="20" height="20" background-color="" align="right" v-align="center" wrap="true" bold="" font-size="18" font-name="宋體"></column> <column header="測試2" field="term" type="String" border="thin" width="40" height="20" background-color="" align="left" v-align="" wrap="bottom" bold="true" font-size="18" font-name="隸書"></column> </headers> </sheet> <sheet data-list="data1" desc="11111" field="examName"> <title desc="but" field="examName" border="thin" height="40" background-color="41" align="center" v-align="center" wrap="true" bold="bold" font-size="25" font-color="12" font-name="黑體"></title> <headers border="thin" height="25" background-color="43" align="center" v-align="center" wrap="true" bold="bold" font-size="20" font-name="宋體" > <column header="名稱" field="examName" type="String" border="thin" width="30" height="20" background-color="" align="center" v-align="top" wrap="true" bold="" font-size="18" font-name="宋體"></column> <column header="測試1" field="schoolYear" type="String" border="thin" width="20" height="20" background-color="" align="right" v-align="center" wrap="true" bold="" font-size="18" font-name="宋體"></column> <column header="測試2" field="term" type="String" border="thin" width="40" height="20" background-color="" align="left" v-align="" wrap="bottom" bold="true" font-size="18" font-name="隸書"></column> </headers> </sheet> </excel>
2) 配置解析器
配置解析器ExcelConfigHelper負責解析匯出配置,生成程式可讀的匯出excel配置ExcelConfigVO物件
public class ExcelConfigHelper { public static ExcelConfigVO GetExcelConfig(String configPath) { ExcelConfigVO config = new ExcelConfigVO(); SAXReader reader = new SAXReader(); try { Document doc = reader.read(new File(configPath)); Element root = doc.getRootElement(); config.setName(root.attributeValue("name")); List<SheetConfigVO> sheetList = new ArrayList<SheetConfigVO>(); config.setSheetList(sheetList); Iterator<Element> si = root.elementIterator(); while (si.hasNext()) { Element se = si.next(); SheetConfigVO sc = new SheetConfigVO(); sheetList.add(sc); sc.setDataList(se.attributeValue("data-list")); sc.setDesc(se.attributeValue("desc")); sc.setField(se.attributeValue("field")); Element te = se.element("title"); if (null != te) { sc.setTitleStyle(getStyleConfig(te)); } Element he = se.element("headers"); if (null != he) { sc.setHeaderStyle(getStyleConfig(he)); } List<ColumnConfigVO> columnList = new ArrayList<ColumnConfigVO>(); sc.setColumnList(columnList); Iterator<Element> ci = he.elementIterator(); while (ci.hasNext()) { Element ce = ci.next(); ColumnConfigVO cc = getColumnConfig(ce); columnList.add(cc); } } } catch (DocumentException e) { e.printStackTrace(); } return config; } private static StyleConfigVO getStyleConfig(Element e) { StyleConfigVO style = new StyleConfigVO(); style.setField(e.attributeValue("field")); style.setDesc(e.attributeValue("desc")); style.setBorder(e.attributeValue("border")); style.setWidth(e.attributeValue("width")); style.setHeight(e.attributeValue("height")); style.setBgcolor(e.attributeValue("background-color")); style.setAlign(e.attributeValue("align")); style.setValign(e.attributeValue("v-align")); style.setWrap(e.attributeValue("wrap")); style.setBold(e.attributeValue("bold")); style.setFontSize(e.attributeValue("font-size")); style.setFontName(e.attributeValue("font-name")); style.setFontColor(e.attributeValue("font-color")); return style; } private static ColumnConfigVO getColumnConfig(Element e) { ColumnConfigVO c = new ColumnConfigVO(); c.setField(e.attributeValue("field")); c.setHeader(e.attributeValue("header")); StyleConfigVO style = getStyleConfig(e); c.setStyle(style); return c; } }
Excel配置類
ExcelConfigVO
public class ExcelConfigVO implements Serializable {
/**
*
*/
private static final long serialVersionUID = -6669292508345659358L;
private String name;
private List<SheetConfigVO> sheetList;
SheetConfigVO
public class SheetConfigVO implements Serializable { /** * */ private static final long serialVersionUID = -7809672890306591286L; private String dataList; private String desc; private String field; private StyleConfigVO titleStyle; private StyleConfigVO headerStyle; private List<ColumnConfigVO> columnList;
StyleConfigVO
public class StyleConfigVO implements Serializable {
/**
*
*/
private static final long serialVersionUID = 2747357536186545711L;
private String desc;
private String field;
private String border;
private String width;
private String height;
private String bgcolor;
private String align;
private String valign;
private String wrap;
private String bold;
private String fontSize;
private String fontName;
private String fontColor;
ColumnConfigVO
public class ColumnConfigVO implements Serializable {
/**
*
*/
private static final long serialVersionUID = 5303919948113915294L;
private String header;
private String field;
private StyleConfigVO style;
3. 根據配置和資料生成excel
Excel生成器ExcelExportHelper根據配置和資料生成excel
public class ExcelExportHelper {
private static final Logger log = LoggerFactory.getLogger(ExcelExportHelper.class);
public static HSSFWorkbook export(Map<String, Object> map, ExcelConfigVO config) {
try {
HSSFWorkbook hw = new HSSFWorkbook();
int sheetIndex = 1;
for (SheetConfigVO sc : config.getSheetList()) {
// dataList資料集合,desc是sheet名稱,field是sheet名稱在資料集合中的欄位,後面二者取一個
String dataList = sc.getDataList();
String desc = sc.getDesc();
String field = sc.getField();
List<Object> datas = (List<Object>) map.get(dataList);
if (StringUtils.isEmpty(desc) && !CollectionUtils.isEmpty(datas) && !StringUtils.isEmpty(field)) {
Object obj = datas.get(0);
Field f = obj.getClass().getDeclaredField(field);
f.setAccessible(true);
desc = (String) f.get(obj);
}
if (StringUtils.isEmpty(desc)) {
desc = "sheet" + sheetIndex;
}
HSSFSheet sheet = hw.createSheet(desc);
if (null != sc.getTitleStyle()) {
StyleConfigVO ts = sc.getTitleStyle();
String tdesc = ts.getDesc();
String tfield = ts.getField();
if (StringUtils.isEmpty(tdesc) && !CollectionUtils.isEmpty(datas) && !StringUtils.isEmpty(tfield)) {
Object obj = datas.get(0);
Field f = obj.getClass().getDeclaredField(tfield);
f.setAccessible(true);
tdesc = (String) f.get(obj);
}
if (StringUtils.isEmpty(tdesc)) {
tdesc = "title" + sheetIndex;
}
HSSFCellStyle titleStyle = getCellStyle(hw, ts);
int rindex = 0;
HSSFRow row = sheet.createRow(rindex++);
if (!StringUtils.isEmpty(ts.getHeight())) {
row.setHeightInPoints(Short.valueOf(ts.getHeight()));
}
HSSFCell cell = row.createCell(0);
cell.setCellStyle(titleStyle);
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
cell.setCellValue(desc);
if (!CollectionUtils.isEmpty(sc.getColumnList()) && sc.getColumnList().size() > 1) {
for (int i = 1; i < sc.getColumnList().size(); i++) {
cell = row.createCell(i);
cell.setCellStyle(titleStyle);
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
cell.setCellValue("");
}
CellRangeAddress merge = new CellRangeAddress(rindex - 1, rindex - 1, 0,
sc.getColumnList().size() - 1);
sheet.addMergedRegion(merge);
}
StyleConfigVO hs = sc.getHeaderStyle();
HSSFCellStyle headerstyle = getCellStyle(hw, hs);
row = sheet.createRow(rindex++);
if (!StringUtils.isEmpty(hs.getHeight())) {
row.setHeightInPoints(Short.valueOf(hs.getHeight()));
}
Map<Integer, HSSFCellStyle> styleMap = new HashMap<Integer, HSSFCellStyle>();
if (!CollectionUtils.isEmpty(sc.getColumnList())) {
for (int i = 0; i < sc.getColumnList().size(); i++) {
ColumnConfigVO column = sc.getColumnList().get(i);
styleMap.put(i, getCellStyle(hw, column.getStyle()));
cell = row.createCell(i);
cell.setCellStyle(headerstyle);
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
cell.setCellValue(column.getHeader());
if (null != column.getStyle() && !StringUtils.isEmpty(column.getStyle().getWidth())) {
sheet.setColumnWidth(i, Short.valueOf(column.getStyle().getWidth()) * 256);
}
}
}
for (Object obj : datas) {
row = sheet.createRow(rindex++);
for (int i = 0; i < sc.getColumnList().size(); i++) {
ColumnConfigVO column = sc.getColumnList().get(i);
if (i == 0 && !StringUtils.isEmpty(column.getStyle().getHeight())) {
row.setHeightInPoints(Short.valueOf(column.getStyle().getHeight()));
}
styleMap.put(i, getCellStyle(hw, column.getStyle()));
cell = row.createCell(i);
cell.setCellStyle(styleMap.get(i));
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
String val = "";
Field f = obj.getClass().getDeclaredField(column.getField());
f.setAccessible(true);
val = (String) f.get(obj);
cell.setCellValue(null == val ? "" : val);
}
}
}
sheetIndex++;
}
return hw;
} catch (NoSuchFieldException e) {
log.error("", e);
} catch (SecurityException e) {
log.error("", e);
} catch (IllegalArgumentException e) {
log.error("", e);
} catch (IllegalAccessException e) {
log.error("", e);
}
return null;
}
private static HSSFCellStyle getCellStyle(HSSFWorkbook hw, StyleConfigVO ts) {
HSSFCellStyle titlestyle = hw.createCellStyle();
HSSFFont titlefont = hw.createFont();
if (!StringUtils.isEmpty(ts.getBold()) && "BOLD".equalsIgnoreCase(ts.getBold().trim())) {
titlefont.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
}
if (!StringUtils.isEmpty(ts.getFontName())) {
titlefont.setFontName(ts.getFontName().trim());
}
if (!StringUtils.isEmpty(ts.getFontSize())) {
titlefont.setFontHeightInPoints(Short.valueOf(ts.getFontSize()));
}
if (!StringUtils.isEmpty(ts.getFontColor())) {
titlefont.setColor(Short.valueOf(ts.getFontColor()));
}
titlestyle.setFont(titlefont);
if (!StringUtils.isEmpty(ts.getBorder())) {
if ("THIN".equalsIgnoreCase(ts.getBorder().trim())) {
titlestyle.setBorderBottom(HSSFCellStyle.BORDER_THIN);
titlestyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);
titlestyle.setBorderRight(HSSFCellStyle.BORDER_THIN);
titlestyle.setBorderTop(HSSFCellStyle.BORDER_THIN);
} else if ("NONE".equalsIgnoreCase(ts.getBorder().trim())) {
titlestyle.setBorderBottom(HSSFCellStyle.BORDER_NONE);
titlestyle.setBorderLeft(HSSFCellStyle.BORDER_NONE);
titlestyle.setBorderRight(HSSFCellStyle.BORDER_NONE);
titlestyle.setBorderTop(HSSFCellStyle.BORDER_NONE);
} else if ("DOUBLE".equalsIgnoreCase(ts.getBorder().trim())) {
titlestyle.setBorderBottom(HSSFCellStyle.BORDER_DOUBLE);
titlestyle.setBorderLeft(HSSFCellStyle.BORDER_DOUBLE);
titlestyle.setBorderRight(HSSFCellStyle.BORDER_DOUBLE);
titlestyle.setBorderTop(HSSFCellStyle.BORDER_DOUBLE);
} else if ("DOTTED".equalsIgnoreCase(ts.getBorder().trim())) {
titlestyle.setBorderBottom(HSSFCellStyle.BORDER_DOTTED);
titlestyle.setBorderLeft(HSSFCellStyle.BORDER_DOTTED);
titlestyle.setBorderRight(HSSFCellStyle.BORDER_DOTTED);
titlestyle.setBorderTop(HSSFCellStyle.BORDER_DOTTED);
} else if ("DASHED".equalsIgnoreCase(ts.getBorder().trim())) {
titlestyle.setBorderBottom(HSSFCellStyle.BORDER_DASHED);
titlestyle.setBorderLeft(HSSFCellStyle.BORDER_DASHED);
titlestyle.setBorderRight(HSSFCellStyle.BORDER_DASHED);
titlestyle.setBorderTop(HSSFCellStyle.BORDER_DASHED);
} else if ("MEDIUM".equalsIgnoreCase(ts.getBorder().trim())) {
titlestyle.setBorderBottom(HSSFCellStyle.BORDER_MEDIUM);
titlestyle.setBorderLeft(HSSFCellStyle.BORDER_MEDIUM);
titlestyle.setBorderRight(HSSFCellStyle.BORDER_MEDIUM);
titlestyle.setBorderTop(HSSFCellStyle.BORDER_MEDIUM);
}
}
if (!StringUtils.isEmpty(ts.getAlign())) {
String align = ts.getAlign().toUpperCase().trim();
switch (align) {
case "CENTER":
titlestyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
case "LEFT":
titlestyle.setAlignment(HSSFCellStyle.ALIGN_LEFT);
case "RIGHT":
titlestyle.setAlignment(HSSFCellStyle.ALIGN_RIGHT);
case "FILL":
titlestyle.setAlignment(HSSFCellStyle.ALIGN_FILL);
case "GENERAL":
titlestyle.setAlignment(HSSFCellStyle.ALIGN_GENERAL);
default:
titlestyle.setAlignment(HSSFCellStyle.ALIGN_JUSTIFY);
}
}
if (!StringUtils.isEmpty(ts.getValign())) {
String valign = ts.getValign().toUpperCase().trim();
switch (valign) {
case "CENTER":
titlestyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
case "BOTTOM":
titlestyle.setAlignment(HSSFCellStyle.VERTICAL_BOTTOM);
case "TOP":
titlestyle.setAlignment(HSSFCellStyle.VERTICAL_TOP);
default:
titlestyle.setAlignment(HSSFCellStyle.VERTICAL_JUSTIFY);
}
}
if (!StringUtils.isEmpty(ts.getBgcolor())) {
titlestyle.setFillForegroundColor(Short.valueOf(ts.getBgcolor()));
titlestyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
}
if (!StringUtils.isEmpty(ts.getWrap())) {
titlestyle.setWrapText(Boolean.valueOf(ts.getWrap()));
}
return titlestyle;
}
public static String getFileName(String fileName, ExcelConfigVO config) {
if (StringUtils.isEmpty(fileName)) {
fileName = config.getName();
}
if (StringUtils.isEmpty(fileName)) {
fileName = "export.xls";
}
return fileName;
}
}
4. 匯出邏輯
1) 獲取匯出任務
匯出任務介面,匯出特定資料時需要實現介面,給配置解析器提供特定的配置,給excel生成器提供特定的資料。
public interface IExcelExportProcessor {
/**
* 配置檔案路徑
*
* @return
*/
public String getConfigPath();
/**
* 匯出檔名
*
* @return
*/
public String getFilename();
/**
* 查詢資料
*
* @param queryMap
* 查詢引數
* @return 匯出資料
*/
public Map<String, Object> getDatas(Map<String, Object> queryMap);
}
匯出任務實現樣例
@Component("excelExport.seat")
public class ExportSeatProcessor implements IExcelExportProcessor {
private static final Logger log = LoggerFactory.getLogger(ExportSeatProcessor.class);
@Override
public String getConfigPath() {
return "";
}
@Override
public String getFilename() {
return null;
}
@Override
public Map<String, Object> getDatas(Map<String, Object> queryMap) {
return null;
}
}
2) 匯出介面
匯出介面根據請求引數得到匯出任務Bean和資料請求引數,通過匯出任務Bean獲取匯出配置,資料,匯出檔名,再呼叫配置解析器,excel生成器,生成excel並返回。
RequestMapping(value = "/export", method = RequestMethod.GET)
public void test(HttpServletRequest req, HttpServletResponse res) throws IOException {
String processorName = req.getParameter("processor");
if (StringUtils.isEmpty(processorName)) {
res.getWriter().println("parameter error!");
return;
}
IExcelExportProcessor processor = (IExcelExportProcessor) ExcelExportContext.getApplicationContext()
.getBean(processorName);
if (null == processor) {
res.getWriter().println("parameter error!");
return;
}
Map<String, Object> queryMap = getParameterMap(req);
String fileName = processor.getFilename();
String configPath = processor.getConfigPath();
Map<String, Object> map = processor.getDatas(queryMap);
ExcelConfigVO config = ExcelConfigHelper.GetExcelConfig(configPath);
fileName = ExcelExportHelper.getFileName(fileName, config);
HSSFWorkbook hw = ExcelExportHelper.export(map, config);
res.setContentType("application/octet-stream");
res.setHeader("Content-disposition", "attachment;filename=" + new String(fileName.getBytes(), "ISO-8859-1"));
OutputStream out = null;
try {
out = res.getOutputStream();
hw.write(out);
} catch (IOException e) {
log.error("export excel error", e);
} finally {
try {
if (null != out) {
out.close();
}
} catch (IOException e) {
log.error("export excel error", e);
}
}
}
http GET請求 url?processorName=xxx&name=xxx$yyy=xxx,增加匯出資料查詢引數,即可匯出excel。