`
madinggui
  • 浏览: 10910 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

采用HTTP协议上传文件实现(java)(转载)

    博客分类:
  • java
阅读更多
通过ServletRequest类的getInputStream()方法获得一个客户端向服务器发出的数据流、分析上传的文件格式,根据分析结果将多个文件依次输出服务器端的目标文件中。
       格式类似下面:
//文件分隔符
-----------------------------7d226137250336
//文件信息头
Content-Disposition: form-data; name="FILE1"; filename="C:\Documents and Settings\Administrator.TIMBER-4O6B0ZZ0\My Documents\tt.sql"
Content-Type: text/plain
//源文件内容
create table info(
content image null);
//下一个文件的分隔符
-----------------------------7d226137250336
Content-Disposition: form-data; name="FILE2"; filename=""
Content-Type: application/octet-stream
-----------------------------7d226137250336
每个表单提交的元素都有分隔符将其分隔,其提交的表单元素的名称和对应的输入值之间也有特殊的字符将其分隔开。

都知道格式了,呵呵就尝试了一下,参照了pell中的MultipartRequest类写了一个上传组件(本来不想自己写的,想改造改造就完事的,可惜反编译出来的代码比较难读),代码如下:

  1/**//*
  2 * 只支持在windows下上传文件
  3 * Created on 2005-10-10
  4 *
  5 * TODO To change the template for this generated file go to
  6 * Window - Preferences - Java - Code Style - Code Templates
  7 */
  8package study.http.upload;
  9
10import java.io.BufferedInputStream;
11import java.io.File;
12import java.io.FileNotFoundException;
13import java.io.FileOutputStream;
14import java.io.IOException;
15import java.io.InputStream;
16import java.io.UnsupportedEncodingException;
17import java.util.ArrayList;
18import java.util.Hashtable;
19import java.util.Iterator;
20import java.util.List;
21import java.util.Map;
22import java.util.Set;
23
24import javax.servlet.ServletException;
25import javax.servlet.ServletInputStream;
26import javax.servlet.http.HttpServlet;
27import javax.servlet.http.HttpServletRequest;
28import javax.servlet.http.HttpServletResponse;
29
30/** *//**
31 * @author liusuifeng
32 *
33 * TODO To change the template for this generated type comment go to Window -
34 * Preferences - Java - Code Style - Code Templates
35 */
36public class TestServlet extends HttpServlet {
37
38    public final static String DEFAULT_ENCODING = "ISO8859_1";
39
40    public final static String CHINESE_ENCODING = "GBK";
41
42    public final static String SIGN_BOUNDARY = "boundary=";
43
44    public final static String SIGN_FORMELEMENT = "name=";
45
46    public final static String SIGN_FORMFILE = "filename=";
47
48    public final static String SIGN_NOTFILE = "application/octet-stream";
49
50    public final static String SIGN_MULTIDATA = "multipart/form-data";
51
52    public final static String CHINESE_CONTENTTYPE = "text/html; charset=GBK";
53
54    private Hashtable paratable = new Hashtable();
55
56    private Hashtable filetable = new Hashtable();
57
58    private String strBoundary = "";
59   
60    private String strSavePath="";
61   
62
63    private static void println(String s) {
64        System.out.println(s);
65    }
66   
67   
68   
69
70    /** *//**
71     * 增加数据到对应的Hashtable中
72     * 说明:如果Hashtable中已存在该键值,则将新增加的和原来的都封装到列表中。
73     * @param table   
74     * @param paraName
75     * @param paraValue
76     */
77    private static void addElement(Hashtable table, String paraName,
78            Object paraValue) {
79        ArrayList list = new ArrayList();
80        if (table.containsKey(paraName)) {
81            Object o = table.get(paraName);
82            if (o instanceof List) {
83                ((List) o).add(paraValue);
84            } else {
85                list.add(o);
86                list.add(paraValue);
87                o = list;
88            }
89            table.put(paraName, o);
90        } else {
91            table.put(paraName, paraValue);
92        }
93    }
94
95    public static String getHashInfo(Hashtable paratable){
96        StringBuffer sb=new StringBuffer();
97        Set keySet=paratable.keySet();
98        Iterator it=keySet.iterator();
99        while(it.hasNext()){
100           
101            Object keyobj=it.next();
102            Object valueobj=paratable.get(keyobj);
103           
104            sb.append("<tr>");
105            sb.append("<td>"+keyobj.toString()+"</td>");
106            if(valueobj instanceof List){
107                sb.append("<td>");
108                int isize=((List)valueobj).size();
109                for(int i=0;i<isize;i++){
110                    Object tempobj=((List)valueobj).get(i);
111                    if(i<isize-1){
112                       sb.append(tempobj.toString()+",");
113                    }
114                    else{
115                       sb.append(tempobj.toString());
116                    }
117                }
118               
119                sb.append("</td>");
120            }
121            else{
122                sb.append("<td>"+valueobj.toString()+"</td>");
123            }
124            sb.append("</tr>");
125        }
126        return sb.toString();
127    }
128   
129   
130    private static byte[] getfileBytes(InputStream is) {
131        List byteList = new ArrayList();
132        byte[] filebyte = null;
133        int readbyte = 0;
134        try {
135            while ((readbyte = is.read()) != -1) {
136                byteList.add(new Byte((byte) readbyte));
137            }
138        } catch (FileNotFoundException e) {
139            e.printStackTrace();
140        } catch (IOException e) {
141            e.printStackTrace();
142        }
143        filebyte = new byte[byteList.size()];
144        for (int i = 0; i < byteList.size(); i++) {
145            filebyte[i] = ((Byte) byteList.get(i)).byteValue();
146        }
147        return filebyte;
148
149    }
150   
151   
152
153   
154    protected void doGet(HttpServletRequest request,
155            HttpServletResponse response) throws ServletException, IOException {
156        doPost(request, response);
157    }
158
159    protected void doPost(HttpServletRequest request,
160            HttpServletResponse response) throws ServletException, IOException {
161        paratable = new Hashtable();
162        filetable = new Hashtable();
163        strSavePath=this.getInitParameter("savepath");
164        File file=new File(strSavePath);
165        if(!file.exists()){
166            file.mkdirs();
167        }
168        String contentType = request.getContentType();   
169        strBoundary = getBoundary(contentType);
170        ServletInputStream sis = request.getInputStream();
171        BufferedInputStream bis = new BufferedInputStream(sis);
172        parseInputStream(bis);
173        appendPara(request.getParameterMap());  /**//*追加url对应传递的参数*/
174        response.setContentType(CHINESE_CONTENTTYPE);
175       
176//        response.getWriter().write(getOutPutInfo());
177//        response.getWriter().write(new String(getfileBytes(sis),"GBK"));
178        bis.close();
179        sis.close();
180        request.setAttribute("para",paratable);
181        request.setAttribute("file",filetable);
182       
183        this.getServletContext().getRequestDispatcher("/result.jsp").
184        forward(request,response);
185       
186    }
187   
188   
189    /** *//**
190     * 不用Hashtable对应的put方法,目的避免覆盖重复的键值
191     * @return
192     */
193    private void appendPara(Map map){
194       
195        if(map!=null){
196            Set keySet=map.keySet();
197            Iterator it=keySet.iterator();
198            while(it.hasNext()){
199                Object keyobj=it.next();
200                String[] valueobj=(String[])map.get(keyobj);
201                println("keyobj===="+keyobj);
202                println("valueobj===="+valueobj);
203                for(int i=0;i<valueobj.length;i++){
204                    addElement(paratable,(String)keyobj,valueobj[i]);
205                }
206            }
207        }
208    }
209   
210   
211
212    /** *//**
213     * 输出上传表单信息
214     *
215     * @param pw
216     */
217    protected String getOutPutInfo() {
218        StringBuffer sb = new StringBuffer();
219        sb.append("<table width=100% border=1>");
220        sb.append("<tr><td>参数名</td><td>参数值</td></tr>");
221        sb.append(getHashInfo(paratable));
222        sb.append(getHashInfo(filetable));
223        sb.append("</table>");
224        return sb.toString();
225    }
226
227    /** *//**
228     * 解析字节流
229     * @param is
230     */
231    private void parseInputStream(InputStream is) {
232        byte[] sizes = getfileBytes(is);
233        int icount = 0;
234        String s = "";
235        int readbyte = 0;
236        String reals;
237        try {
238            reals = new String(sizes, DEFAULT_ENCODING);
239            String realsvalue = new String(sizes, CHINESE_ENCODING);
240            String[] arrs = reals.split(strBoundary);
241            String[] arrsvalue = realsvalue.split(strBoundary);
242            for (int i = 0; i < arrs.length; i++) {
243                String tempStr = arrs[i];
244                String tempStr2 = arrsvalue[i];
245                if (tempStr.indexOf(SIGN_FORMFILE) >= 0) {
246                    readFile(tempStr, tempStr2);
247                } else {
248                    readParameter(tempStr2);
249                }
250            }
251        } catch (UnsupportedEncodingException e) {
252            e.printStackTrace();
253        }
254
255    }
256
257    /** *//**
258     * 获取本次上传对应的表单元素间的分隔符,注意该分隔符是随机生成的
259     * @param contentType  
260     * @return
261     */
262    private String getBoundary(String contentType) {
263        String tempStr = "";
264        if (contentType != null && contentType.startsWith(SIGN_MULTIDATA)
265                && contentType.indexOf(SIGN_BOUNDARY) != -1) {
266            //获取表单每个元素的分隔符
267            tempStr = contentType
268                    .substring(
269                            contentType.indexOf(SIGN_BOUNDARY)
270                                    + SIGN_BOUNDARY.length()).trim();
271        }
272        return tempStr;
273    }
274
275    /** *//**
276     * 解析文件上传对应的字节流。实现算法<br>
277     * 通过解析ISO8859_1编码方式的字符串后转换成对应上传文件的字节。
278     * 通过解析GBK编码方式的字符串后转换成对应上传文件的文件名。
279     * 说明:因不清楚字节在不同编码方式下的关系,只好使用两个字符串(比较影响性能,以后优化)
280     * @param s   以ISO8859_1编码方式组成的字符串
281     * @param s2  以GBK编码方式组成的字符串
282     */
283    private void readFile(String s, String s2) {
284        int filepos = -1;
285        if ((filepos = s.indexOf(SIGN_FORMFILE)) >= 0) {
286            String realName = readFileName(s2);
287            //部分确定上传的是文件而不是任意输入的字符串
288            if(!realName.equals("")&& realName.length()>0 && (realName.indexOf(".")>=0)){
289                String filepath = readWriteFile(s, realName);
290                addElement(filetable, realName, filepath);
291            }
292        }
293        else {
294            /**//*上传的不是文件*/
295            if (s.indexOf(SIGN_NOTFILE) >= 0) {
296                return;
297            }
298        }
299
300    }
301   
302    /** *//**
303     * 解析文件上传对应的名称
304     * 实现说明:如果上传的是文件对应格式为:<br>filename="文件名"</br> 格式
305     * 通过处理可以拆分出对应的文件名 
306     * @param s   以GBK编码方式组成的包含文件名的字符串
307     * @return    对应上传文件的文件名(不包括文件路径)
308     */
309    private String readFileName(String s) {
310        int filepos = s.indexOf(SIGN_FORMFILE);
311        String tempstr = s.substring(filepos + SIGN_FORMFILE.length() + 1);
312        int iendpos = tempstr.indexOf("\"");
313        String fileName = tempstr.substring(0, iendpos);
314        int ifilenamepos = fileName.lastIndexOf("\\");
315        String realName = fileName.substring(ifilenamepos + 1);       
316        return realName;
317
318    }
319
320    /** *//**
321     * 通过解析ISO8859_1编码方式的字符串后转换成对应上传文件的字节。
322     * 实现算法说明:文件名转化后的字节和具体的文件字节中间是以两个重复的两个字符隔开,
323     * 对应char值为13,10,转换后的字符对应的最后四个字符也是格式字符,获取对应中间的字节即为
324     * 上传文件的真正的字节数
325     * @param s        以ISO8859_1编码方式组成的包含文件名和具体文件字节的字符串
326     * @param realName  对应的文件名
327     * @return          对应生成的文件名包括全路径
328     */
329    private String readWriteFile(String s, String realName) {
330        int filepos = s.indexOf(SIGN_FORMFILE);
331        String tempstr = s.substring(filepos + SIGN_FORMFILE.length() + 1);
332        int icount = 0;
333        while (true) {
334            int charnum = tempstr.charAt(icount);
335            int charnum2 = tempstr.charAt(icount + 1);
336            int charnum3 = tempstr.charAt(icount + 2);
337            int charnum4 = tempstr.charAt(icount + 3);
338            if (charnum == 13 && charnum2 == 10 && charnum3 == 13
339                    && charnum4 == 10) {
340                break;
341            }
342            icount++;
343        }
344        String filevalue = tempstr.substring(icount + 4, tempstr.length() - 4);
345        FileOutputStream fos = null;
346        String createName=strSavePath + realName;
347        File uploadfile = new File(createName);       
348        String shortname=realName.substring(0,realName.lastIndexOf("."));
349        String filetype=realName.substring(realName.lastIndexOf(".")+1);
350        int namecount=1;
351        while(uploadfile.exists()){           
352            createName=strSavePath+shortname+"["+namecount+"]"+"."+filetype;
353            uploadfile=new File(createName);
354            namecount++;
355           
356        }
357        try {
358            byte[] filebytes = filevalue.getBytes(DEFAULT_ENCODING);
359            fos = new FileOutputStream(uploadfile);
360            fos.write(filebytes);
361        } catch (FileNotFoundException e) {
362            e.printStackTrace();
363        } catch (IOException e1) {
364
365            e1.printStackTrace();
366        } finally {
367            try {
368                fos.close();
369            } catch (IOException e2) {
370
371                e2.printStackTrace();
372            }
373        }
374
375        return createName;
376    }
377
378   
379    /** *//**
380     * 解析提交过来的表单元素对应的名称以及值<br>
381     * 实现说明:如果表单元素的是对应格式为:<br>name="表单元素名"</br> 格式
382     * 表单元素名和具体的输入值中间是以两个重复的两个字符隔开,
383     * 对应char值为13,10,转换后的字符对应的最后四个字符也是格式字符,获取对应中间的字符即为
384     * 表单元素的输入值
385     * 通过处理可以拆分出对应的表单元素名以及输入值 
386     * @param s   以GBK编码方式组成的包含表单元素名和值的字符串   
387     */   
388    private void readParameter(String s) {
389        String paraName = "";
390        String paraValue = "";
391        int istartlen = -1;
392        int iendlen = -1;
393
394        if ((istartlen = s.indexOf(SIGN_FORMELEMENT)) >= 0) {
395            String tempstr = s.substring(istartlen + SIGN_FORMELEMENT.length()
396                    + 1);
397            int nameindex = tempstr.indexOf("\"");
398            paraName = tempstr.substring(0, nameindex);
399            paraValue = tempstr.substring(nameindex + 5, tempstr.length() - 4);
400            addElement(paratable, paraName, paraValue);
401        }
402    }
403
404}
组件简单说明:
       上传路径在servlet初始参数中设定。
       上传的表单元素、文件数据分别封装在Hashtable中。

做了测试,测试环境说明:
AppServer: WeblogicSP4
OS:  WindowXP/ Soloaris 9.0
测试程序:
index.jsp(文件上传页面):
<html>
  <head><title>File Upload</title></head>
  <body>

  <form  name="kkkkkk"     action="test.upload?ssss=bbbbbbbbb&ccccc=eeeeeeee" enctype="multipart/form-data" method="post" >
      <input type=text name="ssss" ><br>
      <input type=text name="ssss" ><br>
      <input type=text name="ssss3" ><br>
      <textarea name="araea"></textarea><br>
     
      <input type=file name="cccc"  ><br>
       <input type=file name="ddddd" ><br>
      <input type=submit value="submit" name="bbbbbbbbb">    
  </form>

  </body>
</html>
result.jsp(查看提交表单数据)
<%@ page contentType="text/html;charset=GBK"%>
<%@ page import="java.util.*"%>
<%@ page import="study.http.upload.*"%>



<%
  Hashtable paratable=(Hashtable)request.getAttribute("para");
  Hashtable filetable=(Hashtable)request.getAttribute("file");
  String parastr=TestServlet.getHashInfo(paratable);
  out.println("<table width=100% border=1>");
  out.println(parastr);
  out.println(TestServlet.getHashInfo(filetable));
  out.println("</table>");

%>
<html>
  <head><title>File Upload</title></head>
  <body>

 

  </body>
</html>

测试时对应的web应用已经指定相关字符集,weblogic.xml内容如下:
<weblogic-web-app>
  <charset-params>
        <input-charset>
            <resource-path>/*</resource-path>
            <java-charset-name>GBK</java-charset-name>
        </input-charset>
    </charset-params>
</weblogic-web-app>


测试运行基本正常,总算解决了心中的一个很长时间的困惑。
分享到:
评论

相关推荐

    Xmodem和Ymodem 传输协议JAVA实现

    本文将深入探讨这两种协议的工作原理,并提供它们在Java环境中的实现。 **Xmodem协议** Xmodem是最简单的文件传输协议之一,每一步传输128字节的数据块。它通过校验和机制来检测数据传输中的错误。Xmodem协议分为两...

    java实现文件批量上传

    在Java开发中,文件批量上传是一项常见的功能,尤其在企业级应用中,用户可能需要上传大量数据或文件。本教程将介绍如何利用SWF(Simple Workflow)和EXT库来实现这一功能。SWF是一个用于创建富互联网应用程序的前端...

    java图形化实现文件上传

    利用java图形化界面和网络编程相结合实现的--文件上传。 运行步骤: (1)分别运行工程两个包中的两个.java文件(UploadClient.java和UploadServer.java)分别会弹出“上传客服端”和“上传服务器”两个窗口。 ...

    Java自带的HttpURLConnection访问接口实现文件上传

    在本文中,我们将深入探讨如何使用HttpURLConnection实现文件上传,同时也会涉及普通参数的传递。 首先,我们需要理解HTTP请求的基本结构。HTTP请求通常由以下几个部分组成:请求行、请求头、空行和请求体。在文件...

    java实现CMPP协议

    6. **测试与调试**:在开发过程中,可以使用_cmpp3.0_文件中的样例数据进行单元测试,模拟SMSC的响应,确保协议实现的正确性。此外,日志记录也是必不可少的,它可以帮助开发者在出现问题时快速定位和解决问题。 7....

    Java实现udp协议的文件传输

    在实现文件传输时,我们不能一次性发送整个文件,因为UDP的数据报大小受到限制(通常为65535字节)。因此,我们需要将文件拆分成多个小块,每个块作为一个独立的数据报发送。同时,为了确保接收端能正确组装文件,...

    Java 上传文件到 SharePoint

    总之,Java上传文件到SharePoint是一个涉及网络通信、文件操作和认证授权的复杂过程。理解并掌握这些概念,结合适当的工具或库,可以有效地实现文件在Java应用和SharePoint之间的传输。在阅读给定的博客文章...

    java 实现 icmp协议测试

    java 实现 icmp协议测试 需要在java lib目录下添加libjpcap.so文件

    ajax实现java文件下载

    本话题将详细探讨如何通过Ajax实现Java文件的下载,并介绍相关的核心概念和技术。 1. **Ajax**(Asynchronous JavaScript and XML)是一种在不重新加载整个网页的情况下,能够更新部分网页的技术。它通过JavaScript...

    java实现利用HTTP基于servlet上传文件至服务器.pdf

    本文介绍了 Java 实现文件上传的方法,包括文件上传概述、HTTP 协议简介、Servlet 简介、文件上传实现和文件上传过程等内容。通过本文,读者可以了解 Java 实现文件上传的基本原理和方法,并应用于实际开发中。

    java处理文件上传的底层实现以及java模拟post协议实现文件上传

    3. 模拟POST协议实现文件上传: 有时,我们需要在服务端模拟POST请求来上传文件,例如测试或集成其他API。可以使用`HttpURLConnection`或第三方库如Apache HttpClient来实现。以下是一个使用HttpURLConnection的...

    如何利用Java实现QQ文件传输功能

    为了在Java中实现文件传输,可以采用UDP协议或者TCP协议。TCP协议提供可靠的数据传输服务,能够保证数据的有序、可靠和无重复地传输,但可能会有较高的延迟。UDP协议不保证数据的传输可靠性,但是它的数据包小,传输...

    实现文件上传的java代码

    本篇文章将详细解析如何实现文件上传的Java代码,主要关注`Upload.java`这个类的实现。 首先,理解文件上传的基本原理至关重要。在HTTP协议中,文件上传通常依赖于多部分/形式数据(Multipart/form-data)的请求...

    电信SMGP协议java实现

    本项目提供了Java版本的SMGP协议实现,且附带了示例代码,方便开发者快速理解和应用。 **1. SMGP协议详解** SMGP协议是一种基于TCP/IP的通信协议,用于连接短信中心(SMSC)和业务系统。协议主要分为三个层次:链路...

    Java使用NFS实现上传、下载、读取文件工具类

    1. 文件上传(File Upload) 2. 文件下载(File Download) 3. 文件读取(File Reading) 4、优点: 封装性:工具类封装了NFS相关的复杂连接、认证和I/O操作细节,使得业务层代码无需关心底层通信协议,只需通过...

    java实现大文件上传并有进度条及其代码解析

    本文将详细介绍如何使用Java实现大文件的上传并展示进度条,同时解析相关的代码实现。 1. **大文件分块上传** 大文件上传的关键在于避免一次性加载整个文件到内存,因为这可能导致内存溢出。Java中,我们可以使用`...

    JAVA代码实现远程操作服务器文件

    SCPClient是一个基于ssh的文件传输协议,可以实现文件的上传和下载。通过使用SCPClient,可以实现远程服务器文件的上传和下载。 5. 使用Session实现远程服务器文件的操作 Session是一个远程服务器文件操作的会话,...

    java代码实现文件上传和下载

    在java代码中实现文件的上传和下载,通过页面的file文件上传到java代码段,获取文件的大小和名字

    使用java实现Xmodem协议

    Java实现Xmodem协议主要涉及的是串口通信和数据传输中的错误检测与纠正技术。Xmodem协议是一种早期的文件传输协议,它主要用于通过慢速的串行通信线路进行数据传输,例如调制解调器连接。在Java中实现Xmodem协议,...

    Java实现opc通信协议代码

    Java实现OPC通信协议主要涉及的是Java编程语言与OPC(OLE for Process Control)技术的结合,这是一种在工业自动化领域广泛使用的数据交换标准。在Java中实现OPC通信,通常需要借助于一些开源库或者商业组件,这些库...

Global site tag (gtag.js) - Google Analytics