最近嘗試使用OKHttp替代Volley作為網(wǎng)絡(luò)請求框架,這肯定是要對OKHttp進(jìn)行重新封裝的,所有封裝完畢,就想對網(wǎng)絡(luò)請求功能進(jìn)行測試,基本的GET,POST驗(yàn)證通過了,但是在測試文件上傳的時(shí)候遇到了門檻,需要自己搭建后臺(tái)服務(wù)器來對此進(jìn)行支持,這里記錄一下這個(gè)過程,一方面對此做一次總結(jié),同時(shí)也為后面使用OkHTTP上傳文件監(jiān)聽進(jìn)度回調(diào)做準(zhǔn)備;還有就是希望能夠幫助到同樣有這個(gè)需求的朋友們。
一.SpringMVC服務(wù)器構(gòu)建
1.后臺(tái)服務(wù)器環(huán)境搭建
這邊我并不想花太多的篇幅來講解這一個(gè)過程(我能說我對后臺(tái)也不太了解嘛?這些步驟純碎百度),只是簡單的講一下思路.
首先需要做的就是配置JAVA開發(fā)環(huán)境,這個(gè)做Android開發(fā)的肯定提前都配置好了,沒什么好多說的。
其次需要搭建一個(gè)tomcat服務(wù)器,我們只需要從官網(wǎng)現(xiàn)在一個(gè)tomcat壓縮包,解壓,配置一下TOMCAT_HOME等環(huán)境變量就行,可參考(http://jingyan.baidu.com/article/8065f87fcc0f182330249841.html),這邊我用的是Tomcat8.0版本。
下載SpringMVC相關(guān)的庫,目前Spring Framework官網(wǎng)都是給出的通過Maven,Gradle等構(gòu)建工具使用Spring,我們沒必要再去搭Maven,Gradle(當(dāng)然,你有足夠的興趣跟經(jīng)歷,也可以嘗試一下,我比較懶,哈哈),我們可以手動(dòng)下載SpringFramework,我這邊使用的是spring-framework-4.3.6,下載地址:http://repo.spring.io/release/org/springframework/spring/4.3.6.RELEASE/,此處,我一共引入了如下jar

-
下載一個(gè)Eclipse,對其添加tomcat服務(wù)器設(shè)置,window->Preferences->Server->Runtime Environment,
按照下圖的步驟,后臺(tái)的開發(fā)環(huán)境基本就配置完成了。

- 啟動(dòng)tomcat服務(wù),打開瀏覽器,輸入http://localhost:8080如果看到tomcat首頁,說明tomcat服務(wù)器配置成功。
2.服務(wù)器代碼構(gòu)建
- 首先我們打開Eclipse,創(chuàng)建一個(gè)Dynamic Web Project,

- 這邊我們先看一下最終的項(xiàng)目結(jié)構(gòu)

-
下面看下對應(yīng)的代碼
FileModel.javapublic class FileModel { private MultipartFile file; public MultipartFile getFile() { return file; } public void setFile(MultipartFile file) { this.file = file; } }FileUploadController.java
@Controller public class FileUploadController { @Autowired ServletContext context; @RequestMapping(value = "/fileUploadPage", method = RequestMethod.GET) public ModelAndView fileUploadPage() { FileModel file = new FileModel(); ModelAndView modelAndView = new ModelAndView("fileUpload", "command", file); return modelAndView; } @RequestMapping(value="/fileUploadPage", method = RequestMethod.POST) public String fileUpload(@Validated FileModel file, BindingResult result, ModelMap model) throws IOException { if (result.hasErrors()) { System.out.println("validation errors"); return "fileUploadPage"; } else { System.out.println("Fetching file"); MultipartFile multipartFile = file.getFile(); String uploadPath = context.getContextPath() + File.separator + "temp" + File.separator; //Now do something with file... File saveFile = new File(uploadPath+file.getFile().getOriginalFilename()); System.out.println("File save path:" + saveFile.getAbsolutePath()); FileCopyUtils.copy(file.getFile().getBytes(), saveFile); String fileName = multipartFile.getOriginalFilename(); model.addAttribute("fileName", fileName); return "success"; } } }fileUpload.js
<%@ page contentType="text/html; charset=UTF-8"%> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> <html> <head> <title>Spring MVC上傳文件示例</title> </head> <body> <form:form method="POST" modelAttribute="fileUpload" enctype="multipart/form-data"> 請選擇一個(gè)文件上傳 : <input type="file" name="file" /> <input type="submit" value="提交上傳" /> </form:form> </body> </html>success.js
<%@ page contentType="text/html; charset=UTF-8"%> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> <html> <head> <title>Spring MVC上傳文件示例</title> </head> <body> <form:form method="POST" modelAttribute="fileUpload" enctype="multipart/form-data"> 請選擇一個(gè)文件上傳 : <input type="file" name="file" /> <input type="submit" value="提交上傳" /> </form:form> </body> </html>spring-servlet.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd "> <!-- 組件掃描:掃描標(biāo)記@Controller標(biāo)記的類,注入到spring容器中 --> <context:component-scan base-package="net.spring.controller" /> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/" /> <property name="suffix" value=".jsp" /> </bean> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" /> </beans>web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"> <display-name>HelloSpringMVC</display-name> <servlet> <servlet-name>spring</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- load-on-startup:表示啟動(dòng)容器時(shí)初始化該Servlet; --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>spring</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> </web-app> 以上代碼配置完成后,將我們創(chuàng)建的工程添加到tomcat容器中,然后啟動(dòng)tomcat,打開瀏覽器輸入http://localhost:8080/webapp/fileUploadPage,可以看到我們的fileUpload頁面。webapp根據(jù)自己創(chuàng)建的Dynamic Web Project時(shí)的設(shè)置而定,我創(chuàng)建Dynamic Web Project時(shí)設(shè)置了Context root為webapp,默認(rèn)為工程名字;fileUploadPage是Controller中RequestMapping注解中設(shè)置的內(nèi)容。頁面如下,至此,服務(wù)器端配置完全結(jié)束,我們也可以用一下,文件上傳成功會(huì)跳轉(zhuǎn)到success.jsp

二.Android使用okhttp實(shí)現(xiàn)文件上傳
android端如何使用okhttp進(jìn)行網(wǎng)絡(luò)請求,這邊不做介紹了,大家可以自定搜索了解一下,相信大多數(shù)人都是知道的,畢竟現(xiàn)在okhttp這么火。其實(shí)使用okhttp進(jìn)行文件上傳,也很簡單,跟不同的網(wǎng)絡(luò)請求用法沒有多大的區(qū)別,無非就是再RequestBody中指定了上傳的文件而已。在查看代碼之前,我想在這邊講一下不同post請求的區(qū)別。
-
普通post請求
我們都知道我們是無法在正常情況下看到post請求的請求參數(shù)的,post請求協(xié)議規(guī)定需要將post請求的請求參數(shù)放在http請求頭的下面,且兩者之間有一個(gè)空行隔開,普通的http post請求,請求參數(shù)都為基本數(shù)據(jù)類型,發(fā)送請求時(shí),將這些數(shù)據(jù)通過key=value鍵值對的方式拼接成字符串,我們可以通過抓包工具看一下

-
單一文件post請求
根據(jù)上面的,我們可以發(fā)現(xiàn),如果是上傳單一文件也一樣,只是http請求頭后面的不是鍵值對,而是我們上傳到文件的二進(jìn)制形式。okhttp中需要使用RequestBody.create(媒體類型,文件)方法,封裝請求body,請求格式如下,數(shù)據(jù)并沒有截取完全。

-
復(fù)合數(shù)據(jù)post請求
這邊我們需要考慮還有一種情況,復(fù)合數(shù)據(jù)的post請求,即post請求既有文件,又有鍵值對,甚至還有其他數(shù)據(jù)類型的時(shí)候,這個(gè)時(shí)候的post請求body就跟前兩者有所區(qū)別了,如下,可以發(fā)現(xiàn),它會(huì)將每一個(gè)請求數(shù)據(jù)進(jìn)行分離,并記錄每一個(gè)字段的信息,如key,value,內(nèi)容長度,數(shù)據(jù)流類型等
--fb12146e-52e3-4b7b-9345-6768dbcad759 Content-Disposition: form-data; name="file"; filename="xxx.jar" Content-Type: application/octet-stream Content-Length: 208700 [[二進(jìn)制文件數(shù)據(jù)]] --fb12146e-52e3-4b7b-9345-6768dbcad759 Content-Disposition: form-data; name="username" Content-Length: 13 name_for_test --fb12146e-52e3-4b7b-9345-6768dbcad759 Content-Disposition: form-data; name="password" Content-Length: 12 pwd_for_test --fb12146e-52e3-4b7b-9345-6768dbcad759--OKHttp中將這種情況封裝到了MultipartBody中,看了上面的格式,就不難理解MultipartBody中的addPart方法了
new MultipartBody.Builder() .addPart(Headers.of( "Content-Disposition", "form-data; name=\"file\"; filename=\"xxx.jar\"") , fileBody); //等價(jià)于下面這行代碼 new MultipartBody.Builder() .addFormDataPart("params","xxx.jar",fileBody);
講了上面的知識(shí),下面看一下Andorid端的上傳代碼,其實(shí)很簡單,file為我們需要上傳的文件,這邊不要忘記啟動(dòng)tomcat,同時(shí)修改url的值。
RequestBody filebody = RequestBody.create(MediaType.parse("application/octet-stream"), file);
RequestBody body = new MultipartBody.Builder()
.addFormDataPart("file", file.getName(), filebody)
.build();
Request request = new Request.Builder()
.url("http://192.168.1.106:8080/webapp/fileUploadPage")
.post(body)
.build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.e(TAG, "請求失敗:" + e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.e(TAG, "請求成功!");
}
});
發(fā)送請求后,我們可以在Logcat中看到“請求成功!”的字樣,說明請求成了,同時(shí)在Eclipse的console中可以看到服務(wù)器輸出

最后我們可以根據(jù)日志中顯示的路徑,去指定目錄下查看對應(yīng)的文件。
這篇文章就寫到這里,最后祝大家國慶快樂!_