Apache FileUpload 上传以及 JExcelApi 解析

 最近遇到点读取 Excel 数据的问题,于是花了点时间找开源工具。
要解析 Excel,首当其冲的是上传文件,以前在项目里我们用 SmartUpload 进行上传,不过这个项目似乎已经停止开发了,于是在这里我使用 Apache Commons FileUpload,可以在 http://jakarta.apache.org/commons/fileupload 找到。目前该项目的最新版本是 1.1.1,网上有大量的范例程序,不过后来用的时候发现大部分方法在新版本中都不推荐使用了,于是好好读了一回 API 和官方范例。

先来看看如何上传文件,Servlet 很简单,在这里我限制了最大上传量为 1M,且直接读进内存中,不进行磁盘临时文件缓存。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
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 {
 
     /** 
     * Constructor of the object.
      */ 
     public  UploadServlet() {
         super ();
    }
 
     /** 
     * Destruction of the servlet.
      */ 
     public   void  destroy() {
         super .destroy();
    }
 
     public   void  doGet(HttpServletRequest request, HttpServletResponse response)
             throws  ServletException, IOException {
    }
 
     /** 
     * 上传文件
     * 
     *  @param  request
     *  @param  response
     *  @throws  ServletException
     *  @throws  IOException
      */ 
     public   void  doPost(HttpServletRequest request, HttpServletResponse response)
             throws  ServletException, IOException {
        response.setContentType( " text/html " );
        response.setCharacterEncoding( " gbk " );
        PrintWriter out  =  response.getWriter();
        out.println( " <html> " );
        out.println( "   <head><title>提示</title></head> " );
        out.println( "   <body> " );
         //  不用获取 URL 对象也行,直接用 getServletContext().getRealPath("/") 代替。 
        URL url  =  getServletContext().getResource( " / " );
         //  从 HTTP servlet 获取 fileupload 组件需要的内容 
        RequestContext requestContext  =   new  ServletRequestContext(request);
         //  判断是否包含 multipart 内容 
         if  (ServletFileUpload.isMultipartContent(requestContext)) {
             //  创建基于磁盘的文件工厂 
            DiskFileItemFactory factory  =   new  DiskFileItemFactory();
             //  设置直接存储文件的极限大小,一旦超过则写入临时文件以节约内存。默认为 1024 字节 
            factory.setSizeThreshold( 1024   *   1024 );
             //  创建上传处理器,可以处理从单个 HTML 上传的多个上传文件。 
            ServletFileUpload upload  =   new  ServletFileUpload(factory);
             //  最大允许上传的文件大小 
            upload.setSizeMax( 1024   *   1024 );
             //  处理上传 
            List items  =   null ;
             try  {
                items  =  upload.parseRequest(requestContext);
                 //  由于提交了表单字段信息,需要进行循环区分。 
                 for  ( int  i  =   0 ; i  <  items.size(); i ++ ) {
                    FileItem fi  =  (FileItem) items.get(i);
                     //  如果不是表单内容,取出 multipart。 
                     if  ( ! fi.isFormField()) {
                         //  上传文件路径和文件、扩展名。 
                        String sourcePath  =  fi.getName();
                        String[] sourcePaths  =  sourcePath.split( " //// " );
                         //  获取真实文件名 
                        String fileName  =  sourcePaths[sourcePaths.length  -   1 ];
                         //  创建一个待写文件 
                        File uploadedFile  =   new  File( new  URI(url.toString() + fileName));
                         //  写入 
                        fi.write(uploadedFile);
                        out.println(fileName + " 上传成功。 " );
                    }
                }
            }  catch  (Exception e) {
                out.println( " 上传失败,请检查上传文件大小是否超过1兆,并保证在上传时该文件没有被其他程序占用。 " );
                out.println( " <br>原因: " + e.toString());
                e.printStackTrace();
            }
        }
        out.println( "   </body> " );
        out.println( " </html> " );
        out.flush();
        out.close();
    }
 
     /** 
     * Initialization of the servlet.
     * 
     *  @throws  ServletException
      */ 
     public   void  init()  throws  ServletException {
    }
} 


表单上一定要加ENCTYPE="multipart/form-data"
<form id="frm_reqNew" name="frm_reqNew" ENCTYPE="multipart/form-data" action="$!actionPath/deliver/deliverReqCreate.shtml" method="post" >
-------------------------------------------------------------------------------------------------------------------
上面的程序示范了如何上传文件到服务器,本文的主要目的不光是上传,还要进行 Excel 解析,抽取有用的内容。开源的 Excel 解析器很多,在此我选择了 JExcelApi,可以在 http://jexcelapi.sourceforge.net 找到,据说是韩国人开发的,最新版本是 2.6.2。为什么没有选 POI,原因也是因为它 N 久没有更新了。我总是喜欢最新的东东,比如 Adobe 的 PDF Reader,硬是下载了 8.0,结果感觉还没有 6.0 好用。:(

