在WEB开发中,经常遇到将列表数据导出生成Excel文件这样的功能需求。
1.编写js脚本
编写export.js,主要是将页面上table中的内容按照一定的格式转化为js数组,准备导出form的数据。
/**
* 导出excel(兼容单行多列)
*
* @param id---->需要导出table的id
* @param sName---->sheetName
* @param titleName---->标题名称
* @param cellStart---->掐头去尾-去掉的头部列数(避免导出无用的列,如序号列)
* @param cellEnd
* ---->掐头去尾-去掉的尾部列数(避免导出无用的列,如操作按钮列)
* @returns {Boolean}
*/
// 导出excel表格
function exportExcel(id, sName, titleName, cellStart, cellEnd) {
var t = document.getElementById(id);
var rl = t.rows.length;
var cl = t.rows[0].cells.length;
// alert(id);
var listData = [];
// alert(listData);
var offsetLeftArray = new Array();
var cell; // 单元格Dom
var col; // 单元格实际所在列
var cellStr; // 每个cell以row,col,rowSpan,colSpan,value形式
var cellStrArray = [];
var objTab = document.getElementById(id);
// 遍历第一次取出offsetLeft集合
for (var i = 0; i < objTab.rows.length; i++) {
for (var j = cellStart; j < objTab.rows[i].cells.length - cellEnd; j++) {
cell = objTab.rows[i].cells[j];
// if (offsetLeftArray.contains(cell.offsetLeft) == -1)
if (containsArray(offsetLeftArray, cell.offsetLeft) == -1) offsetLeftArray.push(cell.offsetLeft);
}
}
offsetLeftArray.sort(function(x, y) {
return parseInt(x) - parseInt(y);
});
// alert("offsetLeft集合:" + offsetLeftArray.join(','));
// 遍历第二次生成cellStrArray
for (var i = 0; i < objTab.rows.length; i++) {
var startIndex = cellStart;
//如果要过滤左边的无用列,解决跨行的问题
if (i != 0 && cellStart > 0) {
for (var k = 0; k < cellStart; k++) {
if (objTab.rows[i - 1].cells[k].rowSpan > 1) startIndex--;
}
startIndex = startIndex < 0 ? 0 : startIndex;
}
var endIndex = cellEnd;
//如果要过滤右边的无用列,解决跨行的问题
if (i != 0 && cellEnd > 0) {
var row = objTab.rows[i - 1];
for (var k = 0; k < cellEnd; k++) {
if (row.cells[row.cells.length - 1 - k].rowSpan > 1) endIndex--;
}
endIndex = endIndex < 0 ? 0 : endIndex;
}
for (var j = startIndex; j < objTab.rows[i].cells.length - endIndex; j++) {
cell = objTab.rows[i].cells[j];
col = containsArray(offsetLeftArray, cell.offsetLeft);
cellStr = i + ',' + col + ',' + cell.rowSpan + ',' + cell.colSpan + "," + ((Sys.firefox || Sys.ie==8.0) ? cell.innerHTML: cell.textContent);
cellStrArray.push(cellStr);
}
}
// 显示
/*
* var str = "行,列,rowSpan,colSpan,值\n"; str += cellStrArray.join('\n');
* alert(str);
*/
listData = cellStrArray;
$('#data').val(JSON.stringify(listData));
if (sName) {
$('#sName').val(sName);
} else {
$('#sName').val('导出');
}
$('#titleName').val(titleName);
if (confirm("确定要导出excel表格吗?")) {
if ($('#excelimport').html() != null) {
$('#excelimport').submit();
}
}
}
var Sys = {};
var ua = navigator.userAgent.toLowerCase();
if (window.ActiveXObject) Sys.ie = ua.match(/msie ([\d.]+)/)[1];
else if (document.getBoxObjectFor) Sys.firefox = ua.match(/firefox\/([\d.]+)/)[1];
function containsArray(array, obj) {
for (var i = 0; i < array.length; i++) {
if (array[i] == obj) {
return i;
break;
}
}
return - 1;
}
2.编写Java后台工具类
ExportExcel.java,
提供生成Excel表格和Excel下载的方法,package省略。
这里需要jxl的jar包,我这里用的是jxl-2.6.9.jar,其他版本也是可以的,请自行下载并导入项目。
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import jxl.Workbook;
import jxl.biff.DisplayFormat;
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.NumberFormats;
import jxl.write.WritableCellFormat;
import jxl.write.WritableFont;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;
import jxl.write.WriteException;
public class ExportExcel {
public synchronized static void createExcel(String filePath,List<Map<Object,Object>> list,String sheetName,String titleName){
try {
File file = new File(filePath);
//打开文件
WritableWorkbook book = Workbook.createWorkbook(file);
//生成名为“第一页”的工作表,参数0表示这是第一页
WritableSheet sheet = book.createSheet(sheetName, 0);
// 在label对象的构造子中指名单元格位置是第一列第一行(0,0)
// 以及单元格内容
Label label0 = new Label(0, 0, titleName, setTitle(25));
// 将定义好的单元格添加到工作表中
sheet.addCell(label0);
//合并单元格
//从col1列到col2列 从row1行到row2行
int col = list.get(0).size();
sheet.mergeCells(0, 0, col-1, 0);
//初始化表头
for (int i = 0; i < col; i++) {
Label label = new Label(i, 1, list.get(0).get("cell_"+i).toString(),setTitle(13));
sheet.addCell(label);
}
//初始化内容
for (int i = 1; i < list.size(); i++) {
Map info = list.get(i);
dataInit(sheet,info,i);
}
// 写入数据并关闭文件
book.write();
book.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public synchronized static void createExcelForAnyTable(String filePath,List list,String sheetName,String titleName){
try {
File file = new File(filePath);
//打开文件
WritableWorkbook book = Workbook.createWorkbook(file);
//生成名为“第一页”的工作表,参数0表示这是第一页
WritableSheet sheet = book.createSheet(sheetName, 0);
//初始化内容
for (int i = 0; i < list.size(); i++) {
String str = (String) list.get(i);
String[] info = str.split(",");
dataInitForAnyTable(sheet,info,i);
}
// 写入数据并关闭文件
book.write();
book.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void createBrief(String filePath,List<Map<Object,Object>> list,String titleName) throws Exception{
File file = new File(filePath);
//打开文件
WritableWorkbook book = Workbook.createWorkbook(file);
if(list != null && list.size()>0){
for(int i=0;i<list.size();i++){
Map map=list.get(i);
List<Map<Object,Object>> dataList=(List<Map<Object,Object>>)map.get("listData");
String sheetName = map.get("sheetName").toString();
//生成名为“第一页”的工作表,参数0表示这是第一页
WritableSheet sheet = book.createSheet(sheetName, i);
createReportExcel(sheet,dataList,sheetName,titleName,i,list.size());
}
// 写入数据并关闭文件
book.write();
book.close();
}
}
private static void createReportExcel(WritableSheet sheet,List<Map<Object,Object>> list,String sheetName,String titleName,int pageNum, int totalNum){
try {
// 在label对象的构造子中指名单元格位置是第一列第一行(0,0)
// 以及单元格内容
Label label0 = new Label(0, 0, titleName+sheetName, setTitle(25));
// 将定义好的单元格添加到工作表中
sheet.addCell(label0);
//合并单元格
//从col1列到col2列 从row1行到row2行
int col = list.get(0).size();
sheet.mergeCells(0, 0, col-1, 0);
//初始化表头
for (int i = 0; i < col; i++) {
Label label = new Label(i, 1, list.get(0).get("cell_"+i).toString(),setTitle(13));
sheet.addCell(label);
}
//初始化内容
for (int i = 1; i < list.size(); i++) {
Map info = list.get(i);
dataInit(sheet,info,i);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static void dataInit(WritableSheet sheet,Map info,int i) throws Exception{
Label label=null;
for (int j = 0; j < info.size(); j++) {
if(j==1){
String firstdata=info.get("cell_"+j).toString().replaceAll("\\===", "#");
label = new Label(j, i+1,firstdata,cellFormat(i-1));
}else{
label = new Label(j, i+1, info.get("cell_"+j).toString(),cellFormat(i-1));
}
sheet.addCell(label);
sheet.setColumnView(j, 30); //设置宽度 第一个参数是第几列 第二个参数是宽度
}
}
private static void dataInitForAnyTable(WritableSheet sheet,String[] info,int i) throws Exception{
Label label=null;
int hang = Integer.parseInt(info[0].toString());
int lie = Integer.parseInt(info[1].toString());
int colspan = Integer.parseInt(info[3].toString());
int rowspan = Integer.parseInt(info[2].toString());
sheet.mergeCells(lie, hang, lie+colspan-1, hang+rowspan-1);
String contentStr = "";
if(info.length>=5){
contentStr = info[4].toString();
}
label = new Label(lie, hang,contentStr,cellFormat(i-1));
sheet.addCell(label);
sheet.setColumnView(lie, 30); //设置宽度 第一个参数是第几列 第二个参数是宽度
}
/**
* 设置背景颜色
* @description TODO
* @param dataid
* @throws WriteException
* @return WritableCellFormat
*/
public static WritableCellFormat cellFormat(int num) throws WriteException {
Colour color = Colour.WHITE;
// if (num % 2 == 0) {
// color = Colour.WHITE;
// } else {
// color = Colour.WHITE;
// }
// 设置字体颜色
WritableFont font = new WritableFont(WritableFont.ARIAL, 11,WritableFont.NO_BOLD, false,
UnderlineStyle.NO_UNDERLINE,Colour.BLACK);
WritableCellFormat cellformat = new WritableCellFormat(font);
// 设置单元格背景颜色
cellformat.setBackground(color);
cellformat.setAlignment(Alignment.CENTRE);
cellformat.setVerticalAlignment(VerticalAlignment.CENTRE);
cellformat.setBorder(Border.ALL, BorderLineStyle.THIN); // 增加边框
return cellformat;
}
public static WritableCellFormat cellFormatNumber(int num) throws WriteException{
WritableFont wf = new WritableFont(WritableFont.ARIAL, 10,
WritableFont.NO_BOLD, false);
DisplayFormat DisplayFormat = NumberFormats.DEFAULT;
WritableCellFormat cellformat = new WritableCellFormat(wf, DisplayFormat);
cellformat.setBackground(Colour.YELLOW);
cellformat.setAlignment(Alignment.RIGHT);
cellformat.setVerticalAlignment(VerticalAlignment.CENTRE);
cellformat.setBorder(jxl.format.Border.ALL, jxl.format.BorderLineStyle.THIN);// 设置细边框
return cellformat;
}
public static WritableCellFormat setTitle(int fontsize)throws WriteException {
Colour color = Colour.WHITE;
// 设置字体颜色
WritableFont font = new WritableFont(WritableFont.ARIAL, fontsize,
WritableFont.BOLD, false, UnderlineStyle.NO_UNDERLINE,Colour.BLACK);
WritableCellFormat cellformat = new WritableCellFormat(font);
// 设置单元格背景颜色
cellformat.setBackground(color);
//设置对齐方式
cellformat.setAlignment(Alignment.CENTRE);
// cellformat.setshrinktofit(true);
cellformat.setBorder(Border.ALL, BorderLineStyle.THIN); // 增加边框
return cellformat;
}
public static void delExcel(String filePath){
File file = new File(filePath);
if(file.isDirectory()){
String[] nameList = file.list();
for(String str : nameList){
File f = new File(filePath + "\\" +str);
if(f.isFile()){
//System.out.println(filePath + "\\" + str +"文件删除");
f.delete();
}
}
}
}
//下载文件
public static void download(String filePath,HttpServletResponse response) throws Exception{
File file = new File(filePath);
if(!file.exists()){
response.sendError(404,"导出文件不存在!");
return;
}
BufferedInputStream br = new BufferedInputStream(new FileInputStream(file));
byte[] buf = new byte[1024];
int len = 0;
response.reset(); //非常重要
response.setContentType("application/vnd.ms-excel;charset=UTF-8");
// System.out.print(response.getContentType());
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Disposition", "attachment; filename=" + file.getName());
// System.out.println("-------");
// System.out.println("fileName=="+file.getName());
OutputStream out = response.getOutputStream();
while((len = br.read(buf)) >0)
out.write(buf,0,len);
br.close();
out.close();
}
//下载word文件
public static void downloadWord(String filePath,HttpServletResponse response) throws Exception{
File file = new File(filePath);
if(!file.exists()){
response.sendError(404,"导出文件不存在!");
return;
}
BufferedInputStream br = new BufferedInputStream(new FileInputStream(file));
byte[] buf = new byte[1024];
int len = 0;
response.reset(); //非常重要
response.setContentType("application/vnd.ms-word;charset=UTF-8");
System.out.print(response.getContentType());
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Disposition", "attachment; filename=" + file.getName());
OutputStream out = response.getOutputStream();
while((len = br.read(buf)) >0)
out.write(buf,0,len);
br.close();
out.close();
}
}
3.Controller里编写方法,处理导出请求
若缺少jar包,请自行下载。
package com.gsww.peop.web.controller; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import net.sf.json.JSONArray; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import com.gsww.peop.web.commons.ExportExcel; @Controller @RequestMapping("/comm") public class CommonController extends CrudSupport{
/** * excel导出功能 * @param request * @param response * @param data * @param sName * @param titleName */ @RequestMapping("/export") public void exportExcel(HttpServletRequest request,HttpServletResponse response, String data,String sName,String titleName){ //文件名称中文时会乱码,这里处理下,处理完火狐下还是乱码,谷歌合适。 String fileName = toUtf8String(sName+".xls"); JSONArray listDataJson = JSONArray.fromObject(data); // try { File dir = new File(request.getSession().getServletContext().getRealPath("/") +"excel"); if(!dir.exists()){ dir.mkdirs(); } String filePath = request.getSession().getServletContext().getRealPath("/") +"excel\\"+fileName; //注意导入ExportExcel.java工具类 //生成Excel表格 ExportExcel.createExcelForAnyTable(filePath,listDataJson,sName,titleName); //下载Excel表格 ExportExcel.download(filePath,response); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * (解决文件导出时文件名为乱码的问题) * @param s * @return */ public static String toUtf8String(String s){ StringBuffer sb = new StringBuffer(); for (int i=0;i<s.length();i++){ char c = s.charAt(i); if (c >= 0 && c <= 255){sb.append(c);} else{ byte[] b; try { b = Character.toString(c).getBytes("utf-8");} catch (Exception ex) { System.out.println(ex); b = new byte[0]; } for (int j = 0; j < b.length; j++) { int k = b[j]; if (k < 0) k += 256; sb.append("%" + Integer.toHexString(k).toUpperCase()); } } } return sb.toString(); } }
4.jsp页面中使用
需要先在web项目中的
webapp文件夹下新建
excel文件夹,用来存放生成的excel文件。
在页面放一个导出按钮,绑定exportExcel函数,此function第一个参数为列表待导出的数据的table的ID;第二个参数为导出的Excel文件名称;第三个参数为Excel的sheet的名称;第四个参数为table去掉的头部列数,比如table的第一列为序号或checkbox,导出时想忽略此列,这个参数就设置为1,为0代表不忽略;第5个参数为table去掉的尾部列数,比如table的最后一列为操作列,导出时想忽略此列,这个参数就设置为1,为0代表不忽略。
<input type="button" value="导出" name="" οnclick="exportExcel('userTbl','学员信息','学员信息',1,1)" >
在jsp页面放置一个导出使用的form,form的action是第三步Controller中导出方法的请求url,这里只需修改action对应的url,其他的不用修改。
<!-- 导出用的form -->
<form action="${ctx}/comm/export" id="excelimport" method="post">
<input type="hidden" name="data" id="data"/>
<input type="hidden" name="sName" id="sName"/>
<input type="hidden" name="titleName" id="titleName"/>
</form>
注意引入export.js,点击导出按钮的时候,调用的是export.js中的方法,src路径按需修改
<script type="text/javascript" src="${ctx}/res/js/export.js"></script>
jsp页面
jsp页面
页面列表
导出的Excel
如果导出的内容不是列表上显示的,那么可以把准备导出的内容放在一个隐藏的table中,但是display设置为none是不行的,这种情况可以这么写
<table id="dataTab" style="position:absolute;top:-3000px;visibility:hidden;width:0px;height:0px;">
...省略
</table>