1. 程式人生 > >利用Servlet上傳檔案(在servlet中處理MIME型別的post資料)

利用Servlet上傳檔案(在servlet中處理MIME型別的post資料)

一、得到HTTP請求訊息的內容
    下面是一個純JAVA的應用程式,它可以獲取表單提交時請求訊息的全部內容,該程式將請求訊息的內容顯示在螢幕上同時寫入程式執行路徑的一個名為request.txt的文字檔案中。
     該程式涉及到JAVA的基本知識:Socket程式設計、多執行緒、Servlet程式設計,但都是一些最基本的知識,只要學習過JAVA應該不難看懂。另外,我在這裡放這個程式的另一個目的是幫助我們對HTTP協議有一點感性的認識。
1.1、HServerAccept.java
import java.io.*;
import java.net.*;
public class HServerAccept implements Runnable{
 //偵聽埠
 final static int LISTEN_PORT=8091;
 public void run(){
  //服務Socket
  ServerSocket server=null;
  try{
   server=new ServerSocket(this.LISTEN_PORT);
   System.out.println("waiting for connecting......");
  }catch(IOException e){
   System.out.println("can't connect to the port:"+this.LISTEN_PORT
    +";"+e.getMessage());
   System.exit(0);
  }
 
  while(true){
   try{
    //當與客戶連線時server.accept()返回一個Socket物件
    new Thread(new ServerEchoRequest(server.accept())).start();
    System.out.println("has start a connection.");
   }catch(IOException e){
    System.out.println("can't recieve data!"+e.getMessage());
   }
  }
 }
 //
 public static void main(String[] args){
  new Thread(new HServerAccept()).start();
 }
}

class ServerEchoRequest implements Runnable{
 private Socket m_Socket=null;
 final static int MAX_BUFF=400;
 private final static int TIMEOUT=3000;
 
 public ServerEchoRequest(Socket socket)throws SocketException{
  this.m_Socket=socket;
  //m_Socket.setSoTimeout(TIMEOUT);
 }
 
 public void run(){
  try{
   getClient();
  }catch(IOException e){
   System.out.println(e);
   System.exit(0);
  }catch(ClassNotFoundException cl){
   System.out.println(cl);
   System.exit(0);
  }
 }
 
 protected void getClient()throws IOException,ClassNotFoundException{
  DataInputStream in=new DataInputStream(m_Socket.getInputStream());
  String s;
  File file=new File("request.txt");
  PrintWriter fileOut=new PrintWriter(new FileWriter(file));
  while((s=in.readLine())!=null){
   System.out.println(s);
   fileOut.println(s);
   fileOut.flush();
  }
 }
}
ServerEchoRequest不是一個公有類可以和HServerAcccept類一齊放在HSereverAccept.java檔案中。
1.2、客戶端是一個html檔案,下面是Client.html的原始碼:


<html>
<head><title>檔案上傳</title></head>
<body>
<form method="POST" action="http://localhost:8091" enctype="multipart/form-data">
<p>&nbsp;ID:<input type="text" name="fileId" size="20"></p>
<p>File:<input type="file" name="fileData" size="20"></p>
<p><input type="submit" value="UpLoad" name="uploadFile"></p>
</form>
</body>
</html>
1.3、下面是程式往request.txt中寫入的典型的內容

POST / HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash,

application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Accept-Language: zh-cn
Content-Type: multipart/form-data; boundary=---------------------------7d71c50110368
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)
Host: localhost:8091
Content-Length: 63792
Connection: Keep-Alive
Cache-Control: no-cache

-----------------------------7d71c50110368
Content-Disposition: form-data; name="fileId"

123456789
-----------------------------7d71c50110368
Content-Disposition: form-data; name="fileData"; filename="E:/JAVA?à

??/hackers/j2ee/servlet/passfile/passedFile.jpg"
Content-Type: image/pjpeg

這裡是一堆亂碼(也就是上傳檔案的資料)
-----------------------------7d71c50110368
Content-Disposition: form-data; name="uploadFile"

