java将html表格导出成Excel表格
java导出Excel是常用的功能,常用的jar包有jxl与poi,最近遇到要将一个html表格导出成excel,我选择了jxl来实现。
1. 看名字就知道jxl是以xml格式来解析的,所以如果html代码里有单标记,是会解析报错的,就需要先用jsoup这个jar包来处理掉所有的单标记,例子代码如下:
首先html的table代码必须带colgroup,这样在生成excel表格时才能计算表格的宽度,
例子如下:
<colgroup><col width='100'></col><col width='100'></col></colgroup>
该工具类写了简单的获取样式,比如字体大小,再结合字的数量计算行的高度,代码虽然写的简陋,但已基本满足我目前的需求,如有类似需求的同学,可以拿去修改下。希望对你们有帮助。
代码如下:
1. 看名字就知道jxl是以xml格式来解析的,所以如果html代码里有单标记,是会解析报错的,就需要先用jsoup这个jar包来处理掉所有的单标记,例子代码如下:
public static String getHtml(String html) { StringBuffer htmlBuf = new StringBuffer(); Document doc = Jsoup.parse(html); for (Element item : doc.getElementsByTag("body")) { handleSingleTag(item); htmlBuf.append(item.html()); } return htmlBuf.toString(); } private static void handleSingleTag(Element item) { if ((item.children() != null) && (item.children().size() > 0)) { for (Element subItem : item.children()) { if (subItem.childrenSize() == 0) { subItem.prependText(""); } handleSingleTag(subItem); } } }2. 我写了个JxlUtil来处这个html的table导出成excel。
首先html的table代码必须带colgroup,这样在生成excel表格时才能计算表格的宽度,
例子如下:
<colgroup><col width='100'></col><col width='100'></col></colgroup>
该工具类写了简单的获取样式,比如字体大小,再结合字的数量计算行的高度,代码虽然写的简陋,但已基本满足我目前的需求,如有类似需求的同学,可以拿去修改下。希望对你们有帮助。
代码如下:
import java.awt.Font; import java.awt.FontMetrics; import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletResponse; import javax.swing.JComponent; import javax.swing.JLabel; import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.dom4j.Node; import com.aomc.manager.util.FileUtil; import com.aomc.manager.util.StringUtil; import jxl.Workbook; import jxl.format.Alignment; import jxl.format.Border; import jxl.format.BorderLineStyle; import jxl.format.Colour; import jxl.format.UnderlineStyle; import jxl.format.VerticalAlignment; import jxl.write.Label; import jxl.write.WritableCellFormat; import jxl.write.WritableFont; import jxl.write.WritableImage; import jxl.write.WritableSheet; import jxl.write.WritableWorkbook; import sun.misc.BASE64Decoder; public class JxlUtil { public static void write(WritableSheet sheet, String contentHtml) throws Exception{ Document doc = DocumentHelper.parseText(contentHtml); Element root = doc.getRootElement(); List<Integer> colsWidthList = getColsWidthList(root); setColWidth(sheet, colsWidthList); writeSheetData(sheet, root, 0, colsWidthList); } public static void write(HttpServletResponse response, String reportName, String contentHtml) { OutputStream output = null; WritableWorkbook book = null; // if(StringUtil.isEmpty(reportName)) { reportName = "导出数据.xls"; } // try { response.reset(); response.setContentType("application/x-download; charset=utf-8"); response.setHeader("Content-Disposition", "attachment; filename=" + new String(reportName.getBytes("utf-8"), "iso8859-1")); output = new BufferedOutputStream(response.getOutputStream()); book = Workbook.createWorkbook(output); // WritableSheet sheet = book.createSheet("导出数据", 0); // Document doc = DocumentHelper.parseText(contentHtml.replaceAll("", " ").replaceAll(" ", " ").replaceAll(" ", " ").replaceAll("&", "&")); Element root = doc.getRootElement(); List<Integer> colsWidthList = getColsWidthList(root); setColWidth(sheet, colsWidthList); writeSheetData(sheet, root, 0, colsWidthList); // book.write(); book.close(); response.flushBuffer(); output.close(); } catch (Exception e) { e.printStackTrace(); } finally { FileUtil.closeOutputStream(output); } } /** * 设置列宽 */ private static void setColWidth(WritableSheet sheet, List<Integer> colsWidthList) { // for(int i=0,size=colsWidthList.size();i<size;i++){ sheet.setColumnView(i, (int)(colsWidthList.get(i) / 6.5)); } } /** * 写表格数据 */ private static void writeSheetData(WritableSheet sheet, Element element, int rowNum, List<Integer> colsWidthList) throws Exception{ List<Element> items = element.elements(); if(items != null) { Iterator<Element> it = items.iterator(); while(it.hasNext()) { Element item = it.next(); // if("table".equals(item.getName())) { Map<Integer, Integer> colsWidthMap = getTableColsWidthMap(item); String tableTextAlign = getTextAlign(item); //row List<Element> rowItems = item.elements(); if(rowItems != null && rowItems.size() > 0) { Map<String, Integer> rowSpanMap = new HashMap<>(); // for(int i=0,rowSize=rowItems.size();i<rowSize;i++) { Element rowItem = rowItems.get(i); // if("tr".equals(rowItem.getName())) { String rowTextAlign = getTextAlign(rowItem); //row int rowHeight = 0; String backgroundColor = getStyleBackgroundColor(rowItem); // List<Element> colItems = rowItem.elements(); if(colItems != null && colItems.size() > 0) { int colIndex = 0; for(int j=0,colSize=colItems.size();j<colSize;j++) { Element colItem = colItems.get(j); // if("th".equals(colItem.getName()) || "td".equals(colItem.getName())) { if(rowSpanMap.get(colIndex+"_"+rowNum) != null) { colIndex++; } // String colBackgroundColor = getStyleBackgroundColor(colItem); // int lineNum = 0; int lineHeight = 0; // String colTextAlign = getTextAlign(colItem); String colVerticalAlign = getStyleValue(colItem, "vertical-align:"); String fontSize = getFontSize(colItem); //col WritableFont wf = new WritableFont(WritableFont.ARIAL, 10, WritableFont.NO_BOLD, false, UnderlineStyle.NO_UNDERLINE, jxl.format.Colour.BLACK); if("th".equals(colItem.getName())) { wf.setBoldStyle(WritableFont.BOLD); } if(!StringUtil.isEmpty(fontSize)) { wf.setPointSize(Integer.parseInt(fontSize)); } // lineHeight = wf.getPointSize() * 26; // WritableCellFormat cellFormat = new WritableCellFormat(wf); if(item.attributeValue("noExportBorder") == null) { cellFormat.setBorder(Border.ALL, BorderLineStyle.THIN); } cellFormat.setWrap(true); if("top".equals(colVerticalAlign)) { cellFormat.setVerticalAlignment(VerticalAlignment.TOP); } else if("center".equals(colVerticalAlign)) { cellFormat.setVerticalAlignment(VerticalAlignment.CENTRE); } else if("bottom".equals(colVerticalAlign)) { cellFormat.setVerticalAlignment(VerticalAlignment.BOTTOM); } else { cellFormat.setVerticalAlignment(VerticalAlignment.CENTRE); } if("center".equals(colTextAlign) || (colTextAlign == null && "center".equals(rowTextAlign)) || (colTextAlign == null && rowTextAlign == null && "center".equals(tableTextAlign))) { cellFormat.setAlignment(Alignment.CENTRE); } if(backgroundColor != null) { cellFormat.setBackground(Colour.GRAY_25); } if(colBackgroundColor != null) { //Color color = Color.decode(colBackgroundColor); cellFormat.setBackground(Colour.YELLOW); } String value = getCellContent(colItem); sheet.addCell(new Label(colIndex, rowNum, value, cellFormat)); // String rowspanStr = colItem.attributeValue("rowspan"); if(rowspanStr != null) { int rowspan = Integer.parseInt(rowspanStr); if(rowspan > 1) { sheet.mergeCells(colIndex, rowNum, colIndex, rowNum-1+rowspan); for(int k=1;k<rowspan;k++) { sheet.addCell(new Label(colIndex, rowNum+k, "", cellFormat)); rowSpanMap.put(colIndex+"_"+(rowNum+k), rowspan); } } } // String width = getStyleWidth(colItem); if(!StringUtil.isEmpty(width)) { int w = Integer.parseInt(width); // String lineArr[] = value.split("\n"); if(value.endsWith("\n")) { lineNum++; } Font font = new Font(wf.getName(), wf.getBoldWeight(), wf.getPointSize()); JComponent jc = new JLabel(); FontMetrics fm = jc.getFontMetrics(font); for(int m=0;m<lineArr.length;m++) { int lineWidth = fm.stringWidth(lineArr[m]); if(lineWidth == 0) { lineNum++; } else { lineNum += lineWidth/((12*w)/20); if(lineWidth%((12*w)/20) > 0) { lineNum++; } } } // int count = 0; for(int k=colIndex;k<colsWidthList.size();k++) { if(w >= colsWidthList.get(k)) { w -= colsWidthList.get(k); count++; } else { break; } // if(w == 0) { break; } } // if(count > 1) { sheet.mergeCells(colIndex, rowNum, colIndex-1+count, rowNum); } colIndex += count; // int tempRowHeight = lineNum * lineHeight; if(tempRowHeight > rowHeight) { rowHeight = tempRowHeight; } } } } } // String height = getStyleHeight(rowItem); if(!StringUtil.isEmpty(height)) { int setHeight = Integer.parseInt(height)*15; sheet.setRowView(rowNum, rowHeight > setHeight ? rowHeight : setHeight); } else { sheet.setRowView(rowNum, rowHeight); } // rowNum++; } } } } else { writeSheetData(sheet, item, rowNum, colsWidthList); } } } } /** * 获得列宽列表 */ private static List<Integer> getColsWidthList(Element element) { List<Map<Integer, Integer>> colsMapList = new ArrayList<>(); getTableColsWidthMapList(element, colsMapList); // List<Integer> colsWidthList = new ArrayList<>(); for(Map<Integer, Integer> itemMap : colsMapList) { if(colsWidthList.size() == 0) { for(int i=0,size=itemMap.keySet().size();i<size;i++) { colsWidthList.add(itemMap.get(i)); } } else { Integer index = 0; for(int i=0,size=itemMap.keySet().size();i<size;i++) { Integer width = itemMap.get(i); for(int j=index,length=colsWidthList.size();j<length;j++) { Integer wh = colsWidthList.get(j); if(width < wh) { colsWidthList.remove(j); colsWidthList.add(j, wh-width); colsWidthList.add(j, width); index = j+1; break; } else if(width > wh){ width -= wh; } else { index = j+1; break; } } } } } return colsWidthList; } /** * 获得table的列宽map列表 */ private static void getTableColsWidthMapList(Element element, List<Map<Integer, Integer>> colsMapList) { List<Element> items = element.elements(); if(items != null) { Iterator<Element> it = items.iterator(); while(it.hasNext()) { Element item = it.next(); // if("table".equals(item.getName())) { Map<Integer, Integer> map = getTableColsWidthMap(item); setColWidth(item, map); colsMapList.add(map); } else { getTableColsWidthMapList(item, colsMapList); } } } } /** * 高置列的宽度 */ private static void setColWidth(Element element, Map<Integer, Integer> map) { List<Element> rowItems = element.elements(); if(rowItems != null && rowItems.size() > 0) { int rowNum = 0; Map<String, Integer> rowSpanMap = new HashMap<>(); for(int i=0,rowSize=rowItems.size();i<rowSize;i++) { Element rowItem = rowItems.get(i); // if("tr".equals(rowItem.getName())) { List<Element> colItems = rowItem.elements(); if(colItems != null && colItems.size() > 0) { int colIndex = 0; Iterator<Element> colIt = colItems.iterator(); while(colIt.hasNext()) { Element colItem = colIt.next(); // if("th".equals(colItem.getName()) || "td".equals(colItem.getName())) { String rowspanStr = colItem.attributeValue("rowspan"); if(rowspanStr != null) { int rowspan = Integer.parseInt(rowspanStr); if(rowspan > 1) { for(int k=1;k<rowspan;k++) { rowSpanMap.put(colIndex+"_"+(rowNum+k), rowspan); } } } // if(rowSpanMap.get(colIndex+"_"+rowNum) != null) { colIndex++; } // String colspanStr = colItem.attributeValue("colspan"); int width = 0; if(colspanStr == null) { width = map.get(colIndex); colIndex++; } else { int colspan = Integer.parseInt(colspanStr); for(int k=colIndex;k<colspan+colIndex;k++) { width += map.get(k); } colIndex += colspan; } setStyleWidth(colItem, width); } } } rowNum++; } } } } /** * 获得table的列宽map key: 列位置 value: 宽度 */ private static Map<Integer, Integer> getTableColsWidthMap(Element element) { Map<Integer, Integer> map = new HashMap<>(); List<Element> colGroupList = element.elements("colgroup"); if(colGroupList != null && colGroupList.size() > 0) { List<Element> colList = colGroupList.get(0).elements("col"); if(colList != null && colList.size() > 0) { for(int i=0,size=colList.size();i<size;i++) { Element colItem = colList.get(i); String width = colItem.attributeValue("width"); map.put(i, Integer.parseInt(width)); } return map; } } // Map<String, Integer> colSpanMap = new HashMap<>(); //row List<Element> rowItems = element.elements(); if(rowItems != null && rowItems.size() > 0) { for(int i=0,rowSize=rowItems.size();i<rowSize;i++) { Element rowItem = rowItems.get(i); // if("tr".equals(rowItem.getName())) { List<Element> colItems = rowItem.elements(); if(colItems != null && colItems.size() > 0) { int j = 0; Iterator<Element> colIt = colItems.iterator(); while(colIt.hasNext()) { Element colItem = colIt.next(); // if("th".equals(colItem.getName()) || "td".equals(colItem.getName())) { // String colspanStr = colItem.attributeValue("colspan"); String width = getStyleWidth(colItem); if(colspanStr == null) { if(width != null) { map.put(j, Integer.parseInt(width)); } else if(!map.keySet().contains(j)) { map.put(j, null); } j++; } else { Integer colspan = Integer.parseInt(colspanStr); String key = j + "-" + (j - 1 + colspan); if(width != null) { colSpanMap.put(key, Integer.parseInt(width)); } for(int k=j;k<colspan;k++) { if(!map.keySet().contains(k)) { map.put(k, null); } } j += colspan; } } } } } } } //根据colspan计算宽度 for(Integer index : map.keySet()) { Integer width = map.get(index); if(width == null) { for(String key : colSpanMap.keySet()) { String indexArr[] = key.split("-"); int startIndex = Integer.parseInt(indexArr[0]); int endIndex = Integer.parseInt(indexArr[1]); if(index >= startIndex && index <= endIndex) { Integer colSpanWidth = colSpanMap.get(key); boolean flag = true; for(int i=startIndex;i<=endIndex;i++) { if(i != index) { Integer itemWidth = map.get(i); if(itemWidth == null) { flag = false; break; } colSpanWidth -= map.get(i); } } // if(flag) { map.put(index, colSpanWidth); } } } } } //根据table宽度计算列宽度 String tableWidthStr = getStyleWidth(element); tableWidthStr = tableWidthStr == null ? element.attributeValue("width") : tableWidthStr; if(tableWidthStr != null) { Integer pindex = null; boolean flag = true; int totalWidth = Integer.parseInt(tableWidthStr.replaceAll("px", "").trim()); for(Integer index : map.keySet()) { Integer width = map.get(index); if(width == null) { if(pindex != null) { flag = false; pindex = null; break; } pindex = index; } else { totalWidth -= width; } } // if(flag && pindex != null) { map.put(pindex, totalWidth); } } return map; } /** * 获得水平对齐方式 */ private static String getStyleValue(Element element, String key) { String value = null; String style = element.attributeValue("style"); // if(!StringUtil.isEmpty(style)) { String styleArr[] = style.split(";"); for(String sItem : styleArr) { String prop = sItem.trim(); if(prop.startsWith(key)) { value = prop.replaceAll(key, "").trim(); } } } return value; } /** * 获得水平对齐方式 */ private static String getFontSize(Element element) { String fontSize = null; String style = element.attributeValue("style"); // if(!StringUtil.isEmpty(style)) { String styleArr[] = style.split(";"); for(String sItem : styleArr) { String prop = sItem.trim(); if(prop.startsWith("font-size:")) { fontSize = prop.replaceAll("font-size:", "").replaceAll("px", "").trim(); } } } return fontSize; } /** * 获得水平对齐方式 */ private static String getTextAlign(Element element) { String textAlign = null; String style = element.attributeValue("style"); // if(!StringUtil.isEmpty(style)) { String styleArr[] = style.split(";"); for(String sItem : styleArr) { String prop = sItem.trim(); if(prop.startsWith("text-align:")) { textAlign = prop.replaceAll("text-align:", "").trim(); } } } return textAlign; } /** * 获得背景颜色 */ private static String getStyleBackgroundColor(Element element) { String backgroundColor = null; String style = element.attributeValue("style"); // if(!StringUtil.isEmpty(style)) { String styleArr[] = style.split(";"); for(String sItem : styleArr) { String prop = sItem.trim(); if(prop.startsWith("background-color:")) { backgroundColor = prop.replaceAll("background-color:", "").trim(); } } } return backgroundColor; } /** * 设置样式宽度 */ private static void setStyleWidth(Element element, Integer width) { String style = element.attributeValue("style"); StringBuffer buffer = new StringBuffer(); // if(!StringUtil.isEmpty(style)) { String styleArr[] = style.split(";"); for(String sItem : styleArr) { String prop = sItem.trim(); if(!prop.startsWith("width:")) { buffer.append(prop); buffer.append(";"); } } } buffer.append("width:"); buffer.append(width.toString()); buffer.append("px;"); // element.addAttribute("style", buffer.toString()); } /** * 获得样式宽度 */ private static String getStyleWidth(Element element) { String width = null; String style = element.attributeValue("style"); // if(!StringUtil.isEmpty(style)) { String styleArr[] = style.split(";"); for(String sItem : styleArr) { String prop = sItem.trim(); if(prop.startsWith("width:")) { width = prop.replaceAll("width:", "").replaceAll("px", "").trim(); } } } return width; } /** * 获得样式高度 */ private static String getStyleHeight(Element element) { String height = null; String style = element.attributeValue("style"); // if(!StringUtil.isEmpty(style)) { String styleArr[] = style.split(";"); for(String sItem : styleArr) { String prop = sItem.trim(); if(prop.startsWith("height:")) { height = prop.replaceAll("height:", "").replaceAll("px", "").trim(); } } } return height; } /** * 是否显示内容 */ private static boolean isDispaly(Element element) { String style = element.attributeValue("style"); if(!StringUtil.isEmpty(style)) { String styleArr[] = style.split(";"); for(String prop : styleArr) { String propArr[] = prop.split(":"); if(propArr.length == 2 && "display".equals(propArr[0].trim()) && "none".equals(propArr[1].trim())) { return false; } } } return true; } /** * 是否流布局 */ private static boolean isFloatLayout(Element element) { String style = element.attributeValue("style"); if(!StringUtil.isEmpty(style)) { String styleArr[] = style.split(";"); for(String prop : styleArr) { String propArr[] = prop.split(":"); if(propArr.length == 2 && "float".equals(propArr[0].trim())) { return true; } } } return false; } /** * 获得单元格内容 */ private static String getCellContent(Element element) { if(!isDispaly(element)) { return " "; } // StringBuffer buffer = new StringBuffer(); if(element.elements() == null || element.elements().size() == 0){ if(element.getText().length() == 0) { buffer.append(" "); } else { buffer.append(element.getText()); } } // List<Element> items = element.elements(); // if(items != null) { boolean isFirst = true; for(int i=0,size=items.size();i<size;i++){ Element item = items.get(i); if(item.attributeValue("noExport") == null) { boolean floatLayout = isFloatLayout(item); if(!isFirst) { if(floatLayout) { buffer.append(" "); } else if (!floatLayout) { buffer.append(""); } } // getSubContent(item, buffer); // if(item.attributeValue("newLine") != null) { buffer.append("\n"); } isFirst = false; } } } return buffer.toString(); } /** * 获得单元格内容 */ private static void getSubContent(Element element, StringBuffer buffer) { if(element.getName().equalsIgnoreCase("xmp")) { String content = element.asXML(); buffer.append(content.substring(5, content.length() - 6)); return; } // if(!isDispaly(element)) { return; } // if(element.elements() == null || element.elements().size() == 0){ if(element.getText().length() == 0) { if("br".equals(element.getName())) { buffer.append("\n"); } else if("img".equalsIgnoreCase(element.getName())) { /*String imgSrc = element.attributeValue("src"); if(!StringUtil.isEmpty(imgSrc) && imgSrc.startsWith("data:image")) { GenerateImage(imgSrc.split(",")[1]); }*/ } else { buffer.append(""); } } else { buffer.append(element.getText()); } } else { Iterator<Node> it = element.nodeIterator(); while(it.hasNext()) { Node item = it.next(); if(item.getName() == null) { buffer.append(item.getText()); } else { Element itemEl = (Element)item; if(itemEl.attributeValue("noExport") == null) { getSubContent(itemEl, buffer); } } } } } /** * 关闭 */ public static void closeWritableWorkbook(WritableWorkbook book) { if(book != null) { try{ book.close(); } catch(Exception e) { e.printStackTrace(); } } } }