一、使用说明
实际开发运用过程中,往往需要将页面上的一些表格数据生成Excel供用户下载使用,根据不同的需求,此处整理了两种方式:(两种方式浏览器都可直接提示下载或保存文件)
方式一:
1、需求:
生成的Excel跟页面上格式、数据、字段完全一样,且表格无多余操作控件(如下拉框等),并使用IE浏览器。
2、思路:
利用IE浏览器的ActiveX控件,借助剪贴板工具控件,直接将数据粘贴成为Excel。本质就是复制粘贴,要保证IE浏览器设 置里的ActiveX控件启用,以及允许对剪贴板进行编程访问。
3、优缺点:
优点:快捷、方便、即使表格数据量很大也能秒生成,完整保留表格样式;
缺点:使用条件苛刻,且只满足单一的对数据的复制粘贴。
方式二:
1、需求
需要对数据进行处理、计算、并对Excel的字段、样式进行个性化设置。
2、思路:
对表单数据进行封装处理,传到后台(或从后台数据库读取),拿到数据后根据需求进行计算处理,然后利用org.apache.poi.jar对将数据按照个性化写入Excel。(注:Apache POI 是用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程式对Microsoft Office格式档案读和写的功能。)
3、优缺点:
优点:可对数据进行后台读取、计算处理、对Excel进行个性化设置、可扩展性强;
缺点:生成速度慢、开发工作量相对大。
二、代码演示:
方式一:在做好相关设置后,直接调用如下代码就可下载表格:
//导出
$("#export").click(function() {
/**thead的id**/
//var tHeadId = "tableHead";
//**tbody的id**//
//var tBodyId = "dataView";
//expStatisticsForm(tHeadId, tBodyId);
var elTable = document.getElementById("exportTable");
try{
var oRangeRef = document.body.createTextRange();
oRangeRef.moveToElementText( elTable );
oRangeRef.execCommand( "Copy" );
var appExcel = new ActiveXObject( "Excel.Application" );
appExcel.Visible = true;
appExcel.Workbooks.Add().Worksheets.Item(1).Paste();
appExcel = null;
}catch (e) {
window.parent.parent.layerAlert("提示", "要在项目中使用Excel,您必须安装微软Office Excel或者金山WPS,同时浏览器须允许执行ActiveX控件(使用IE浏览器)!");
return ;
}
});
其中,“exporttTable”为需要导出的表格的ID。
方式二:此情况又分为两种情况:(实际是请求和参数传递的差异)
1、参数少,数据从后台数据库读取,字段、列宽等后台给定。
直接使用get请求:window.location.href= webCfg.servePath + "/mbgl/fileDownload/"+id 到后台下载,其中webCfg.servePath为服务根目录,id为传递的参数,后台拿到ID再根据需求取得数据处理生成Excel。
2、参数多,数据量大,(如:前端传入表数据、指定表字段、Excel样式)
此种情况采用隐藏表单发送post请求的方式:
前端具体实现如下(实际开发案例):
/**导出表单的内容为Excel**/
function exportExcel(){
var title = $("#title").val().trim();//标题
var sheetName = "绩效考核表";//sheet名
//表头信息
var tableHeads = [];
var headTr = $("#itemTable tr:eq(2)");
$(headTr).children('th').each(function(j){
if(j==0){
tableHeads.push("序号");
}else{
tableHeads.push($(this).text());
}
});
var tdWidths = ["50","100","100","100","100","150","100","100","150"];//列宽
var colKeys = ["num","orgName","unitName","targetName","rule","content","score","propUnitName","remark"];//表字段对应实体类的字段
//封装表格数据
var dataList = [];
var dataTrLength = $("#itemTable tr").length;
if(dataTrLength>3){//有数据
for(var i= 3;i var dataItem = {}; dataItem.num = i-2; var thisTr = $("#itemTable tr:eq("+i+")"); dataItem.orgName = $(thisTr).find("input[name='orgName']").val().trim();//单位名称 dataItem.unitName = $(thisTr).find("input[name='unitName']").val().trim();//部门名称 dataItem.targetName = $(thisTr).find("input[name='targetName']").val().trim();//姓名 dataItem.rule = $(thisTr).find("input[name='rule']").val().trim();//考核条款 dataItem.content = $(thisTr).find("textarea[name='content']").val().trim();//考核事项 dataItem.score = $(thisTr).find("input[name='score']").val().trim();//考核分值 dataItem.propUnitName = $(thisTr).find("input[name='propUnitName']").val().trim();//提出部门 dataItem.remark = $(thisTr).find("textarea[name='remark']").val().trim();//备注 dataList.push(dataItem); }; }; dataList = JSON.stringify(dataList); //利用隐藏表单发送请求下载Excel var form = $("
form.attr('style', 'display:none');
form.attr('target', '');
form.attr('method', 'post');
form.attr('action', webCfg.servePath + "/pc/jxkh/exportExcel");
var input1 = $('');
input1.attr('type', 'hidden');
input1.attr('name', 'title');
input1.attr('value', title);
var input2 = $('');
input2.attr('type', 'hidden');
input2.attr('name', 'sheetName');
input2.attr('value', sheetName);
var input3 = $('');
input3.attr('type', 'hidden');
input3.attr('name', 'tableHeads');
input3.attr('value', JSON.stringify(tableHeads));
var input4 = $('');
input4.attr('type', 'hidden');
input4.attr('name', 'tdWidths');
input4.attr('value', JSON.stringify(tdWidths));
var input5 = $('');
input5.attr('type', 'hidden');
input5.attr('name', 'colKeys');
input5.attr('value', JSON.stringify(colKeys));
var input6 = $('');
input6.attr('type', 'hidden');
input6.attr('name', 'dataList');
input6.attr('value', dataList);
$('body').append(form);
form.append(input1);
form.append(input2);
form.append(input3);
form.append(input4);
form.append(input5);
form.append(input6);
form.submit();
form.remove();
};
封装时注意input的value只能装字符串,对于对象可转换为字符串到后台再转换回对象。
Controller实现如下:
/**
*
*
Title: exportExcel
*
Description: 下载表单到Excel
* @param request
* @throws IOException
* @throws JsonMappingException
* @throws JsonParseException
*/
@RequestMapping(value = "/exportExcel", method = RequestMethod.POST)
public void exportExcel(HttpServletRequest request, HttpServletResponse response) throws JsonParseException,
JsonMappingException, IOException {
String title = request.getParameter("title");//标题
String sheetName = request.getParameter("sheetName");//sheet名
String tableHeadsStr = request.getParameter("tableHeads");//表头
String[] tableHeads = tableHeadsStr.substring(2, tableHeadsStr.length() - 2).split("\",\"");
String tdWidthsStr = request.getParameter("tdWidths");//列宽
String[] tdWidths = tdWidthsStr.substring(2, tdWidthsStr.length() - 2).split("\",\"");
String colKeysStr = request.getParameter("colKeys");//数据对应实体字段
String[] colKeys = colKeysStr.substring(2, colKeysStr.length() - 2).split("\",\"");
String dataStr = request.getParameter("dataList");//JSON数据字符串
//json字符串转对象集合
List
if (StringUtils.isNotEmpty(dataStr)) {
JsonMapper jsonMapper = JsonMapper.buildNonDefaultMapper();
dataList = jsonMapper.getMapper().readValue(dataStr, new TypeReference>() {
});
}
//调用工具下载Excel
ExportExcelUtil.ExportExcel(title, sheetName, tableHeads, colKeys, tdWidths, dataList, request, response);
}
这里数据由前端传入,当然也可以获取到前端传入的参数后从后台数据库获取数据进行处理。
ExportExcelUtil工具封装如下:
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.util.CellRangeAddress;
/**
*
*
* Title: ExportExcelUtil
*
*
* Description:导出下载Excel的工具类
*
*
* @author liuc
* @date 2019年1月10日
*/
public class ExportExcelUtil {
private static HSSFWorkbook workbook;
private static HSSFSheet sheet;
/**
*
*
* Title: ExportExcel
*
*
* Description:导出Excel的方法
*
*
* @param title
* 标题
* @param tableHeads
* 表头数组
* @param colWidths
* 列宽数组
* @param dataList
* 数据集合
* @throws IOException
*/
public static void ExportExcel(String title, String sheetName, String[] tableHeads, String[] colKeys,
String[] colWidths, List
throws IOException {
InputStream input = (getExcelFile(title, dataList, sheetName, tableHeads, colKeys, colWidths));
HSSFWorkbook book = new HSSFWorkbook(input);
OutputStream output = null;
try {
output = response.getOutputStream();
response.reset();
response.setHeader("Content-disposition", "attachment; filename=" + URLEncoder.encode(title, "UTF-8"));
response.setContentType("application/vnd.ms-excel;charset=utf-8");
response.setCharacterEncoding("utf-8");
book.write(output);
output.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (output != null) {
output.close();
}
}
}
/**
* 创建行元素
*
* @param style
* 样式
* @param height
* 行高
* @param value
* 行显示的内容
* @param row1
* 起始行
* @param row2
* 结束行
* @param col1
* 起始列
* @param col2
* 结束列
*/
private static void createRow(HSSFCellStyle style, int height, String value, int row1, int row2, int col1, int col2) {
sheet.addMergedRegion(new CellRangeAddress(row1, row2, col1, col2)); // 设置从第row1行合并到第row2行,第col1列合并到col2列
HSSFRow rows = sheet.createRow(row1); // 设置第几行
rows.setHeight((short) height); // 设置行高
HSSFCell cell = rows.createCell(col1); // 设置内容开始的列
cell.setCellStyle(style); // 设置样式
cell.setCellValue(value); // 设置该行的值
}
/**
* 创建样式
*
* @param fontSize
* 字体大小
* @param align
* 水平位置 左右居中2 居右3 默认居左 垂直均为居中
* @param bold
* 是否加粗
* @return
*/
private static HSSFCellStyle getStyle(int fontSize, int align, boolean bold, boolean border) {
HSSFFont font = workbook.createFont();
font.setFontName("宋体");
font.setFontHeightInPoints((short) fontSize);// 字体大小
if (bold) {
font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
}
HSSFCellStyle style = workbook.createCellStyle();
style.setFont(font); // 设置字体
style.setAlignment((short) align); // 左右居中2 居右3 默认居左
style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);// 上下居中1
if (border) {
style.setBorderRight((short) 2);
style.setBorderLeft((short) 2);
style.setBorderBottom((short) 2);
style.setBorderTop((short) 2);
style.setLocked(true);
}
return style;
}
/**
*
*
* Title: getExcelFile
*
*
* Description: 根据传入的参数,返回InputStream对象
*
*
* @param title
* @param dataList
* @param sheetName
* @param tableHeads
* @param colWidths
* @return
* @throws IOException
*/
public static InputStream getExcelFile(String title, List
String[] colKeys, String[] colWidths) throws IOException {
workbook = new HSSFWorkbook();
sheet = workbook.createSheet(sheetName);
// 创建表头 startRow代表表体开始的行
int startRow = createHeadCell(title, tableHeads, colWidths);// 返回的int值表示从哪一行开始为表体数据
// 创建表体数据
HSSFCellStyle cellStyle = getStyle(14, 2, false, true); // 建立新的cell样式
setCellData(dataList, cellStyle, startRow, colKeys);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
workbook.write(baos);
byte[] ba = baos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(ba);
return bais;
}
/**
* 创建表头
*
* @param headNames
* @param colWidths
*/
private static int createHeadCell(String title, String[] headNames, String[] colWidths) {
// 表头标题
HSSFCellStyle titleStyle = getStyle(18, 2, true, false);// 样式
// :22号字体,左右居中,加粗
createRow(titleStyle, 2 * 256, title, 0, 0, 0, headNames.length - 1);// 样式初始化,行高,标题内容,合并行(0,0),合并列(0,列数-1)
// 表头
boolean b = (headNames != null && headNames.length > 0);
if (b) {
HSSFRow row1 = sheet.createRow(1);
row1.setHeight((short) (2 * 200));
HSSFCell fcell = null;
HSSFCellStyle cellStyle = getStyle(14, 2, true, true); // 建立新的cell样式
for (int i = 0; i < headNames.length; i++) {
fcell = row1.createCell(i);
fcell.setCellStyle(cellStyle);
fcell.setCellValue(headNames[i]);
if (colWidths != null && i < colWidths.length) {
sheet.setColumnWidth(i, Integer.parseInt(colWidths[i]) * 50);
}
}
}
return b ? 2 : 1; // 从哪一行开始渲染表体
}
/**
* 创建表体数据
*
* @param dataList
* 表体数据
* @param cellStyle
* 样式
* @param startRow
* 开始行
* @param colKeys
* 值对应map的key
*/
private static void setCellData(List
// 创建数据
HSSFRow row = null;
HSSFCell cell = null;
int i = startRow;
int num = 1;
if (dataList != null && dataList.size() > 0) {
for (Object aao : dataList) {
row = sheet.createRow(i);
row.setHeight((short) (1 * 256));
int j = 0;
for (String key : colKeys) {
Object colValue = null;
if (key.equals("num")) {
colValue = num + "";
} else {
colValue = getFieldValueByName(key, aao);
}
cell = row.createCell(j);
cell.setCellStyle(cellStyle);
if (colValue != null) {
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
cell.setCellValue(colValue.toString());
}
j++;
}
i++;
num++;
}
}
}
/**
* 根据属性名获取属性值
*
* @param fieldName
* @param object
* @return
* */
private static Object getFieldValueByName(String fieldName, Object object) {
try {
String firstLetter = fieldName.substring(0, 1).toUpperCase();
String getter = "get" + firstLetter + fieldName.substring(1);
Method method = object.getClass().getMethod(getter, new Class[] {});
Object value = method.invoke(object, new Object[] {});
return value;
} catch (Exception e) {
return null;
}
}
}
其中Excel样式均可在里面设置,当然也可以从前端传入参数使用。
