文件上傳

https://blog.csdn.net/luckyboyguo/article/details/12513079
一般情況下提交表單元素form,默認的傳輸類型為application/x-www-form-urlencoded,后臺可以通過request.getParameter()獲取String類型的表單值。但是當iuput元素中有文件時,就不能通過這種方式傳遞。

1. 文件上傳的條件

  • 表單必須是post提交方式
  • 表單中必須有文件上傳項,文件上傳必須有name屬性和值
  • 表單中的enctype屬性必須設置為multipart/form-data
<form method="POST" enctype="multipart/form-data" action="fup.cgi">
  File to upload: <input type="file" name="upfile"><br/>
  Notes about the file: <input type="text" name="note"><br/>
  <br/>
  <input type="submit" value="Press"> to upload the file!
</form>
  • enctype=application/x-www-form-urlencoded 傳遞時,可以使用request.getParameter() 獲取
  • enctype=multipart/form-data傳遞時,不可以使用request.getParameter() 獲取

2. Servlet獲取上傳文件

form/data方式傳遞的請求報文的body為:

------WebKitFormBoundaryJAjpF3viDTBKnfAy
Content-Disposition: form-data; name="username"

loserwang
------WebKitFormBoundaryJAjpF3viDTBKnfAy
Content-Disposition: form-data; name="password"

ddd
------WebKitFormBoundaryJAjpF3viDTBKnfAy
Content-Disposition: form-data; name="nickname"

ddd
------WebKitFormBoundaryJAjpF3viDTBKnfAy
Content-Disposition: form-data; name="sex"

male
------WebKitFormBoundaryJAjpF3viDTBKnfAy
Content-Disposition: form-data; name="picture"; filename="loserwang.jpg"
Content-Type: image/jpeg

??????JFIF?????,?,?????C???
??
    
?
???????!????'#))'#&%,1?5,.;/%&6J7;ACFGF*4MRLDR?EFC???C???? ?? C-&-CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC???v???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????

理論上在Servlet處可以獲取request的body,分析結果,將上傳文件的二進制寫入本地,但是這樣過于繁瑣。最好的方式是使用第三方的jar包獲取數據,這方面有很多現成的成熟優秀的jar包,比如commons-fileupload.jar。

3. commons-fileupload

Commons是Apache開發源代碼組織的一個Java子項目,該項目主要涉及一些開發中常用的模塊,如文件上傳、命令行處理、數據庫連接池等等

The Commons FileUpload package makes it easy to add robust, high-performance, file upload capability to your servlets and web applications.

3.1 步驟

fileupload.png
  • (2).讀取文件
// 1.創建一個磁盤文件項工廠對象
DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
//2.創建一個核心解析類
 ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);
//3. 解析request請求,返回的是List集合,List集合中存放的是FileItem對象
 try {
            List<FileItem> list = servletFileUpload.parseRequest(request);
// 4.遍歷集合,獲得每個FileItem,判斷是表單項還是文件上傳項 
for(FileItem fileItem:list){
                //判斷是表單項還是文件上傳項
                if(fileItem.isFormField()){ 
                        //點單項處理
                  }else
                      //文件上傳項處理
                  }
 }

3.2 表單項處理

假設存在一個多選項name = hobby

//遍歷前的步驟
  Map<String, String> map = new HashMap<String, String>();
 List<String> hobbyList = new ArrayList<String>();
......
//讀取表單數據
    String name = fileItem.getFieldName();
     String value = fileItem.getString("UTF-8");
 //處理多選項。復選框為list
                    if("hobby" == name){
                        hobbyList.add(value);
                        String hobbyValue = hobbyList.toString().substring(1,hobbyList.size()-1);
                        map.put("hobby", hobbyValue);
                    }else{
                        //將結果存入map
                        map.put(name, value);
                    }

3.2 文件項處理

把上傳文件放到 /web/upload:

            //獲取文件名
                    String fileName = fileItem.getFieldName();
                    //獲取文件上傳的數據
                    InputStream is = fileItem.getInputStream();
                    //獲得文件路徑
                    String path = this.getServletContext().getRealPath("/upload");
                    String url = path + "\\" + fileName ;
                    //將輸入流對接到輸出流
                    OutputStream os = new FileOutputStream(url);
                    int len = 0;
                    byte[] b = new byte[1024];
                    while ((len = is.read(b)) != -1){
                        os.write(b, 0, len);
                    }
                    is.close();
                    os.close();

這種情況雖然可以滿足基本要求,但是如果上傳的文件名相同,新文件會覆蓋舊文件。為了每個文件不被覆蓋,給每一個文件一個唯一的文件名。可以通過UUID來實現

public class UploadUtils {
    /**
     * 產生隨機的文件名
     */
    public static String getUUIDFileName(String fileName){
        // 將文件名的前面部分進行截取: xx.jpg -> .jpg
        int idx = fileName.lastIndexOf(".");
        String extention = fileName.substring(0, idx);
        //JAVA的UUID能產生隨機的id
        String uuidFileName = UUID.randomUUID().toString().replace("-","_") + extention;
        return uuidFileName;
    }

}

(IDEA踩坑:IDEA不編譯空文件夾。/web/upload一開始沒有圖片,所以不會在out中產生upload文件夾,就會報錯找不到路徑。我們直接移動一個圖片到文件夾,選中Build-Rebuild Project 重新加載項目后,重啟服務器 或者update resources即可)。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。