tomcat實現文件上傳下載


實現下載
修改server.xml
修改web.xml
 

實現上傳
實現客戶端的上傳
post請求
代碼實現

實現服務端的處理
 

小結
 
 
 
 
實現下載
實現下載需要
 - 修改Tomcat中的server.xml
 - 修改web.xml
 
修改server.xml
在<Host> </Host>中加入(一般在文件末尾可以找到)
 
<Context docBase="C://Download" path="/download" reloadable="true" />1
其中docBase項是本地目錄,path項是訪問目錄
 
修改web.xml
 
   <servlet>
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>true</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>12345678910111213
其中listings下確保值是true
這時在C://Download下存放文件,並打開相應的地址,就能看見文件目錄了
 
實現上傳
實現上傳也是分兩步

實現客戶端的上傳
實現服務端的處理
 

實現客戶端的上傳
 
post請求
我們都知道http常用的請求方式有get、post等,其中我們實現文件上傳,就是模擬表單采用post方式上傳文件
首先來看一下post報文的格式,以上傳一張圖片為例
 
POST/logsys/home/uploadIspeedLog!doDefault.html HTTP/1.1
Accept: text/plain, */*
Accept-Language: zh-cn
Host: 192.168.24.56
Content-Type:multipart/form-data;boundary=【這里隨意設置】
User-Agent: WinHttpClient
Content-Length: 3693
Connection: Keep-Alive123456789
以上部分是請求的參數,不需要我們完全實現,通過方法傳參的方式自動構建
 
--【這里隨意設置】
Content-Disposition: form-data;name="file1";filename="C://E//a.png"
Content-Type:application/octet-stream

<文件的二進制信息>
--【這里隨意設置】--1234567
這一部分是報文的內容,需要我們通過字符串或者字節流自行拼接,並且格式不能出錯

  注意,三處【這里隨意設置】的部分必須完全相同
 

代碼實現
 
public static void uploadFile(String fileName) { 
    try { 
        // 換行符 
        final String newLine = "\r\n"; 
        //數據分隔線 
        final String BOUNDARY = "【這里隨意設置】";//可以隨意設置,一般是用  ---------------加一堆隨機字符
        //文件結束標識
        final String boundaryPrefix = "--"; 
        // 服務器的域名 
        URL url = new URL("http://localhost:8070/secondary/HandleFile"); 
        HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 
        // 設置為POST情 
        conn.setRequestMethod("POST"); 
        // 發送POST請求必須設置如下兩行 
        conn.setDoOutput(true); 
        //conn.setDoInput(true);/不必加,默認為true 
        //conn.setUseCaches(false);//用於設置緩存,默認為true,不改也沒有影響(至少在傳輸單個文件這里沒有) 
        // 設置請求頭參數 
        //關於keep-alive的說明:https://www.kafan.cn/edu/5110681.html
        //conn.setRequestProperty("connection", "Keep-Alive");//現在的默認設置一般即為keep-Alive,因此此項為強調用,可以不加
        //conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows Nt 5.1; SV1)");//用於模擬瀏覽器,非必須
        //用於表示上傳形式,必須
        conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY); 
        //這里是Charset,網上大多都是Charsert???我的天,笑哭。不過好像沒什么影響...不知道哪位大佬解釋一下
        conn.setRequestProperty("Charset", "UTF-8");
        //獲取conn的輸出流用於向服務器輸出信息
        OutputStream out = new DataOutputStream(conn.getOutputStream()); 
        //構造文件的結構 
        //寫參數頭
        StringBuilder sb = new StringBuilder(); 
        sb.append(boundaryPrefix)//表示報文開始
          .append(BOUNDARY)//添加文件分界線
          .append(newLine);//換行,換行方式必須嚴格約束
        //固定格式,其中name的參數名可以隨意修改,只需要在后台有相應的識別就可以,filename填你想要被后台識別的文件名,可以包含路徑
        sb.append("Content-Disposition: form-data;name=\"file\";")
            .append("filename=\"").append(fileName)
            .append("\"")
            .append(newLine); 
        sb.append("Content-Type:application/octet-stream"); 
        //換行,為必須格式
        sb.append(newLine); 
        sb.append(newLine); 
        //將參數頭的數據寫入到輸出流中 
        out.write(sb.toString().getBytes()); 
        System.out.print(sb);
        //寫文件數據(通過數據輸入流) 
        File file = new File(fileName);
        DataInputStream in = new DataInputStream(new FileInputStream( 
                file)); 
        byte[] bufferOut = new byte[1024]; 
        int bytes = 0; 
        //每次讀1KB數據,並且將文件數據寫入到輸出流中 
        while ((bytes = in.read(bufferOut)) != -1) { 
            out.write(bufferOut, 0, bytes); 
        } 
        in.close();
        //寫參數尾 
        out.write(newLine.getBytes()); 
        System.out.print(new String(newLine.getBytes()));
        // 定義最后數據分隔線,即--加上BOUNDARY再加上--。
        sb = new StringBuilder();
        sb.append(newLine)
            .append(boundaryPrefix)
            .append(BOUNDARY)
            .append(boundaryPrefix)
            .append(newLine);
        // 寫上結尾標識 
        out.write(sb.toString().getBytes()); 
        System.out.println(sb);
        //輸出結束,關閉輸出流
        out.flush(); 
        out.close(); 
        //定義BufferedReader輸入流來讀取URL的響應 ,注意必須接受來自服務器的返回,否則服務器不會對發送的post請求做處理!!這里坑了我好久
        BufferedReader reader = new BufferedReader(new InputStreamReader( 
                conn.getInputStream())); 
        String line = null; 
        while ((line = reader.readLine()) != null) { 
            System.out.println(line); 
        } 
    } catch (Exception e) { 
        System.out.println("發送POST請求出現異常!" + e); 
        e.printStackTrace(); 
    } 

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
注釋很清楚,結合post請求的格式理解一下,就不一一解釋了
 
實現服務端的處理
上述的代碼會形成一個post請求到服務器,於是相應的接口的dopost()方法就會相應
dopost()中做了什么呢?

獲取報文中的文件信息
處理文件信息,包括識別文件名,識別文件類型(由用戶定義,而不是文件后綴)
存儲到本地(服務器端硬盤)

代碼如下:
 
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
//注意導的包
/**
 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
 */
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    response.setCharacterEncoding("UTF-8");
    request.setCharacterEncoding("UTF-8");
    response.setContentType("text/html");
    PrintWriter out = response.getWriter();
    //輸出到客戶端瀏覽器
    DiskFileItemFactory factory = new DiskFileItemFactory();
    ServletFileUpload sup = new ServletFileUpload(factory);//這里要將factory傳入,否則會報NullPointerException: No FileItemFactory has been set.
    try{
        List<FileItem> list = sup.parseRequest(request);
        for(FileItem fileItem:list){
            System.out.println(fileItem.getFieldName()+"--"+fileItem.getName());
            if(!fileItem.isFormField()){
                if("file".equals(fileItem.getFieldName())){
                    //獲取遠程文件名
                    String remoteFilename = new String(fileItem.getName().getBytes(),"UTF-8");
                    File remoteFile = new File(remoteFilename);
                    //設置服務器端存放文件的位置
                    File locate = new File("C://E//download/",remoteFile.getName());
//                      locate.getParentFile().mkdirs();//用於確保文件目錄存在,如果為單級目錄可以去掉
                    locate.createNewFile(); //創建新文件
                    InputStream ins = fileItem.getInputStream();   //FileItem的內容
                    OutputStream ous = new FileOutputStream(locate); //輸出
                    try{
                        byte[] buffer = new byte[1024]; //緩沖字節
                        int len = 0;
                        while((len = ins.read(buffer))>-1)
                            ous.write(buffer, 0, len);
                    }finally{
                        ous.close();
                        ins.close();
                    }
                }
            }      
        }
    }catch (FileUploadException e){}
    out.print("everything is ok");
    out.flush();
    out.close();
}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
同樣注釋很清楚,不再解釋了
小結
將上述過程理解清楚后,再結合post報文的格式,那么是否就可以處理多個文件同時上傳了呢?如果對客戶端的流做出一些大小限制,是不是就可以限制上傳大小了?…一個小demo,幫助理解一下基礎的實現。
---------------------
作者:Sailist
來源:CSDN
原文:https://blog.csdn.net/sailist/article/details/81083205
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM