<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    beauty_beast

    上善若水 厚德載物

    采用HTTP協議上傳文件實現(java)

    Posted on 2005-10-13 21:41 柳隨風 閱讀(7119) 評論(1)  編輯  收藏
        j2ee開發也好幾年,文件上傳功能基本都是用的第三方的組件,雖然知道其原理,但一直不知道具體是如何實現的,最近有時間,正好同事開發遇到這方面的問題,查了點資料,基本明白了具體實現,為了備忘,就寫下這篇隨筆。
        首先說說同事遇到的問題,最近的項目是使用webwork開發的,同事需要實現多文件上傳的功能,但是
    webwork原則上支持三種上傳解析 pell,cos,jakarta,三種都有自身的優勢和不足,使用發現:
    在webwork中只有pell支持中文文件路徑,但是使用該方式只能處理一個上傳文件,
    而其他兩種雖然支持多文件上傳,但中文支持不好。

    上述的見解都是本人的個人認識,可能支持只是我不知道,如果有誰知道不妨指導一下,不勝感激。
    上傳解析的實現簡單說一下:
           通過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>



    測試運行基本正常,總算解決了心中的一個很長時間的困惑。

    注:以上的程序只是本人學習的代碼,有很多欠缺的地方,歡迎大家指正,不甚感激。
             上面代碼只供參考,嘿嘿出了問題我就不負責了。

    最近沒啥事,又出差在外,唉日子過得好慢!!!!!

















      




















            

    Feedback

    # re: 采用HTTP協議上傳文件實現(java)  回復  更多評論   

    2006-09-27 14:28 by testdfsdgf
    good

    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 在线免费一区二区| 国产成人精品一区二区三区免费| 国产精品亚洲自在线播放页码| 亚洲综合日韩中文字幕v在线| 亚洲2022国产成人精品无码区 | 国产在线精品一区免费香蕉| 国产福利免费视频| 久久久久国色AV免费观看| 中文字幕永久免费| 日本中文字幕免费高清视频| 久草免费福利资源站| 久久不见久久见免费视频7| 19禁啪啪无遮挡免费网站| 成人福利免费视频| 扒开双腿猛进入爽爽免费视频| 成年男女男精品免费视频网站| 精品熟女少妇AV免费观看| 免费鲁丝片一级在线观看| 国产视频精品免费| 亚洲精品视频在线看| 亚洲线精品一区二区三区影音先锋 | a级毛片在线免费观看| 午夜免费福利视频| 95老司机免费福利| 色婷婷7777免费视频在线观看 | 国产无遮挡裸体免费视频在线观看| 久久免费高清视频| 69pao强力打造免费高清| 最近中文字幕无免费视频| 国产精品免费视频网站| 2022中文字字幕久亚洲| 亚洲毛片在线观看| 亚洲熟女www一区二区三区| 免费一级毛suv好看的国产网站| 99久久99这里只有免费的精品| 中文免费观看视频网站| 国产福利免费观看| 久久精品国产精品亚洲蜜月| 亚洲自国产拍揄拍| www成人免费视频| 麻豆高清免费国产一区|