以下程序修改直上传,做了部分调整,取消了文件储存,直接通过读取输入流进行解析,并假设约定的 Excel 文件有五列 N 行,第一行为标题信息。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
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 {
        
     /** 
     * Constructor of the object.
      */ 
     public  UploadServlet() {
         super ();
    }
 
     /** 
     * Destruction of the servlet.
      */ 
     public   void  destroy() {
         super .destroy();
    }
 
     public   void  doGet(HttpServletRequest request, HttpServletResponse response)
             throws  ServletException, IOException {
    }
 
     /** 
     * 上传文件
     * 
     *  @param  request
     *  @param  response
     *  @throws  ServletException
     *  @throws  IOException
      */ 
     public   void  doPost(HttpServletRequest request, HttpServletResponse response)
             throws  ServletException, IOException {
        response.setContentType( " text/html " );
        response.setCharacterEncoding( " gbk " );
        PrintWriter out  =  response.getWriter();
        out.println( " <html> " );
        out.println( "   <head><title>提示</title></head> " );
        out.println( "   <body> " );
         //  声明文件域 
        FileItem fileItem  =   null ;
         //  从 HTTP servlet 获取 fileupload 组件需要的内容 
        RequestContext requestContext  =   new  ServletRequestContext(request);
         //  判断是否包含 multipart 内容,如果不包含,则不进行任何处理。 
         if  (ServletFileUpload.isMultipartContent(requestContext)) {
             //  创建基于磁盘的文件工厂 
            DiskFileItemFactory factory  =   new  DiskFileItemFactory();
             //  设置直接存储文件的极限大小,一旦超过则写入临时文件以节约内存。默认为 1024 字节 
            factory.setSizeThreshold( 1024   *   1024 );
             //  创建上传处理器,可以处理从单个 HTML 上传的多个上传文件。 
            ServletFileUpload upload  =   new  ServletFileUpload(factory);
             //  最大允许上传的文件大小 
            upload.setSizeMax( 1024   *   1024 );
             try  {
                 //  处理上传 
                List items  =   null ;
                items  =  upload.parseRequest(requestContext);
                 //  由于提交了表单字段信息,需要进行循环区分。 
                 for  ( int  i  =   0 ; i  <  items.size(); i ++ ) {
                    FileItem fi  =  (FileItem) items.get(i);
                     //  如果不是表单内容,取出 multipart。 
                     if  ( ! fi.isFormField()) {
                        fileItem  =  fi;
                         // 一次只上传单个文件 
                         break ;
                    }
                }
                out.println(parseExcel(fileItem));
            }  catch  (Exception e) {
                out.println( " 上传失败!请检查上传的文件是否为excel格式、信息是否完整完整、且大小是否超过1兆。 " );
                out.println( " <br>原因: " + e.toString());
                e.printStackTrace();
            }
        }
        out.println( "   </body> " );
        out.println( " </html> " );
        out.flush();
        out.close();
    }
 
     /** 
     * 分析excel文件
     * 
     *  @param  FileItem fi 文件域
     *  @return  String
     *  @throws  Exception
      */ 
     private  String parseExcel(FileItem fi)  throws  Exception{
         //  声明 Workbook 
        Workbook workbook  =   null ;
         try {
            workbook  =  Workbook.getWorkbook(fi.getInputStream());
            Sheet sheet  =  workbook.getSheet( 0 );
             // 总行数 
             int  count  =  sheet.getRows();
             // 取出标题 
              String a1  =  sheet.getCell( 0 , 0 ).getContents();
              String a2  =  sheet.getCell( 1 , 0 ).getContents();
              String a3  =  sheet.getCell( 2 , 0 ).getContents();
              String a4  =  sheet.getCell( 3 , 0 ).getContents();
              String a5  =  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 (Exception e){
             throw  e;
        } finally {
             if (workbook != null ){
                workbook.close();
            }
        }
    }
    
     /** 
     * Initialization of the servlet.
     * 
     *  @throws  ServletException
      */ 
     public   void  init()  throws  ServletException {
    }
} 


JExcelApi 用起来很简单,而且还可以根据 Excel 中数据类型转换成 Java 数据类型,比如 int、double,具体信息可以参考它的开发指南。当然,本范例还提供现构造 Excel 然后下载的方法,如果以后遇到,一定继续完善。
------------------------------------------------------------------------------------------------------------------
生成 excel 和下载
代码如下,放在 servlet 中,io 异常我没捕获,直接由 get or post 方法抛出,当然,如果更严谨点可以放在 finally 里关闭。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
    //设置输出格式和头信息
        response.setContentType("application/x-msdownload;charset=GBK");
        String filename = new String("供应商报价清单.xls".getBytes("GBK"),"ISO_8859_1");
        response.setHeader("Content-Disposition","attachment;filename="+filename);
 
        //虚拟数据
        String materialName = "马桶";       //材料名
        String size = "200×300";           //规格
        String unit = "台";                //单位
        String qty = "2";                  //数量
        String band = "不知道牌子";          //材料品牌
        String company = "成都某厂";         //厂家名
        String memo = "质量可靠";            //备注
        String price = "20.30";            //价格
        String repDate = "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);
        }
 
        //输出流
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        //构造工作区
        WritableWorkbook workbook = Workbook.createWorkbook(baos);
        //构造 sheet
        WritableSheet sheet = workbook.createSheet("报价清单", 0);
        //构造粗标题字体
        WritableFont blodFont = new WritableFont(WritableFont.TAHOMA,10,WritableFont.BOLD, false);
        WritableCellFormat blodFormat = new WritableCellFormat (blodFont);
        Label label = 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();
 
            //向浏览器返回文件流
            OutputStream os = response.getOutputStream();
            os.write(baos.toByteArray());
            os.flush();
            os.close();
            baos.close();
        } catch (RowsExceededException e) {
            e.printStackTrace();
        } catch (WriteException e) {
            e.printStackTrace();
        }
    }

你可能感兴趣的:(Apache FileUpload 上传以及 JExcelApi 解析)