SpringMVC服務(wù)+Android端OKHttp文件上傳

最近嘗試使用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)也不太了解嘛?這些步驟純碎百度),只是簡單的講一下思路.

  1. 首先需要做的就是配置JAVA開發(fā)環(huán)境,這個(gè)做Android開發(fā)的肯定提前都配置好了,沒什么好多說的。

  2. 其次需要搭建一個(gè)tomcat服務(wù)器,我們只需要從官網(wǎng)現(xiàn)在一個(gè)tomcat壓縮包,解壓,配置一下TOMCAT_HOME等環(huán)境變量就行,可參考(http://jingyan.baidu.com/article/8065f87fcc0f182330249841.html),這邊我用的是Tomcat8.0版本。

  3. 下載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

SpringMVC需要的jar.png
  1. 下載一個(gè)Eclipse,對其添加tomcat服務(wù)器設(shè)置,window->Preferences->Server->Runtime Environment,

    按照下圖的步驟,后臺(tái)的開發(fā)環(huán)境基本就配置完成了。

eclipse配置tomcat.png
  1. 啟動(dòng)tomcat服務(wù),打開瀏覽器,輸入http://localhost:8080如果看到tomcat首頁,說明tomcat服務(wù)器配置成功。
2.服務(wù)器代碼構(gòu)建
  1. 首先我們打開Eclipse,創(chuàng)建一個(gè)Dynamic Web Project,
創(chuàng)建動(dòng)態(tài)web項(xiàng)目.png
  1. 這邊我們先看一下最終的項(xiàng)目結(jié)構(gòu)
服務(wù)器工程目錄結(jié)構(gòu).png
  1. 下面看下對應(yīng)的代碼
    FileModel.java

    public 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>
    
  2. 以上代碼配置完成后,將我們創(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

服務(wù)器上傳文件頁面.png

二.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ū)別。

  1. 普通post請求

    我們都知道我們是無法在正常情況下看到post請求的請求參數(shù)的,post請求協(xié)議規(guī)定需要將post請求的請求參數(shù)放在http請求頭的下面,且兩者之間有一個(gè)空行隔開,普通的http post請求,請求參數(shù)都為基本數(shù)據(jù)類型,發(fā)送請求時(shí),將這些數(shù)據(jù)通過key=value鍵值對的方式拼接成字符串,我們可以通過抓包工具看一下

抓包_post_基本數(shù)據(jù).png
  1. 單一文件post請求

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

抓包_post_單一文件.png
  1. 復(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ù)器輸出

請求成功.png

最后我們可以根據(jù)日志中顯示的路徑,去指定目錄下查看對應(yīng)的文件。

這篇文章就寫到這里,最后祝大家國慶快樂!_

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容