UpLoad
-----------------------------7d71c50110368--
二、利用Servlet得到上傳的檔案
2.1、目錄結構
     WEB-INF
           classes
                  shilei
                         UploadFileServlet.java
                         UploadFileServlet.class
     index.html
2.2、UploadFileServlet.java
package shilei;
/**
 *上傳檔案
 */
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class UploadFileServlet extends HttpServlet{
 public static final int NONE=0;//狀態碼,表示沒有特殊操作
 public static final int DATA_HEADER=1;//下一行要讀到報頭資訊
 public static final int FIELD_DATA=2;//下面要讀到表單域的文字值
 public static final int FILE_DATA=3;//下面要讀的是上傳檔案和二進位制資料
 //請求訊息實體的總長度(請求訊息中除訊息頭之外的資料長度)
 private int totalBytes;
 //容納請求訊息實體的位元組陣列
 /**
  *在讀取二進位制資料檔案時需要注意,在用文字形式按行讀入資料時,因為readLine()
  *不能讀入回車換行符,按行讀入資料會丟失二進位制資料中的"0A"和"0D"(十六進位制)字
  *符.所以將響應實體放入一個二進位制位元組陣列中,然後在位元組陣列中對檔案資料進行定
  *位,這樣就不會丟失資料.
  */
 private byte[] requestMessage;
 private String requestMessageStr;//表示訊息實體的字串
 //
 private String contontType="";//請求訊息型別
 private String fieldName="";//表單域的名稱
 private String fieldValue="";//表單域的值
 //
 private String boundary="";//分界符字串
 private String lastBoundary="";//結束分界符字串
 //
 private int fileLength=0;//上傳檔案的長度
 private String fileId="";//上傳檔案的ID
 private String fileName="";//上傳檔案的名稱
 //容納表單域的名稱/值的雜湊表
 private Hashtable formFields=new Hashtable();
 public void doPost(HttpServletRequest req,HttpServletResponse res)
  throws ServletException,IOException{
  this.totalBytes=req.getContentLength();
  this.requestMessage=new byte[this.totalBytes];
  this.contontType=req.getContentType();
  //在訊息頭型別中找到分界符的定義
  int pos=this.contontType.indexOf("boundary=");
  if(pos!=-1){
   pos+="boundary=".length();
   //解析出分界符
   //在資料部分的分界符比在Content-Type中規定的分界符在前面將會
   //多出兩個短槓"--",而在所有資料結束時分界符的前後都多了兩個
   //"--"這是HTTP協議的規定.
   this.boundary="--"+this.contontType.substring(pos);
   this.lastBoundary=this.boundary+"--";//得到結束分界符
  }
  int state=this.NONE;//起始狀態為NONE
  //得到請求訊息的資料輸入流
  DataInputStream in=new DataInputStream(req.getInputStream());
  in.readFully(this.requestMessage);//根據長度,將訊息實體的內容讀入到位元組陣列中
  in.close();
  //從位元組陣列中得到表示實體的字串
  this.requestMessageStr=new String(this.requestMessage);
  //從字串中得到輸出緩衝流
  BufferedReader buffer=new BufferedReader(new StringReader(this.requestMessageStr));
  //暫存讀出的一行
  String readLine="";
  while(true){
   readLine=buffer.readLine();
   //如果到達結束分界符就跳出迴圈
   if(readLine==null||readLine.equalsIgnoreCase(this.lastBoundary))break;
   switch(state){
    case NONE:
     if(readLine.startsWith(this.boundary)){
      //如果讀到分界符,則表示下一行一個表頭
      state=this.DATA_HEADER;//狀態設為表示表頭資訊
     }
     break;
    case DATA_HEADER:
     pos=readLine.indexOf("filename=");
     //先判斷出這是一個文字表單域的頭資訊,還是一個上傳檔案的頭資訊
     if(pos==-1){
      //如果是文字表單域的頭資訊,解析出表單域的名稱
      pos=readLine.indexOf("name=");
      pos+="name=".length()+1;//1表示後面"的佔位
      readLine=readLine.substring(pos);
      //去掉最後面一個"符號後將表單域名稱放入fieldName
      fieldName=readLine.substring(0,readLine.length()-1);
      //狀態設為表示表單域的文字值
      state=this.FIELD_DATA;
     }else{
      //如果是檔案資料的頭,先儲存這一行,用於在位元組陣列中定位
      String temp=readLine;
      //先解析出檔名,1表示後面"的佔位
      pos=readLine.indexOf("filename=")+"filename=".length()+1;
      //去掉最後面一個"符號
      readLine=readLine.substring(pos,readLine.length()-1);
      //定位檔名
      pos=readLine.lastIndexOf("//");//轉義字元
      //檔名存入fileName
      fileName=readLine.substring(pos+1);
     
      //下面這一部分從位元組陣列中讀取檔案的資料
      pos=this.byteIndexOf(this.requestMessage,temp,0);//定位行
      //定位下一行,2表示一個回車和一個換行佔2個位元組
      this.requestMessage=this.subBytes(
       this.requestMessage,pos+temp.getBytes().length+2,
       this.requestMessage.length);
      //再讀一行資訊,是這一部分資料的Content-type
      readLine=buffer.readLine();
      //設定檔案輸入流,準備寫檔案
      File file=new File(this.fileName);
      DataOutputStream fileOut=new DataOutputStream(new FileOutputStream(file));
      /**
       *位元組陣列再往下一行,4表示兩個回車換行佔4個位元組。本行(指Content-type行)的
       *回車換行2個位元組,Content-type的下一行是回車換行表示的空行佔2個位元組
       *得到檔案資料的起始位置
       */
      this.requestMessage=this.subBytes(
       this.requestMessage,readLine.getBytes().length+4,
       this.requestMessage.length);
      //定位檔案資料的結尾
      pos=this.byteIndexOf(this.requestMessage,this.boundary,0);
      //獲取檔案資料,pos-2是因為在檔案資料和boundary之間有一回車換行表示的空行
      this.requestMessage=this.subBytes(this.requestMessage,0,pos-2);
      //將檔案資料存檔
      fileOut.write(this.requestMessage);
      //檔案長度存入fileLength
      this.fileLength=this.requestMessage.length;
      //狀態設為表示要讀到上傳檔案和二進位制資料
      state=this.FILE_DATA;
     }
     break;
    case FIELD_DATA:
     //讀出表域的值,存入fileValue
     this.fieldValue=buffer.readLine();
     formFields.put(this.fieldName,this.fieldValue);
     //狀態設為表示沒有特殊操作
     state=this.NONE;
     break;
    case FILE_DATA:
     //如果是檔案資料不進行分析直接讀過去
     while((!readLine.startsWith(this.boundary))&&
      (!readLine.startsWith(this.lastBoundary)))readLine=buffer.readLine();
     if(readLine.startsWith(this.boundary)) state=this.DATA_HEADER;
     break;
   }//end switch
  }//end while
  res.setContentType("text/html;charset=gb2312");
  PrintWriter out=res.getWriter();
  out.println("<html>");
  out.println("<head><title>檔案上傳結果</title></head>");
  out.println("<body>");
  out.println("<h>檔案上傳結果</h><hr>");
  out.println("ID:為"+formFields.get("fileId")+"的檔案:"+this.fileName+"已經上傳成功!");
  out.println("檔案長度為"+this.fileLength+"位元組");
  out.println("</body></html>"); 
 }
 /**
  *@param b 要搜尋的位元組陣列
  *@param s 要查詢的字串
  *@param start 搜尋的起始位置
  *@return 如果找到返回s的第一個位元組在位元組陣列中的下標,否則返回-1
  */
 private int byteIndexOf(byte[] b,String s,int start){
  return this.byteIndexOf(b,s.getBytes(),start);
 }
 /**
  *@param b 要搜尋的位元組陣列
  *@param s 要查詢的位元組陣列
  *@param start 搜尋的起始位置
  *@return 如果找到返回s的第一個位元組在位元組陣列中的下標,否則返回-1
  */
 private int byteIndexOf(byte[] b,byte[] s,int start){
  int i;
  if(s.length==0)return 0;
  int max=b.length-s.length;
  if(max<0)return -1;
  else if(start>max)return -1;
  else if(start<0) start=0;
  search:
   for(i=start;i<max;i++){
    if(b[i]==s[0]){
     //找到了s的第一個元素後比較剩餘部分是否相等
     int k=1;
     while(k<s.length){
      if(b[k+i]!=s[k]) continue search;
      k++;
     }
     return i;
    }
   }
   return -1;
 }
 /**
  *在一個位元組陣列中提取一個位元組陣列
  */
 private byte[] subBytes(byte[] b,int from,int end){
  byte[] result=new byte[end-from];
  System.arraycopy(b,from,result,0,end-from);
  return result;
 }
 /**
  *在一個位元組陣列中提取一個字串
  */
 private String subBytesToString(byte[] b,int from,int end){
  return new String(this.subBytes(b,from,end));
 }
}
2.3、index.html
<html>
<head><title>檔案上傳</title></head>
<body>
<form method="post" action="UploadFileServlet" enctype="multipart/form-data">
<p>ID:<input type="text" name="fileId" size="20"></p>
<p>File:<input type="file" name="fileData" size="20"></p>
<p><input type="submit" value="Upload" name="uploadFile"></p>
</form>
</body>
</html>
2.4、web.xml檔案
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
   version="2.5">

  <display-name>PassFile</display-name>
  <description>PassFile</description>
  <servlet>
   <servlet-name>UploadFileServlet</servlet-name>
   <servlet-class>shilei.UploadFileServlet</servlet-class>
  </servlet>
  <servlet-mapping>
   <servlet-name>UploadFileServlet</servlet-name>
    <url-pattern>/UploadFileServlet</url-pattern>
  </servlet-mapping>
