Spring|文件上傳

介紹兩種上傳方式,上傳到項目所部署的服務器,和上傳到一個單獨的文件服務器。

前言

  文件上傳的前提:
    表單在提交的時候 method 必須爲 POST 請求,enctype 必須爲 multipart/form-data。
    原因:

     √ get 請求會把表單的參數用 URL 編碼在地址欄,但是大多數瀏覽器會限制地址欄的長度,所以 get 請求對於提交數據有大小要求(一般最大爲2K)。如果我們要上傳文件,肯定要選用沒有數據大小限制的 POST 請求。

     √ form的 enctype 屬性默認值爲 application/x-www-form-urlencoded 。指示表單表單中的所有 input 使用 URLencode 轉碼方法。這種數據編碼格式在傳輸非ascii字符時,效率非常低。

     √ 例如傳輸’人’這個字,UTF-8 字符集下它佔3個字節,爲 E5A5BD,使用URL編碼就是在每個字節前加一個%,變成%E5%A5%BD。變成字符串 ‘%E5%A5%BD’,九個ascii碼字符就佔九個字節,然後拼接在請求體中傳輸。

     √ 這時候我們發現要傳的’人’這個字原來只要3字節,傳輸的時候要傳9字節。傳輸小數據還好,數據大的話效率就太低了。

     √ 當 enctype 爲 multipart/form-data 時,對非ascii碼字符不再進行轉碼,是多個字節就傳多少個字節,並且在傳輸時每個表單項都有屬於自己的請求頭,後端代碼在解析的時候就會判斷出哪一個表單項是文件。application/x-www-form-urlencoded 和 multipart/form-data 的詳細區別分析可以看這篇博客


上傳到項目所部署的服務器

  環境搭建:
    1. 底層需要使用 apache 的 commons-fileupload.jarcommons-io.jar這兩個包來幫助我們完成文件上傳。

    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.3</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.4</version>
    </dependency>

    2. 把文件解析器對象加入到IOC容器中。文件解析器可以使用set方法注入,指定一些關於上傳文件的相關配置。比如最大上傳文件,默認編碼等等。注意:文件解析器對象的id必須爲multipartResolver。

    <!-- 配置文件解析器 -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="8388608"></property>
    </bean>

流程:
在這裏插入圖片描述
JSP代碼

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<body>
    <form action="user/uploadFile" method="post" enctype="multipart/form-data">
        <input type="file" name="upload_file1"/>
        <input type="submit" value="提交"/>
    </form>
</body>
</html>

Controller代碼
!注意如果不使用@RequestParam註解來指定請求參數名,則上傳文件input的name必須和controller方法中的形參名相同。

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/uploadFile")
    //定義一個MultipartFile類型的形參和上傳文件項綁定
    public String testFileUpload(HttpServletRequest req, @RequestParam("upload_file1") MultipartFile upload) throws IOException {
        //獲取文件上傳的基準位置
        String basePath = this.getServletContext().getRealPath("/upload");
        //按日期對文件夾進行管理
        String  datePath = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        //判斷上傳文件夾是否存在,不存在就創建一個
        File dir = new File(basePath + "/" + datePath);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        //指定保存文件名
        String uuid = UUID.randomUUID().toString().replace("-","");
        String fileName = uuid + "_" + upload.getOriginalFilename();
        //持久化
        upload.transferTo(new File(dir,fileName));
        return "success";
    }

上傳到一個單獨的文件服務器

  環境搭建:
    1. 除了上面用到的 commons-fileupload.jarcommons-io.jar這兩個包,還需要引入sun公司的jersey-client.jarjersey-server.jar這兩個包。

    <dependency>
      <groupId>com.sun.jersey</groupId>
      <artifactId>jersey-client</artifactId>
      <version>1.19.4</version>
    </dependency>
    <dependency>
      <groupId>org.glassfish.jersey.core</groupId>
      <artifactId>jersey-server</artifactId>
      <version>2.22.2</version>
    </dependency>

    2. 把文件解析器對象加入到IOC容器中。文件解析器可以使用set方法注入,指定一些關於上傳文件的相關配置。比如最大上傳文件,默認編碼等等。注意:文件解析器對象的id必須爲multipartResolver。

    <!-- 配置文件解析器 -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="8388608"></property>
    </bean>

    3. 創建兩個項目,分別將他們部署在不同的tomcat上。創建兩個tomcat的時候要注意兩個tomcat的HTTP port 和 JMX port端口的不能相同。
    4. tomcat-conf-web.xml 開啓可寫入。未開啓上傳會出現403狀態碼。

    <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>false</param-value>
        </init-param>
        <!-- 設置可寫 -->
        <init-param>
            <param-name>readonly</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

JSP代碼

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<body>
    <form action="user/uploadToFileServer" method="post" enctype="multipart/form-data">
        <input type="file" name="upload"/>
        <input type="submit" value="提交"/>
    </form>
</body>
</html>

Controller代碼

@Controller
@RequestMapping("/user")
public class UserController {

	public static final String FILESERVERURL = "http://localhost:8090/fileserver/upload/";
	
    @RequestMapping("/uploadToFileServer")
    public String testFileUploadToImgServer(MultipartFile upload) throws IOException {

        //指定保存文件名
        String uuid = UUID.randomUUID().toString().replace("-","");
        String fileName = uuid + "_" + upload.getOriginalFilename();
        //對文件名進行URL編碼,不然過會URL請求文件服務器會出現400狀態碼(解決中文文件名上傳問題)
        String encodeFileName = URLEncoder.encode(fileName, "UTF-8");
        //創建客戶端對象
        Client client = Client.create();
        //與遠程文件服務器資源連接
        WebResource resource = client.resource(FILESERVERURL + encodeFileName);
        //以字節方式寫入
        resource.put(upload.getBytes());
        return "success";
    }
}

注意:fileserver這個項目部署後要創建upload這個文件夾,不然上傳會出現409狀態碼。

發佈了46 篇原創文章 · 獲贊 1 · 訪問量 2505
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章