介紹兩種上傳方式,上傳到項目所部署的服務器,和上傳到一個單獨的文件服務器。
前言
文件上傳的前提:
表單在提交的時候 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.jar
和 commons-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.jar
和 commons-io.jar
這兩個包,還需要引入sun公司的jersey-client.jar
和jersey-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狀態碼。