使用swfupload上传文件到Java应用服务器

swfupload是很好的一个上传组件. 不过它的代码/例子里面给的是PHP和.net的. 本以为直接用很简单, 结果绕了不少弯路. 总结一下, 抛砖引玉.

搭建了个简单的struts环境, 配置个基本的action, 把swfupload的脚本拷贝到一个jsp里面, 然后将upload_url设置为相应的actoin:

window.onload = function() {
    var settings = {
     flash_url : "swfupload.swf",
     upload_url: "/swfupload/upload.do?state=save"
     post_params: {},
     file_size_limit : "100 MB"
    ......

结果不能正常工作. 跟踪了一下, 是能够正常到这个action的. 但是里面的处理有问题. 试着用Apache的commons upload组件, 还是不行. 写了一些测试代码, 发现:

request.getContentType() 返回是对的(二进制流)
request.getContentLength() 也是对的, 基本上是文件的长度

request.getInputStream() 有问题, read() 一下 返回的是 -1, 表明已经到末尾了. 在网上查了一下, Apache的Mail List里面有老外遇到了类似的问题, 原因是Struts在包装Form的时候, 已经对这个Stream进行了操作. 所以这里再操作就出错了.

OK, 那么绕过Struts呢? 直接写一个Servlet来试试. (用拦截器应该也可以, 不过没做实验) 在web.xml里面添加一个Servlet, 让他处理所有的.save请求:

    <servlet>
        <servlet-name>save</servlet-name>
        <servlet-class>
            upload.SaveServlet
        </servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>save</servlet-name>
        <url-pattern>*.save</url-pattern>
    </servlet-mapping>

然后把upload.jsp里面改掉, 使用新的url:

upload_url: "/swfupload/upload.save"

嗯..... Servlet里面该如何处理呢?

为了查看具体的内容, 构造一个 txt 文件, 用来做上传测试. 里面内容都是简单的英文避免乱码.

abcdefg0123456789
abcdefg0123456789

然后, 在Wiredshark里面, 捕捉上传的请求到底是什么东西.

写一些测试代码来看看. 在Servlet里面, 使用下面的测试代码来看看request里面是什么东西:

可以看到, swfobject在上传的时候, 使用的是multipart/formdata类型的请求(和普通上传是一致的). 里面的数据是分块的,每一块可能为:

form-data类型的数据. 里面是swfobject附加的一些补充信息, 比如上传的文件名, 等等;
Application/octet-stream. 里面是实际的文件内容(二进制流).

这样就好办了. 既然有了这些数据, 在Servlet中就能处理.写个测试程序, 看看Servlet中, inputstream是什么东西:

protected void service(HttpServletRequest request,
    HttpServletResponse response) throws ServletException, IOException {
   int size = request.getContentLength();
   byte[] b = new byte[size];
   request.getInputStream().read(b);
   System.out.println(new String(b));
}

结果为:

------------Ef1ei4ae0ae0gL6cH2cH2Ef1Ij5ei4
Content-Disposition: form-data; name="Filename"

link.txt
------------Ef1ei4ae0ae0gL6cH2cH2Ef1Ij5ei4
Content-Disposition: form-data; name="Filedata"; filename="link.txt"
Content-Type: application/octet-stream

abcdefg0123456789
abcdefg0123456789
abcdefg0123456789
abcdefg0123456789
------------Ef1ei4ae0ae0gL6cH2cH2Ef1Ij5ei4
Content-Disposition: form-data; name="Upload"

Submit Query
------------Ef1ei4ae0ae0gL6cH2cH2Ef1Ij5ei4--

这样,事情就明了了. 上面的数据的含义为:
------------Ef1ei4ae0ae0gL6cH2cH2Ef1Ij5ei4-- 类似的唯一ID分隔(这个ID每个请求都会不同). 同样, 该ID可以从request.getContextType() 中得到.
分隔后, 是 Content-Disposition: form-data; name="xxxxxx" 是swfobject附加的一些信息. 具体哪些信息, 可以从 name 中读取.
如果name="Filedata", 则相当于找到了实际的数据. 继续向下读两行(跳过Content-Type: application/octet-stream 和 一个空行), 开始读入数据, 一直到遇到了下一个分隔ID.
基本思路就是这样, 可以按照这个次序写一段程序来解析request.getInputStream(), 来把实际的数据读取出来.

嗯...自己比较懒, 有没有更好的方法? 当然有, Apache Common Upload 组件其实已经完成了上面的解析的工作. 直接拿过来用, 在上面配置的upload.SaveServlet 中补充代码:

    protected void service(HttpServletRequest request,

           HttpServletResponse response) throws ServletException, IOException {

      

       FileItemFactory factory = new DiskFileItemFactory();

       // Create a new file upload handler

      

       ServletFileUpload upload = new ServletFileUpload(factory);

        //防止中文文件名乱码

        upload.setHeaderEncoding( "UTF-8" );

       try {

           List<FileItem> items = upload.parseRequest(request) ;

           if (items != null ) {

              Iterator<FileItem> itr = items.iterator();

              while (itr.hasNext()) {

                  FileItem item = (FileItem) itr.next();

                  if (item.isFormField()) {

                   continue ;

                  } else {

                   File fullFile= new File(item.getName());

                      //文件都保存在c:\uploadtest文件夹下面, 使用原始的文件名

                      File savedFile= new File( "c:/uploadtest/" , fullFile.getName());

                      item.write(savedFile);

                  }

              }

           }

       } catch (Exception e) {

           e.printStackTrace();

       }

       //结束upload. 如果没有这一行, 浏览器里面一直是uploading....

       response.getOutputStream().println ( "200 OK" );

    }

在IE, FireFox, Opera下测试通过. 其实到最后, 自己写的东西几乎没有, 都是把现成的东西拿来拼一拼~~  效果如图:

其它的东西, 比如swfupload怎么安装配置, 具体的参数是什么, 就不写了,它自己的文档已经写的很详细了~~

另:我自己是用Filter拦截的,果然好用,但是在指定上传路径的时候,我指定的是相对于站点根目录的路径/xxx/images/id,但是文件却上传到了C:\xxx\images\id路径下,所以只好重新设定上传路径为绝对路径。

1,Jsp中获取当前站点目录的绝对路径:
方法:
request.getRealPath(String str);
已经不建议使用,替代方法是:
request.getSession().getServletContext().getRealPath(String str);
其中参数str可以是文件或者文件夹名称。
2,Jsp经常在windows下开发,在Linux服务器上运行,而两个系统的“文件分隔符”是不一样的,windows下是“\”,linux下是“/”,通用的获取当前系统的“文件分隔符”的方法是:
System.getProperty("file.separator");

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值