JXL导出Excel数据表
封装了一个简单易用、通用、动态的从数据库导出到Excel的方法,可以动态的指定导出那些列,显示什么名字,按什么顺序显示;支持本地文件存储和JSP/Servlet文件下载。
本方法包括两个类,Column是辅助类,Excel是主类:
Column:
/**
* 用于Excel导出的辅助类,映射数据结果集(ResultSet)内列名的元数据和Excel内的显示列名
*/
public class Column {
private int index;
private String metaName;
private String displayName;
private int length;
/**
* 构造函数
*
* @param index
* 显示顺序,0 为显示的第一列
* @param meta
* 元列名,在ResultSet内的名字,必须大写
* @param display
* 显示列名,在Excel内的显示,可以是任何文字
* @param length
* 列名长度
*/
public Column(int index, String meta, String display,int length) {
this.index = index;
this.metaName = meta;
this.displayName = display;
this.length = length;
}
/**
* 显示列名,在Excel内的显示,可以是任何文字
*
* @return
*/
public String getDisplayName() {
return displayName;
}
/**
* 显示顺序,0 为显示的第一列
*
* @return
*/
public int getIndex() {
return index;
}
/**
* 元列名,在ResultSet内的名字,必须大写
*
* @return
*/
public String getMetaName() {
return metaName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public void setIndex(int index) {
this.index = index;
}
public void setMetaName(String metaName) {
this.metaName = metaName;
}
public int getLength() {
return length;
}
public void setLength(int length) {
this.length = length;
}
}
Excel:
/**
* 从数据库读数据,写入Excel
*
* @param os
* 数据流,如果是写本地文件的话,可以是FileOutputStream;
* 如果是写Web下载的话,可以是ServletOupputStream
* @param title
* Excel工作簿的标题,如果不用的话,可以写null或者""
* @param rs
* 数据结果集
* @param map
* 数据结果集对应Excel表列名映射:key对应数据结果集的列名,必须是大写; value,目前只能对应Column对象
* @throws Exception
* 方法内的父类异常有SQLException和IOException
*/
public static void export(OutputStream os, String title, ResultSet rs,
Map map) throws Exception {
jxl.write.WritableWorkbook wbook = Workbook.createWorkbook(os); // 建立excel文件
jxl.write.WritableSheet wsheet = wbook.createSheet("第一页", 0); // sheet名称
jxl.write.Label wlabel = null; // Excel表格的Cell
ResultSetMetaData rsmd = rs.getMetaData();
int count = rsmd.getColumnCount();
// 如果有标题的话,要设置一下偏移
int offset = 1;
if (title == null || title.trim().equals(""))
offset = 0;
else {
// 设置标题字体
int numTitle = 18;// 列名字体大小
jxl.write.WritableFont titleFont = new jxl.write.WritableFont(
WritableFont.createFont("宋体"), numTitle, WritableFont.BOLD);
jxl.write.WritableCellFormat titleFormat = new jxl.write.WritableCellFormat(titleFont);
titleFormat.setBorder(Border.ALL, BorderLineStyle.THIN); // 线条
titleFormat.setVerticalAlignment(VerticalAlignment.CENTRE); // 垂直对齐
titleFormat.setAlignment(Alignment.CENTRE); // 水平对齐
// 添加excel标题
jxl.write.Label wlabel1 = new jxl.write.Label(0, 0, title, titleFormat);
wsheet.addCell(wlabel1);
wsheet.mergeCells(0, 0, count-1, 0);//合并单元格
}
// 设置列名字体
int charTitle = 12;// 列名字体大小
jxl.write.WritableFont columnFont = new jxl.write.WritableFont(
WritableFont.createFont("宋体"), charTitle, WritableFont.BOLD);
jxl.write.WritableCellFormat columnFormat = new jxl.write.WritableCellFormat(
columnFont);
columnFormat.setBorder(Border.ALL, BorderLineStyle.THIN); // 线条
columnFormat.setVerticalAlignment(VerticalAlignment.CENTRE); // 垂直对齐
columnFormat.setAlignment(Alignment.CENTRE); // 水平对齐
columnFormat.setWrap(true); // 是否换行
columnFormat.setBackground(Colour.GRAY_25);// 背景色暗灰-25%
// 根据原数据和map来创建Excel的列名
for (int i = 1; i <= count; i++) {
String name = rsmd.getColumnName(i).toUpperCase();
if (map.containsKey(name)) {
Column col = (Column) map.get(name);
wlabel = new jxl.write.Label(col.getIndex(), offset, col
.getDisplayName(),columnFormat);
wsheet.setColumnView(i-1, col.getLength()); // 设置列宽,第1列
wsheet.addCell(wlabel);
}
}
// 设置正文字体
int charNormal = 10;// 标题字体大小
WritableFont normalFont = new WritableFont(WritableFont
.createFont("宋体"), charNormal);
jxl.write.WritableCellFormat normalFormat = new jxl.write.WritableCellFormat(
normalFont);
normalFormat.setBorder(Border.ALL, BorderLineStyle.THIN); // 线条
normalFormat.setVerticalAlignment(VerticalAlignment.CENTRE); // 垂直对齐
normalFormat.setAlignment(Alignment.CENTRE);// 水平对齐
normalFormat.setWrap(true); // 是否换行
// 往Excel输出数据
int rowIndex = 1 + offset;
Collection array = map.values();
while (rs.next()) {
Iterator it = array.iterator();
while (it.hasNext()) {
Column col = (Column) it.next();
String value = rs.getString(col.getMetaName());
wlabel = new jxl.write.Label(col.getIndex(), rowIndex, value,normalFormat);
wsheet.addCell(wlabel);
}
rowIndex++;
}
wbook.write(); // 写入文件
wbook.close();
os.flush();
os.close();
}
}
//JSP页面的下载如下,同样的代码也可以改成Servlet的
<%
ConnectionPool pool = ConnectionPool.getInstance();
Connection conn = null;
ResultSet rs = null;
Statement stmt = null;
conn = pool.getConnection();
stmt = conn.createStatement();
rs = stmt.executeQuery("Select t.*, t.rowid from mis2_personal_weekly_job_plan t Where Rownum Between 1 And 2");
HashMap map = new HashMap();
map.put("ID", new Column(0, "ID", "编号"));
map.put("JOB_CONTENT", new Column(1, "JOB_CONTENT", "工作内容"));
map.put("JOB_TARGET", new Column(2, "JOB_TARGET", "工作目标"));
String fileName = "周工作计划.xls";
response.reset();
response.setHeader("Cache-Control", "public");
response.setContentType("application/ms-excel;charset=gbk");
//response.setContentType("application/vnd.ms-excel");
String fn=new String(fileName.getBytes("gb2312"),"ISO8859-1");// 将文件名变成中文
response.addHeader("Content-Disposition","attachment;filename=" + fn);
Excel.export(response.getOutputStream(), "", rs, map);
%>
补充意见:
1、需要注意在封装字段标题时需要将map的关键字置为大写,不然会找不到的,因为在excel类里将从数据库取到的字段名称进行了toUpperCase()。
2、建议使用个计数器,在map中设置value时我们只需使用var++让他自己去加去,不用去写0,1,2,3...,这样我们在修改调整字段时,就不用去改这些写死的索引号,这样更为灵活一些。
3、导出文件好像不支持中文名,如果写中文它会用字母替代,还是用英文吧。
建议写成如下这样:
HashMap map = new HashMap();
int k=0;//计数器,这样我们在写map的value值时,就不用在Column里写0,1,2,3...了,真接用k++
//其中map中的关键字都得是大写的,不然会找不到的,因为在excel类里用了.toUpperCase()方法
map.put("ID".toUpperCase(), new Column(k++, "ID", "编号"));
map.put("JOB_CONTENT".toUpperCase(), new Column(k++, "JOB_CONTENT", "工作内容"));
map.put("JOB_TARGET".toUpperCase(), new Column(k++, "JOB_TARGET", "工作目标"));
最后不要使用JSP的方式导出,如果用JSP写导出的话,会出现异常信息:
java.lang.IllegalStateException: 已获取输出流
出现这种异常,只需要把导出的代码写入Servlet即可以解决。
切忌!切忌!