public class ExportReportForExcel implements IExportReport{
/**
* Function 生成Excel报表 CreateTime 2014年7月22日
*
* @author yyh
* @version 1.2.0
* @param HttpServletRequest
* request
* @param HttpServletResponse
* response
* @param Map
* <?,?> reportInfo 生成报表所需要的数据
*/
@Override
public void createReport(HttpServletRequest request,
HttpServletResponse response, Map<?, ?> reportInfo)
throws Exception {
String[] tableList = (String[]) reportInfo.get("tableList");
// 判断生成数据是否为空
if (tableList == null || tableList.length < 0) {
System.out.println("没有导出数据");
}
// 设置文件响应信息
String showFileName = URLEncoder.encode(reportInfo.get("title") + ".xls", "UTF-8");
showFileName = new String(showFileName.getBytes("iso8859-1"), "gb2312");
// 定义输出类型
response.reset();
response.setContentType("application/msexcel");
response.setHeader("Pragma", "public");
response.setHeader("Cache-Control", "max-age=30");
response.setHeader("Content-disposition", "attachment; filename="
+ new String(showFileName.getBytes("gb2312"), "iso8859-1"));
// 生成Excel并响应客户端
ServletOutputStream out = response.getOutputStream();
ByteArrayOutputStream bos = (ByteArrayOutputStream) getStream(reportInfo);
response.setContentLength(bos.size());
bos.writeTo(out);
out.close();
out.flush();
bos.close();
bos.flush();
}
/**
* Function 构建报表数据 CreateTime 2014年7月22日
*
* @author yyh
* @version 1.2.0
* @param reportInfo
* 生成报表所需要的数据
* @return OutputStream
* @throws IOException
* @throws BadElementException
*/
private OutputStream getStream(Map<?, ?> reportInfo) throws IOException,
BadElementException {
// 实例化HSSFWorkbook
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet("" + reportInfo.get("title"));
// 创建表头样式
HSSFCellStyle cellStyle = wb.createCellStyle();
// 文本位置(居中)
cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
// 设置字体
HSSFFont font = wb.createFont();
font.setFontName("宋体");
font.setFontHeightInPoints((short) 10);// 字体大小
font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);// 加粗
// font.setColor(HSSFColor.BLUE.index);//字体颜色
cellStyle.setFont(font);
cellStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);
cellStyle.setBorderRight(HSSFCellStyle.BORDER_THIN);
cellStyle.setBorderTop(HSSFCellStyle.BORDER_THIN);
cellStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN);
String[] tableCaptionList = (String[]) reportInfo.get("tableCaptionList");
String[] tableList = (String[]) reportInfo.get("tableList");
String[] tableColList = (String[]) reportInfo.get("tableColList"); // 记录每一个<table>的最大列数
int rowIndex = 0;
HSSFRow row = null;
HSSFCell cell = null;
BufferedImage bufferImg = null;
for (int a = 0; a < tableColList.length; a++) {
int tableRowIndex = 0;
String colInfo = tableColList[a];
String colStr = colInfo.indexOf("#PAGINATION#") >= 0 ? colInfo.substring(0,colInfo.indexOf("#PAGINATION#")) : colInfo;
colStr = colStr.indexOf("#NOBORDER#") >= 0 ? colStr.substring(0,colStr.indexOf("#PAGINATION#")) : colStr;
int col = Integer.parseInt(colStr);
boolean flag = false; // 判断是否存在图片
if (tableCaptionList.length > 0) {
sheet.addMergedRegion(new CellRangeAddress(rowIndex, rowIndex, 0, col-1));// 合并 --> 用于跨行、跨列
row = sheet.createRow(rowIndex);
cell = row.createCell(a);
cell.setCellValue(tableCaptionList[a]);
cell.setCellStyle(cellStyle);
flag = tableCaptionList[a].indexOf("#IMG#") >= 0 ? true : false;
}
if (col > 0) {
if (rowIndex > 0) {
rowIndex++;
}
String[] rows = null;
Object[][] cellInfo = null;
for (int j = 0; j < tableList.length; j++) {
if (a == j) {
rows = tableList[j].split("#ROW#");
// 截取<table>对应行<row>对应列<td>的值存入二维数组
for (int k = 0; k < rows.length; k++) {
String tds[] = rows[k].split("#TD#");
if (cellInfo == null) {
cellInfo = new Object[rows.length][tds.length];
}
cellInfo[k] = tds;
}
/*
* 数组rowsInfo记录<table>对应位置的状态信息(指<td>的状态)
*
* 1、跨行标识:(1111/1122) 如:状态1111 表示该<td>被当前行所跨;状态1122 表示该<td>被当前行之前的行所跨
*
* 2、跨列标识:(2222/2233) 如:状态2222 表示该<td>是所跨列中最后一列之前的列;状态2233 表示该<td>是所跨列中最后的一列
*
* 3、跨行且跨列标志:(1111/1122) 为了方便操作,使用跨行标识
*
* 4、不跨行且不跨列标志:0 (数组的默认值)
*
* 说明:如跨行标识:(1111/1122)使用两种标志是为了方便识别某<td>的状态,与使用一种状态(如1111)效果一样
*
*/
int [][] rowsInfo = new int[rows.length][col];
// 生成excel数据
for (int rNum = 0; rNum < cellInfo.length; rNum++) {
if (tableCaptionList.length == 0 && rNum == 0) {
rowIndex--;
}
row = sheet.createRow(++rowIndex);
Object[] dataExcel = cellInfo[rNum];
boolean preHasRowSpan = false;// 记录当前行是否存在跨行(针对当前行被之前的行所跨的情况)
for (int l = 0; l < col ; l++) {
if (rowsInfo[tableRowIndex][l]==1122) {
preHasRowSpan = true;
break;
}
}
/*
* currentRow: 用于保存当前行对应位置的实时状态信息
*
* 如:currentRow[0]=1122 表示 当前行 的第一个<td>已被 前面的行 所占用
* 如:currentRow[0]=1234 表示 当前行 的第一个<td>已被 当前行 占用
* 如:currentRow[0]=0 表示 当前行 的第一个<td>未被占用
*
* int[] currentRow = rowsInfo[tableRowIndex];
* 数组为对象是引用传递,故而重新new一个数组
*/
int[] currentRow = new int[rowsInfo[tableRowIndex].length] ;
for (int i = 0; i < currentRow.length; i++) {
currentRow[i] = rowsInfo[tableRowIndex][i];
}
for (int cNum = 0; cNum < dataExcel.length; cNum++) {
String data = dataExcel[cNum].toString();
if (flag) {// 图片
ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
// ImageIO.read(参数):
// 参数是File时,只能是本地路径,如:e:/login.jpg
// 参数是URL时,可以是远程路径 ,
// 如:http://localhost:8080/eam/temp/login.jpg
bufferImg = ImageIO.read(new URL(URLDecoder.decode(data.trim(),"utf-8")));
ImageIO.write(bufferImg,"jpg",byteArrayOut);
HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0, 512, 255,(short) 1, 1,(short) 10, 20);
// 插入图片
patriarch.createPicture(anchor,wb.addPicture(byteArrayOut.toByteArray(),HSSFWorkbook.PICTURE_TYPE_JPEG));
} else {
String value = data.indexOf("#COLSPAN#") >= 0 ? data.substring(0,data.indexOf("#COLSPAN#")) : data;
value = value.indexOf("#ROWSPAN#") >= 0 ? value.substring(0,value.indexOf("#ROWSPAN#")) : value;
value = value.indexOf("#ALIGN#") >= 0 ? value.substring(value.indexOf("#ALIGN#")+7) : value;
value = value.indexOf("#VALIGN#") >= 0 ? value.substring(value.indexOf("#VALIGN#")+8) : value;
int tempNum = cNum; // 标识当前<td>在写入的excel中的位置
// 获取该<td>在Excel中(Cell)的位置
tempNum = getCurrentCellIndex(
tableRowIndex, col,
preHasRowSpan,
currentRow, cNum,
tempNum);
// 跨行、跨列
setRowSpanAndColSpan(sheet,
rowIndex,
tableRowIndex,
rowsInfo, currentRow,
data, tempNum);
cellStyle = setAlign(wb, data);// 对齐方式 (针对单个的Cell)
cell = row.createCell(tempNum);// 为该<td>创建对应Cell
cell.setCellValue(" " + value);
cell.setCellStyle(cellStyle);
}
}
tableRowIndex++;
}
//
}
}
}
}
// 写入字节流
ByteArrayOutputStream bos = new ByteArrayOutputStream();
wb.write(bos);
// 返回bos
return bos;
}
/**
* 水平对齐方式、垂直对齐方式 控制
* @param cellStyle 样式
* @param data <td>的内容
*/
private HSSFCellStyle setAlign(HSSFWorkbook wb , String data) {
String alignStr = data;
HSSFCellStyle cellStyle = wb.createCellStyle(); // 创建表格体样式
// 默认
cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 水平居中
cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 垂直居中
cellStyle.setWrapText(true); // 自动换行
cellStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);
cellStyle.setBorderRight(HSSFCellStyle.BORDER_THIN);
cellStyle.setBorderTop(HSSFCellStyle.BORDER_THIN);
cellStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN);
// 水平对齐方式:居中、右、左对齐
if (alignStr.indexOf("#ALIGN#") >=0) {
String align = alignStr.substring(0, alignStr.indexOf("#ALIGN#")).trim();
if ("right".equals(align)) {
cellStyle.setAlignment(HSSFCellStyle.ALIGN_RIGHT);
}else if ("left".equals(align)) {
cellStyle.setAlignment(HSSFCellStyle.ALIGN_LEFT);
}else if ("center".equals(align)) {
cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
}
}
// 垂直对齐方式:
if (alignStr.indexOf("#VALIGN#") >=0) {
String vAlign = alignStr.substring(alignStr.indexOf("#ALIGN#")>=0?(alignStr.indexOf("#ALIGN#")+7):0, alignStr.indexOf("#VALIGN#")).trim();
if ("top".equals(vAlign)) {
cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_TOP);
}else if ("bottom".equals(vAlign)) {
cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_BOTTOM);
}else if ("middle".equals(vAlign)) {
cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
}
}
return cellStyle;
}
/**
* 获取该<row>下当前<td>在Excel中(Cell)的位置(解决跨行跨列情况中Cell下标的控制)
*
* @param tableRowIndex 标识二维数组 rowsInfo[row][col] 的外层下标
* @param col 标识<table>的最大列数
* @param preHasRowSpan 记录当前行<row>是否存在跨行(针对当前行被之前的行所跨的情况)
* @param currentRow 记录当前行<row>对应位置的实时状态信息(指<td>的状态)
* @param cNum
* @param tempNum 标识当前<td>在写入的Excel(Cell)中的位置
* @return
*
* @author yyh createTime 2014-07-22
*
*/
private int getCurrentCellIndex(int tableRowIndex, int col,
boolean preHasRowSpan, int[] currentRow, int cNum, int tempNum) {
if (preHasRowSpan) {
if (tableRowIndex > 0) {
int usedNum = 0; // 记录当前行被使用(跨行或跨列)的最后一个<td>的下标
if (cNum==0) {
for (int i = 0; i < col ; i++) {
if (currentRow[i]==1122) {
usedNum ++;
continue;
}
break;
}
}else{
for (int i = 0; i < col ; i++) {
if (currentRow[i]==1234) {
usedNum = i;
}
}
usedNum ++; // +1 标识当前被使用的最后一个td的下一个td的下标
int num = 0;
for (int i = 0; i < col ; i++) {
if (currentRow[usedNum+i]==1122) { // 判断当前被使用的最后一个td的下一个td是否跨行
num ++;
continue;
}
break;
}
usedNum = usedNum + num;
}
tempNum = usedNum;
}
}else{
for (int i = 0; i < col ; i++) {
if (currentRow[i]==1234) {
tempNum = i+1;
}
}
}
return tempNum;
}
/**
* Excel 跨行跨列控制
*
* @param sheet sheet对象
* @param rowIndex 标识sheet的行下标
* @param tableRowIndex 标识二维数组 rowsInfo[row][col] 的外层下标
* @param rowsInfo 记录<table>对应位置的状态信息(指<td>的状态)
* @param currentRow 记录当前行<row>对应位置的实时状态信息(指<td>的状态)
* @param data <td>的内容
* @param tempNum 标识当前<td>在写入的Excel(Cell)中的位置
*
* @author yyh createTime 2014-07-22
*
*/
private void setRowSpanAndColSpan(HSSFSheet sheet, int rowIndex,
int tableRowIndex, int[][] rowsInfo, int[] currentRow, String data,
int tempNum) {
int colspan = 0;
int rowspan = 0;
// 跨行、跨列
if (data.indexOf("#COLSPAN#") >= 0 && data.indexOf("#ROWSPAN#") >= 0) {
colspan = Integer.parseInt(data.substring(data.indexOf("#COLSPAN#")+9).trim());
rowspan = Integer.parseInt(data.substring(data.indexOf("#ROWSPAN#")+9 , data.indexOf("#COLSPAN#")).trim());
}else if (data.indexOf("#ROWSPAN#") >= 0) {// 跨行
rowspan = Integer.parseInt(data.substring(data.indexOf("#ROWSPAN#")+9).trim());
}else if (data.indexOf("#COLSPAN#") >= 0) {// 跨列
colspan = Integer.parseInt(data.substring(data.indexOf("#COLSPAN#")+9).trim());
}
if (rowspan > 1 && colspan > 1) { // 跨行、跨列
// 跨行且跨列 使用跨行的状态标志
sheet.addMergedRegion(new CellRangeAddress(rowIndex, rowIndex+rowspan-1, tempNum, tempNum+colspan-1));
for (int l = 0; l < rowspan; l++) {
for (int i = 0; i < colspan; i++) {
currentRow[tempNum+i] = 1234;
if (l > 0) {
rowsInfo[tableRowIndex+l][tempNum+i] = 1122;
}else{
rowsInfo[tableRowIndex+l][tempNum+i] = 1111; // 用于标识跨行的第一行
}
}
}
}else if (rowspan > 1){ //只跨行的单元格合并方法
sheet.addMergedRegion(new CellRangeAddress(rowIndex, rowIndex+rowspan-1, tempNum, tempNum));
for (int i = 0; i < rowspan; i++) {
if (i > 0) {
rowsInfo[tableRowIndex+i][tempNum] = 1122;
}else{
rowsInfo[tableRowIndex+i][tempNum] = 1111; // 用于标识跨行的第一行
}
}
currentRow[tempNum] = 1234; // 用于标识当前位置已经被占用
}else if (colspan > 1){ //只跨列的单元格合并方法
sheet.addMergedRegion(new CellRangeAddress(rowIndex, rowIndex, tempNum, tempNum+colspan-1));
for (int i = 0; i < colspan; i++) {
currentRow[tempNum+i] = 1234; // 用于标识当前位置已经被占用
if (i==(colspan-1)) {
rowsInfo[tableRowIndex][tempNum+i] = 2233; // 用于标识跨列的最后一列
}else{
rowsInfo[tableRowIndex][tempNum+i] = 2222;
}
}
}else{ // 不跨行、不跨列
currentRow[tempNum]=1234;
}
}
}