</web-app>
說明:本web.xml的主要功能是配置Servlet。
完成上述步驟並建立相關的檔案後就可以把passFile資料夾直接部署在tomcat的webapps資料夾的下面,啟動tomcat後直接在瀏覽器中輸入http://localhost:8080/passFile就可以演示本例子了。當然不要忘了將.java檔案編譯成.class檔案。

 

相關推薦

利用Servlet檔案(在servlet處理MIME型別的post資料)

一、得到HTTP請求訊息的內容    下面是一個純JAVA的應用程式,它可以獲取表單提交時請求訊息的全部內容,該程式將請求訊息的內容顯示在螢幕上同時寫入程式執行路徑的一個名為request.txt的文字檔案中。     該程式涉及到JAVA的基本知識:Socket程式設計

Servlet檔案到指定路徑-Form提交

我們使用開源專案Commons FileUpload最常用ServletFileUpload上傳 專案結構: pom.xml 這裡就是用到了javax.servlet-api-3.0.1.jar、commons-fileupload-1.3.2.jar、common

servlet 檔案,下載檔案響應頭部設定

使用apache的開源jar編寫 編寫檔案上傳幫助類 /** * 檔案上傳幫助類 * * @author ajie * */ public class FileUploadUtil { /** * 建立資料夾

android通過servlet檔案到伺服器

伺服器端:部署在Tomcat上,直接在myEclipse上開發即可 package com; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.

ajax servlet檔案

== Java程式碼 == package com.wang; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.util.List; im

servlet檔案

servlet上傳檔案是,servlet封裝了一個ServletInputStream,以下是我寫的上傳檔案,對於我的電腦來說是伺服器,上傳就是講一個檔案放到我電腦的一個地方,以下程式碼,我實現了 1.對於任意檔案格式的上傳,包括txt,docx,png,MP3等上傳, 2

基於SSM框架實現利用FTP檔案至Linux遠端伺服器

基於SSM框架實現利用FTP上傳檔案至Linux遠端伺服器 摘要:JavaWEB開發通常採用SSM框架,在完成web開發時經常涉及到遠端訪問Linux伺服器實現檔案上傳。通常實現檔案上傳可通過InputStream和OutputStream實現檔案讀寫操作,但對於Linux伺服器需要

利用SpringMVC檔案的Demo

前言: 檔案的上傳功能也在網站中發揮著不可替代的作用,這裡我就來講講簡單利用SpringMVC實現檔案的上傳。 這裡我的配置是這樣的: idea+maven+tomcat9+jdk8 我也將該專案的D

PHP利用FTP檔案

簡單示例:  $ftpfile = $_FILES['userfile'];//檔案資訊 $conn = ftp_connect('127.0.0.1', 21, 90);//替換為自己的IP ftp_login($conn, 'user', 'password');//替

利用HTML5檔案並顯示在前端預覽,以圖片為例

由於專案中有上傳檔案的功能,所以這次單獨拿出來研究研究,我上網查了查,以前都是用iframe,但是自從HTML5出世之後,就可以利用H5的一些特性來上傳檔案了,啥也不說了,我上程式碼了 <!DOCTYPE html> <html lang

關於小程式&VUE檔案的java處理方法

簡述 相關文章有很多,在此記錄一下用起來個人一直在用的一種方式:使用servlet來獨立處理檔案上傳,獲取前端的檔案之後向CDN同步,最後返回檔案的最終相對路徑,由前端訪問CDN服務來展示圖片; 使用servlet的方便性在於可以跟專案實現零耦合,方便

ajax 檔案post檔案,ajax 提交 JSON 格式的資料

ajax簡介 前後臺做資料互動 前後端做資料互動的方式(三種):     (1)瀏覽器視窗輸入地址(get的方式)(2)form表單提交資料(3)ajax提交資料 特點 特點:  (1)非同步       非同步與同步的區別:同步是請求發過去,要等著迴應;非同步不

微信小程式wx.uploadFile(檔案)PHP伺服器獲取formData的資料

例如下面的程式碼是微信小程式上傳圖片的程式碼: wx.chooseImage({ success: function(res) { var tempFilePaths = res.tempFilePaths wx.uploadFile({

java檔案以流方式判斷型別

package com.omg.utils; /** * 檔案型別枚取 */ public enum FileType { /** * JEPG. */ JPEG("FFD8FF"), /** * PNG. */ PNG("89504E47

使用springmvc從頁面獲取資料,然後根據獲得的引數資訊進行修改,如果修改的資料含有不是基本資料型別的引數。比如的引數有Date型別資料時,需要我們進行引數型別轉換。

1.1 需求   在商品修改頁面可以修改商品的生產日期,並且根據業務需求自定義日期格式。 1.2 需求分析   由於日期資料有很多格式,所以springmvc沒辦法把字串轉換成日期型別。所以需要自定義引數繫結。前端控制器接收到請求後,找到註解形式的處理器介面卡,對RequestMapping標記的方法進

servlet組建檔案

表單上傳,普通欄位和檔案都可以接收,返回檔案上傳後的路徑 public static String upload(HttpServletRequest request, HttpServletResponse response) throws ServletExcept

vue專案如何利用base64圖片與檔案

前端在進行資原始檔上傳的時候,可以藉助HTML5中,fileReader物件進行圖片和檔案的上傳。利用該物件提供的一些屬性方法更加方便的獲取所上傳的檔案資訊。在vue專案中操作方法如下: 1)繫結input[type=‘file’]的change事件 <inpu

Servletzip檔案並解壓

根據需要寫一個上傳檔案的小程式,比較簡單就用serlvet寫。首先是要上傳檔案到伺服器,然後是解壓刪除zip包。同時寫一個監聽器,用於進度條展現上傳進度。 首先是頁面Upload.jsp:前臺需要上傳一個檔案和上傳檔名稱(對應伺服器的相應目錄),Ajax提交請求以實現進度

利用FTPClient檔案中文名字亂碼解決辦法

新增下面這一段: if (FTPReply.isPositiveCompletion(ftpClient.sendCommand( "OPTS UTF8", "ON"))) {// 開啟伺服器對UTF-8的支援,如果伺服器支援就用UTF-8編碼,否則就使用本地編碼(GBK)

Servlet學習:(三)Servlet3.0 檔案

一、注意事項 客戶端(瀏覽器) 表單的提交方法必須是post 必須有一個檔案上傳元件 <input type="file" name="file"/> 必須設定表單的enctype="multipart/form-data 伺服器 在Servelt上添