<!-- FEED自动发现标记开始 --> <link title="RSS 2.0" type="application/rss+xml" href="http://feed.feedsky.com/softwave" rel="alternate"> <!-- FEED自动发现标记结束 -->
<!--Google 468*60横幅广告开始--><script type="text/javascript"><!-- google_ad_client = "pub-7343546549496470"; google_ad_width = 468; google_ad_height = 60; google_ad_format = "468x60_as"; google_ad_type = "image"; //2007-07-26: CSDN google_ad_channel = "6063905817"; google_color_border = "6699CC"; google_color_bg = "E6E6E6"; google_color_link = "FFFFFF"; google_color_text = "333333"; google_color_url = "AECCEB"; google_ui_features = "rc:6"; //--> </script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script><!--Google 468*60横幅广告结束-->
最近遇到点读取 Excel 数据的问题,于是花了点时间找开源工具。
要解析 Excel,首当其冲的是上传文件,以前在项目里我们用 SmartUpload 进行上传,不过这个项目似乎已经停止开发了,于是在这里我使用 Apache Commons FileUpload,可以在
http://jakarta.apache.org/commons/fileupload
找到。目前该项目的最新版本是 1.1.1,网上有大量的范例程序,不过后来用的时候发现大部分方法在新版本中都不推荐使用了,于是好好读了一回 API 和官方范例。
先来看看如何上传文件,Servlet 很简单,在这里我限制了最大上传量为 1M,且直接读进内存中,不进行磁盘临时文件缓存。
import
java.io.IOException;
import
java.io.PrintWriter;
import
java.io.File;
import
java.net.URI;
import
java.net.URL;
import
javax.servlet.ServletException;
import
javax.servlet.http.HttpServlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
import
java.util.List;
import
org.apache.commons.fileupload.RequestContext;
import
org.apache.commons.fileupload.servlet.ServletRequestContext;
import
org.apache.commons.fileupload.servlet.ServletFileUpload;
import
org.apache.commons.fileupload.disk.DiskFileItemFactory;
import
org.apache.commons.fileupload.FileItem;
public
class
UploadServlet
extends
HttpServlet{
/**
*Constructoroftheobject.
*/
public
UploadServlet(){
super
();
}
/**
*Destructionoftheservlet.
*/
public
void
destroy(){
super
.destroy();
}
public
void
doGet(HttpServletRequestrequest,HttpServletResponseresponse)
throws
ServletException,IOException{
}
/**
*上传文件
*
*
@param
request
*
@param
response
*
@throws
ServletException
*
@throws
IOException
*/
public
void
doPost(HttpServletRequestrequest,HttpServletResponseresponse)
throws
ServletException,IOException{
response.setContentType(
"
text/html
"
);
response.setCharacterEncoding(
"
gbk
"
);
PrintWriterout
=
response.getWriter();
out.println(
"
<html>
"
);
out.println(
"
<head><title>提示</title></head>
"
);
out.println(
"
<body>
"
);
//
不用获取URL对象也行,直接用getServletContext().getRealPath("/")代替。
URLurl
=
getServletContext().getResource(
"
/
"
);
//
从HTTPservlet获取fileupload组件需要的内容
RequestContextrequestContext
=
new
ServletRequestContext(request);
//
判断是否包含multipart内容
if
(ServletFileUpload.isMultipartContent(requestContext)){
//
创建基于磁盘的文件工厂
DiskFileItemFactoryfactory
=
new
DiskFileItemFactory();
//
设置直接存储文件的极限大小,一旦超过则写入临时文件以节约内存。默认为1024字节
factory.setSizeThreshold(
1024
*
1024
);
//
创建上传处理器,可以处理从单个HTML上传的多个上传文件。
ServletFileUploadupload
=
new
ServletFileUpload(factory);
//
最大允许上传的文件大小
upload.setSizeMax(
1024
*
1024
);
//
处理上传
Listitems
=
null
;
try
{
items
=
upload.parseRequest(requestContext);
//
由于提交了表单字段信息,需要进行循环区分。
for
(
int
i
=
0
;i
<
items.size();i
++
){
FileItemfi
=
(FileItem)items.get(i);
//
如果不是表单内容,取出multipart。
if
(
!
fi.isFormField()){
//
上传文件路径和文件、扩展名。
StringsourcePath
=
fi.getName();
String[]sourcePaths
=
sourcePath.split(
"
////
"
);
//
获取真实文件名
StringfileName
=
sourcePaths[sourcePaths.length
-
1
];
//
创建一个待写文件
FileuploadedFile
=
new
File(
new
URI(url.toString()
+
fileName));
//
写入
fi.write(uploadedFile);
out.println(fileName
+
"
上传成功。
"
);
}
}
}
catch
(Exceptione){
out.println(
"
上传失败,请检查上传文件大小是否超过1兆,并保证在上传时该文件没有被其他程序占用。
"
);
out.println(
"
<br>原因:
"
+
e.toString());
e.printStackTrace();
}
}
out.println(
"
</body>
"
);
out.println(
"
</html>
"
);
out.flush();
out.close();
}
/**
*Initializationoftheservlet.
*
*
@throws
ServletException
*/
public
void
init()
throws
ServletException{
}
}
上面的程序示范了如何上传文件到服务器,本文的主要目的不光是上传,还要进行 Excel 解析,抽取有用的内容。开源的 Excel 解析器很多,在此我选择了 JExcelApi,可以在
http://jexcelapi.sourceforge.net
找到,据说是韩国人开发的,最新版本是 2.6.2。为什么没有选 POI,原因也是因为它 N 久没有更新了。我总是喜欢最新的东东,比如 Adobe 的 PDF Reader,硬是下载了 8.0,结果感觉还没有 6.0 好用。:(
以下程序修改直上传,做了部分调整,取消了文件储存,直接通过读取输入流进行解析,并假设约定的 Excel 文件有五列 N 行,第一行为标题信息。
import
java.io.IOException;
import
java.io.PrintWriter;
import
javax.servlet.ServletException;
import
javax.servlet.http.HttpServlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
import
java.util.List;
import
org.apache.commons.fileupload.RequestContext;
import
org.apache.commons.fileupload.servlet.ServletRequestContext;
import
org.apache.commons.fileupload.servlet.ServletFileUpload;
import
org.apache.commons.fileupload.disk.DiskFileItemFactory;
import
org.apache.commons.fileupload.FileItem;
import
jxl.Workbook;
import
jxl.Sheet;
import
jxl.Cell;
public
class
UploadServlet
extends
HttpServlet{
/**
*Constructoroftheobject.
*/
public
UploadServlet(){
super
();
}
/**
*Destructionoftheservlet.
*/
public
void
destroy(){
super
.destroy();
}
public
void
doGet(HttpServletRequestrequest,HttpServletResponseresponse)
throws
ServletException,IOException{
}
/**
*上传文件
*
*
@param
request
*
@param
response
*
@throws
ServletException
*
@throws
IOException
*/
public
void
doPost(HttpServletRequestrequest,HttpServletResponseresponse)
throws
ServletException,IOException{
response.setContentType(
"
text/html
"
);
response.setCharacterEncoding(
"
gbk
"
);
PrintWriterout
=
response.getWriter();
out.println(
"
<html>
"
);
out.println(
"
<head><title>提示</title></head>
"
);
out.println(
"
<body>
"
);
//
声明文件域
FileItemfileItem
=
null
;
//
从HTTPservlet获取fileupload组件需要的内容
RequestContextrequestContext
=
new
ServletRequestContext(request);
//
判断是否包含multipart内容,如果不包含,则不进行任何处理。
if
(ServletFileUpload.isMultipartContent(requestContext)){
//
创建基于磁盘的文件工厂
DiskFileItemFactoryfactory
=
new
DiskFileItemFactory();
//
设置直接存储文件的极限大小,一旦超过则写入临时文件以节约内存。默认为1024字节
factory.setSizeThreshold(
1024
*
1024
);
//
创建上传处理器,可以处理从单个HTML上传的多个上传文件。
ServletFileUploadupload
=
new
ServletFileUpload(factory);
//
最大允许上传的文件大小
upload.setSizeMax(
1024
*
1024
);
try
{
//
处理上传
Listitems
=
null
;
items
=
upload.parseRequest(requestContext);
//
由于提交了表单字段信息,需要进行循环区分。
for
(
int
i
=
0
;i
<
items.size();i
++
){
FileItemfi
=
(FileItem)items.get(i);
//
如果不是表单内容,取出multipart。
if
(
!
fi.isFormField()){
fileItem
=
fi;
//
一次只上传单个文件
break
;
}
}
out.println(parseExcel(fileItem));
}
catch
(Exceptione){
out.println(
"
上传失败!请检查上传的文件是否为excel格式、信息是否完整完整、且大小是否超过1兆。
"
);
out.println(
"
<br>原因:
"
+
e.toString());
e.printStackTrace();
}
}
out.println(
"
</body>
"
);
out.println(
"
</html>
"
);
out.flush();
out.close();
}
/**
*分析excel文件
*
*
@param
FileItemfi文件域
*
@return
String
*
@throws
Exception
*/
private
StringparseExcel(FileItemfi)
throws
Exception{
//
声明Workbook
Workbookworkbook
=
null
;
try
{
workbook
=
Workbook.getWorkbook(fi.getInputStream());
Sheetsheet
=
workbook.getSheet(
0
);
//
总行数
int
count
=
sheet.getRows();
//
取出标题
Stringa1
=
sheet.getCell(
0
,
0
).getContents();
Stringa2
=
sheet.getCell(
1
,
0
).getContents();
Stringa3
=
sheet.getCell(
2
,
0
).getContents();
Stringa4
=
sheet.getCell(
3
,
0
).getContents();
Stringa5
=
sheet.getCell(
4
,
0
).getContents();
//
取出内容
for
(
int
i
=
1
;i
<
count;i
++
){
Cell[]cells
=
sheet.getRow(i);
System.out.println(cells[
0
].getContents()
+
cells[
1
].getContents()
+
cells[
2
].getContents()
+
cells[
3
].getContents()
+
cells[
4
].getContents());
}
return
"
上传成功。
"
;
}
catch
(Exceptione){
throw
e;
}
finally
{
if
(workbook
!=
null
){
workbook.close();
}
}
}
/**
*Initializationoftheservlet.
*
*
@throws
ServletException
*/
public
void
init()
throws
ServletException{
}
}
JExcelApi 用起来很简单,而且还可以根据 Excel 中数据类型转换成 Java 数据类型,比如 int、double,具体信息可以参考它的开发指南。当然,本范例还提供现构造 Excel 然后下载的方法,如果以后遇到,一定继续完善。
------------------------------------------------------------------------------------------------
关于生成 excel 和下载,一月份的文章还留了个尾巴,今天把它补充上去。2007-04-22 by rosen jiang
代码如下,放在 servlet 中,io 异常我没捕获,直接由 get or post 方法抛出,当然,如果更严谨点可以放在 finally 里关闭。
//
设置输出格式和头信息
response.setContentType(
"
application/x-msdownload;charset=GBK
"
);
Stringfilename
=
new
String(
"
供应商报价清单.xls
"
.getBytes(
"
GBK
"
),
"
ISO_8859_1
"
);
response.setHeader(
"
Content-Disposition
"
,
"
attachment;filename=
"
+
filename);
//
虚拟数据
StringmaterialName
=
"
马桶
"
;
//
材料名
Stringsize
=
"
200×300
"
;
//
规格
Stringunit
=
"
台
"
;
//
单位
Stringqty
=
"
2
"
;
//
数量
Stringband
=
"
不知道牌子
"
;
//
材料品牌
Stringcompany
=
"
成都某厂
"
;
//
厂家名
Stringmemo
=
"
质量可靠
"
;
//
备注
Stringprice
=
"
20.30
"
;
//
价格
StringrepDate
=
"
2007-04-11
"
;
//
报价时间
List
<
String[]
>
list
=
new
ArrayList
<
String[]
>
();
for
(
int
i
=
10
;i
>
0
;i
--
){
String[]outPut
=
{materialName,size,unit,qty
+
i,band,company,memo,price,repDate};
list.add(outPut);
}
//
输出流
ByteArrayOutputStreambaos
=
new
ByteArrayOutputStream();
//
构造工作区
WritableWorkbookworkbook
=
Workbook.createWorkbook(baos);
//
构造sheet
WritableSheetsheet
=
workbook.createSheet(
"
报价清单
"
,
0
);
//
构造粗标题字体
WritableFontblodFont
=
new
WritableFont(WritableFont.TAHOMA,
10
,WritableFont.BOLD,
false
);
WritableCellFormatblodFormat
=
new
WritableCellFormat(blodFont);
Labellabel
=
null
;
try
{
//
标题行
label
=
new
Label(
0
,
0
,
"
材料名
"
,blodFormat);
sheet.addCell(label);
label
=
new
Label(
1
,
0
,
"
规格
"
,blodFormat);
sheet.addCell(label);
label
=
new
Label(
2
,
0
,
"
单位
"
,blodFormat);
sheet.addCell(label);
label
=
new
Label(
3
,
0
,
"
数量
"
,blodFormat);
sheet.addCell(label);
label
=
new
Label(
4
,
0
,
"
材料品牌
"
,blodFormat);
sheet.addCell(label);
label
=
new
Label(
5
,
0
,
"
厂家名
"
,blodFormat);
sheet.addCell(label);
label
=
new
Label(
6
,
0
,
"
备注
"
,blodFormat);
sheet.addCell(label);
label
=
new
Label(
7
,
0
,
"
价格
"
,blodFormat);
sheet.addCell(label);
label
=
new
Label(
8
,
0
,
"
报价时间
"
,blodFormat);
sheet.addCell(label);
//
输出业务数据
for
(
int
i
=
1
;i
<=
list.size();i
++
){
String[]outPut
=
list.get(i
-
1
);
label
=
new
Label(
0
,i,outPut[
0
]);
sheet.addCell(label);
label
=
new
Label(
1
,i,outPut[
1
]);
sheet.addCell(label);
label
=
new
Label(
2
,i,outPut[
2
]);
sheet.addCell(label);
label
=
new
Label(
3
,i,outPut[
3
]);
sheet.addCell(label);
label
=
new
Label(
4
,i,outPut[
4
]);
sheet.addCell(label);
label
=
new
Label(
5
,i,outPut[
5
]);
sheet.addCell(label);
label
=
new
Label(
6
,i,outPut[
6
]);
sheet.addCell(label);
label
=
new
Label(
7
,i,outPut[
7
]);
sheet.addCell(label);
label
=
new
Label(
8
,i,repDate);
sheet.addCell(label);
}
//
写入文件
workbook.write();
workbook.close();
//
向浏览器返回文件流
OutputStreamos
=
response.getOutputStream();
os.write(baos.toByteArray());
os.flush();
os.close();
baos.close();
}
catch
(RowsExceededExceptione){
e.printStackTrace();
}
catch
(WriteExceptione){
e.printStackTrace();
}
}
生成 excel 的样子是这样的:
请注意!引用、转贴本文应注明原作者:Rosen Jiang 以及出处:
http://www.blogjava.net/rosen
<!--新Google 468*60横幅广告开始--><script type="text/javascript"><!-- google_ad_client = "pub-7343546549496470"; /* 468x60, 创建于 08-8-6 */ google_ad_slot = "7368701459"; google_ad_width = 468; google_ad_height = 60; //--> </script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script><!--新Google 468*60横幅广告结束-->
<!--新Google 468x15 横链接单元开始--><script type="text/javascript"><!-- google_ad_client = "pub-7343546549496470"; /* 468x15 横链接单元 */ google_ad_slot = "5785741422"; google_ad_width = 468; google_ad_height = 15; //--> </script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script><!--新Google 468x15 横链接单元结束-->
<!-- Google Reader shared发布代码开始 --><script type="text/javascript" src="http://www.google.com/reader/ui/publisher.js"></script><script type="text/javascript" src="http://www.google.com/reader/public/javascript/user/00697638153916680411/state/com.google/broadcast?n=5&callback=GRC_p(%7Bc%3A%22green%22%2Ct%3A%22%5Cu8FD9%5Cu4E9B%5Cu6587%5Cu7AE0%5Cu4E5F%5Cu503C%5Cu5F97%5Cu4E00%5Cu770B%22%2Cs%3A%22false%22%7D)%3Bnew%20GRC"></script><!-- Google Reader shared发布代码结束 -->