servlet formフォームからコミットされたファイルを取得

17524 ワード

知らず知らずのうちに、私はすでにスタック全体の道に向かっているような気がします.この2、3日、バックエンドで転送されたファイルデータを受信することを学びました.レベルが多すぎるので、servletを使ってデータを受信するつもりです.このブログは、アップロードされたファイルの取得方法、htmlプロトコルの内容からファイルの取得方法、Apache Commons FileUploadソースコードの読み取り方法の理解を浅く深く記録しています.
How
html form
<form action="../form_ajax" method="post" enctype="multipart/form-data">
       :<input type="text" name="username"/><br/>
            <br/>
         :<input type="file" name="myfile"/><br/>
    <input type="submit" value="submit"/><br/>
form>
  • formタグに属性enctype="multipart/form-data"
  • を追加
    servlet apiでファイル内容を取得する
    @MultipartConfig
    public class FileUpload1Servlet extends HttpServlet {
    
        private static Logger LOGGER = Logger.getLogger(FileUpload1Servlet.class);
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //    
            //    Servlet   @MultipartConfig         
            //  part      name    
            Part part = req.getPart("myfile");
            //Servlet3              ,           
            //     
            String fileName = part.getSubmittedFileName();
            //      
            InputStream inputStream = part.getInputStream();
    
            BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
            StringBuffer sb = new StringBuffer();
            String line = br.readLine();
            while(line != null){
                sb.append("
    "
    ).append(line); line = br.readLine(); } LOGGER.info("content:"+sb.toString()); PrintWriter printWriter = resp.getWriter(); printWriter.print(" , 。"); printWriter.flush(); printWriter.close(); } }

    enctype="multipart/form-data"属性を含むフォームからコミットされたデータは、サーブレットRequest.getParameterメソッドではパラメータを取得できません.次の手順でパラメータを取得します.
  • 1、サーブレット類に注釈を付ける@MultipartConfig
  • 2、サーブレットRequest.getPartメソッドを使用してPartオブジェクトを取得します.Partオブジェクトは対応するあなたのフォームの各inputです.

  • 欠点:
  • 渡されたフォームのvalueを取得したい場合は、PartはInputStream getInputStream()throws IOExceptionのみを提供してくれます.方法は、普通のテキストタイプに対して、私たちは自分で処理しなければなりません.

  • Apache Commons FileUploadでファイル内容を取得する
    まずApache Commons FileUpload依存を追加します.
    public class FileUpload2Servlet extends HttpServlet {
    
        private static Logger LOGGER = Logger.getLogger(FileUpload2Servlet.class);
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
            // Configure a repository (to ensure a secure temp location is used)
            ServletContext servletContext = this.getServletConfig().getServletContext();
            File repository = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
            factory.setRepository(repository);
    
            // Create a new file upload handler
            ServletFileUpload upload = new ServletFileUpload(factory);
    
            try {
                // Parse the request
                List items = upload.parseRequest(req);
    
                // Process the uploaded items
                Iterator iter = items.iterator();
                while (iter.hasNext()) {
                    FileItem item = iter.next();
    
                    if (item.isFormField()) {
                        processFormField(item);
                    } else {
                        processUploadedFile(item);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            PrintWriter printWriter = resp.getWriter();
            printWriter.print("   ,   。");
            printWriter.flush();
            printWriter.close();
        }
    
        private void processFormField(FileItem item) {
        }
    
        private void processUploadedFile(FileItem item) {
        }
    
    }

    上記のコードのように、取得したFileItemは対応するフォームのinputであり、FileItemによってストリームや値を取得できるなど、オリジナルのservlet apiよりも便利です.
    Apache Commons FileUpload非file属性文字化を取得
    FileItem.getStringは、フォームから渡された属性値を取得する方法であり、デフォルトではISO-8859-1で復号されます.このメソッドには、String getString(String encoding)throws UnsupportedEncodingExceptionがリロードされます.を選択して設定できます.
    に注意
    formフォームにenctype="multipart/form-data"(またはmultipart/mixedなど似たような)属性が追加されていない場合は、サーブレットRequest.getParameterを使用してパラメータを取得します.上記の2つの方法で処理することはできません.そうしないと、エラーが発生します.
    formフォームにenctype="multipart/form-data"(またはmultipart/mixedなど類似の)属性が追加されている場合は、サーブレットRequest.getParameterメソッドでは値が取得できないため、上記の2つの方法または類似の方法で要求パラメータを処理する必要があります.
    したがって、formフォームにenctype="multipart/form-data"(またはmultipart/mixedなど似たような)属性が追加されているかどうかについては、異なる処理があります.もちろん、これはもともと既知です.formフォームは私たちが自分で書いたからです.伝達されたhttpリクエストヘッダから判断することもできますが、次のブログでは、httpリクエストが送信したデータの中でどのように異なるのかを提示します.Apache Commons FileUploadライブラリは、次のような簡単な方法で判断できます.
    boolean isMultipart = ServletFileUpload.isMultipartContent(req);

    why
    socketは簡単なwebサーバを実現し、httpリクエスト情報を表示することができます.これは私が以前書いたブログで、httpリクエストが送信した内容を直感的に観察することができます.
    enctype="multipart/form-data":この属性はpostデータの場合、どのような形式でデータを符号化するかに影響します.このプロパティのデフォルト値はアプリケーション/x-www-form-urlencodedです.post,enctypeがこの2つの値である場合についてのみ議論する.
    enctype=”application/x-www-form-urlencoded”
    POST / HTTP/1.1
    Host: 127.0.0.1:8000
    Connection: keep-alive
    Content-Length: 44
    Cache-Control: max-age=0
    Origin: http://localhost:8080
    Upgrade-Insecure-Requests: 1
    User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
    Content-Type: application/x-www-form-urlencoded
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    Referer: http://localhost:8080/jquery/jquery_easy_ui_demo/index2.html?
    Accept-Encoding: gzip, deflate, br
    Accept-Language: zh-CN,zh;q=0.8,en;q=0.6
    Cookie: _ga=GA1.1.2113425928.1460981708
    
    username=%E5%BC%A0%E4%B8%89&myfile=test1.sql

    enctype=”multipart/form-data”
    POST / HTTP/1.1
    Host: 127.0.0.1:8000
    Connection: keep-alive
    Content-Length: 1043
    Cache-Control: max-age=0
    Origin: http://localhost:8080
    Upgrade-Insecure-Requests: 1
    User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
    Content-Type: multipart/form-data; boundary=----WebKitFormBoundary2vmXA3pgPdCoiZjv
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    Referer: http://localhost:8080/jquery/jquery_easy_ui_demo/index2.html?
    Accept-Encoding: gzip, deflate, br
    Accept-Language: zh-CN,zh;q=0.8,en;q=0.6
    Cookie: _ga=GA1.1.2113425928.1460981708
    
    
    ------WebKitFormBoundary2vmXA3pgPdCoiZjv
    Content-Disposition: form-data; name="username"
    
      
    ------WebKitFormBoundary2vmXA3pgPdCoiZjv
    Content-Disposition: form-data; name="myfile"; filename="test1.sql"
    Content-Type: application/octet-stream
    
    /*
     Navicat MySQL Data Transfer
    
     Source Server         : localhost
     Source Server Version : 50716
     Source Host           : localhost
     Source Database       : test1
    
     Target Server Version : 50716
     File Encoding         : utf-8
    
     Date: 11/18/2016 00:54:30 AM
    */
    
    SET NAMES utf8;
    SET FOREIGN_KEY_CHECKS = 0;
    
    -- ----------------------------
    --  Table structure for `obj1`
    -- ----------------------------
    DROP TABLE IF EXISTS `obj1`;
    CREATE TABLE `obj1` (
      `name` varchar(20) NOT NULL,
      `id` int(11) NOT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    --  Records of `obj1`
    -- ----------------------------
    BEGIN;
    INSERT INTO `obj1` VALUES ('  ', '1');
    COMMIT;
    
    SET FOREIGN_KEY_CHECKS = 1;
    
    ------WebKitFormBoundary2vmXA3pgPdCoiZjv--

    区別する
    ここでは、リクエストヘッダのContent-Typeプロパティとリクエストボディの2つに注意する必要があります.
  • リクエストヘッダのContent-Type属性は異なり,サーバ側はこの属性からリクエストパラメータをそのように処理すると判断できる.Content-Typeがmultipart/form-dataの場合、boundary=—-WebKitFormBoundary 2 vmXA 3 pgPdCoiZjvという値があります.これは、要求体の異なる属性を区別します.
  • enctype="application/x-www-form-urlencoded"の場合、リクエストボディにはurlencodedが2層にパッチされたクエリー文字列があります.enctype="multipart/form-data"の場合、フォームはboundaryによって異なる部分に分けられ、各部分にはヘッダーとデータが含まれています.上記の例のように.

  • 解析
    getリクエストまたはpostでenctype="アプリケーション/x-www-form-urlencoded"の場合、サーブレットRequest.getParameterメソッドをそのまま使用するとパラメータが得られますが、ここでは説明しません.
    postかつenctype="multipart/form-data"の場合、データはリクエスト体の中にあり、リクエスト体のフォーマットも知っています.このフォーマットに従って必要なデータを解析します.まず体力を要求する内容が得られ,サーブレットRequest.getInputStreamメソッドが返す入力ストリームは体力を要求する内容全体を含むことが分かった.
    上記のpostリクエスト体データを本当に解析するのか、それとも複雑なことなのか、責任ある(怠け者)態度で自分で書くことはありません.次の内容はApache Commons FileUploadソースコードを読むことの理解です.
    Apache Commons FileUpload理解
    コードが少し多いので、貼らないで、私の理解を書いてください.
  • 1、要求体をまずFileItemIteratorに解析し、このオブジェクトは反復器であり、すべてのFileItemStreamオブジェクトを取得することができ、FileItemStreamオブジェクトは伝達されたinputの内容に対応することができ、fieldName、ストリームなどのデータを取得することができる.
  • 2、FileItemIteratorを巡り、FileItemStreamによってFileItemが生成され、本当に生成されたのはFileItemのサブクラスDiskFileItemである.
  • 3、解析時にこのような2層の構造を用いて拡張を容易にするため、FileItemStreamオブジェクトは元のデータを表すことができ、それによってFileItemを生成することができ、現在生成されているのはDiskFileItemであり、以降データベースでキャッシュできるFileItemも知られていない.公式文書にはFileItemStreamを使ってデータを取得するというストリーミングAPI.
  • という紹介もあります
  • 4、メモリを節約するために、DiskFileItemはその内容の大きさに応じて、そのデータをファイルシステムにキャッシュするかどうかを決定します.
  • ➜  jquery pwd
    /Users/mabinbin/Library/Caches/IntelliJIdea2016.1/tomcat/Unnamed_blog_backend/work/Catalina/localhost/jquery
    ➜  jquery ls -lh
    total 249792
    -rw-r--r--  1 mabinbin  staff   122M  4 26 14:18 upload_08e39bf7_614a_4684_aee1_6d44138ff8f4_00000001.tmp

    リファレンス
    HTMLタグのenctypeプロパティsocketは、httpリクエスト情報FileUpload–Using FileUploadを表示する簡単なWebサーバを実現します.