当前位置: 首页 > news >正文

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();
        }
    }

相关文章:

  • this的使用
  • !!java web学习笔记(一到五)
  • (ibm)Java 语言的 XPath API
  • 一、java环境搭建
  • IE与firefox下的css区别
  • copy与strong的举例
  • 浅谈PHP与Java之Web开发整合技术
  • Notepad++中常用的插件
  • 多个.class 打包成 .jar
  • 当项目出现空闲时候,如何开展软件测试工作?
  • php中调用java类的方法
  • 利用SWFTools工具将pdf转换成swf
  • Thrift-java学习小结
  • Flex:使用FlexPaper显示PDF文档
  • SWFObject2.0两种调用方式
  • 【剑指offer】让抽象问题具体化
  • Android 初级面试者拾遗(前台界面篇)之 Activity 和 Fragment
  • canvas实际项目操作,包含:线条,圆形,扇形,图片绘制,图片圆角遮罩,矩形,弧形文字...
  • css选择器
  • FineReport中如何实现自动滚屏效果
  • HashMap剖析之内部结构
  • iOS动画编程-View动画[ 1 ] 基础View动画
  • Java 9 被无情抛弃,Java 8 直接升级到 Java 10!!
  • leetcode98. Validate Binary Search Tree
  • Python爬虫--- 1.3 BS4库的解析器
  • rabbitmq延迟消息示例
  • React中的“虫洞”——Context
  • RedisSerializer之JdkSerializationRedisSerializer分析
  • vue-router的history模式发布配置
  • 从零开始的无人驾驶 1
  • 服务器之间,相同帐号,实现免密钥登录
  • 聊聊directory traversal attack
  • 前端学习笔记之原型——一张图说明`prototype`和`__proto__`的区别
  • 前言-如何学习区块链
  • 如何在GitHub上创建个人博客
  • 实现简单的正则表达式引擎
  • ​油烟净化器电源安全,保障健康餐饮生活
  • #前后端分离# 头条发布系统
  • #我与Java虚拟机的故事#连载09:面试大厂逃不过的JVM
  • (10)ATF MMU转换表
  • (20)目标检测算法之YOLOv5计算预选框、详解anchor计算
  • (SpringBoot)第二章:Spring创建和使用
  • (二) Windows 下 Sublime Text 3 安装离线插件 Anaconda
  • (附源码)springboot电竞专题网站 毕业设计 641314
  • (附源码)springboot青少年公共卫生教育平台 毕业设计 643214
  • (附源码)ssm教师工作量核算统计系统 毕业设计 162307
  • (论文阅读32/100)Flowing convnets for human pose estimation in videos
  • (十一)图像的罗伯特梯度锐化
  • (转)IIS6 ASP 0251超过响应缓冲区限制错误的解决方法
  • (转)iOS字体
  • .360、.halo勒索病毒的最新威胁:如何恢复您的数据?
  • .NET C#版本和.NET版本以及VS版本的对应关系
  • .NET Core MongoDB数据仓储和工作单元模式封装
  • .net下简单快捷的数值高低位切换
  • [ CTF ] WriteUp- 2022年第三届“网鼎杯”网络安全大赛(朱雀组)