美文网首页Java项目移动端Android开发经验谈
SpringMVC服务+Android端OKHttp文件上传

SpringMVC服务+Android端OKHttp文件上传

作者: junjunxx | 来源:发表于2017-10-02 23:16 被阅读198次

    最近尝试使用OKHttp替代Volley作为网络请求框架,这肯定是要对OKHttp进行重新封装的,所有封装完毕,就想对网络请求功能进行测试,基本的GET,POST验证通过了,但是在测试文件上传的时候遇到了门槛,需要自己搭建后台服务器来对此进行支持,这里记录一下这个过程,一方面对此做一次总结,同时也为后面使用OkHTTP上传文件监听进度回调做准备;还有就是希望能够帮助到同样有这个需求的朋友们。

    一.SpringMVC服务器构建

    1.后台服务器环境搭建

    这边我并不想花太多的篇幅来讲解这一个过程(我能说我对后台也不太了解嘛?这些步骤纯碎百度),只是简单的讲一下思路.

    1. 首先需要做的就是配置JAVA开发环境,这个做Android开发的肯定提前都配置好了,没什么好多说的。

    2. 其次需要搭建一个tomcat服务器,我们只需要从官网现在一个tomcat压缩包,解压,配置一下TOMCAT_HOME等环境变量就行,可参考(http://jingyan.baidu.com/article/8065f87fcc0f182330249841.html),这边我用的是Tomcat8.0版本。

    3. 下载SpringMVC相关的库,目前Spring Framework官网都是给出的通过Maven,Gradle等构建工具使用Spring,我们没必要再去搭Maven,Gradle(当然,你有足够的兴趣跟经历,也可以尝试一下,我比较懒,哈哈),我们可以手动下载SpringFramework,我这边使用的是spring-framework-4.3.6,下载地址:http://repo.spring.io/release/org/springframework/spring/4.3.6.RELEASE/,此处,我一共引入了如下jar

    SpringMVC需要的jar.png
    1. 下载一个Eclipse,对其添加tomcat服务器设置,window->Preferences->Server->Runtime Environment,

      按照下图的步骤,后台的开发环境基本就配置完成了。

    eclipse配置tomcat.png
    1. 启动tomcat服务,打开浏览器,输入http://localhost:8080如果看到tomcat首页,说明tomcat服务器配置成功。
    2.服务器代码构建
    1. 首先我们打开Eclipse,创建一个Dynamic Web Project,
    创建动态web项目.png
    1. 这边我们先看一下最终的项目结构
    服务器工程目录结构.png
    1. 下面看下对应的代码
      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">
            请选择一个文件上传 : 
            <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">
            请选择一个文件上传 : 
            <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 ">
      
          <!-- 组件扫描:扫描标记@Controller标记的类,注入到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:表示启动容器时初始化该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. 以上代码配置完成后,将我们创建的工程添加到tomcat容器中,然后启动tomcat,打开浏览器输入http://localhost:8080/webapp/fileUploadPage,可以看到我们的fileUpload页面。webapp根据自己创建的Dynamic Web Project时的设置而定,我创建Dynamic Web Project时设置了Context root为webapp,默认为工程名字;fileUploadPage是Controller中RequestMapping注解中设置的内容。页面如下,至此,服务器端配置完全结束,我们也可以用一下,文件上传成功会跳转到success.jsp

    服务器上传文件页面.png

    二.Android使用okhttp实现文件上传

    android端如何使用okhttp进行网络请求,这边不做介绍了,大家可以自定搜索了解一下,相信大多数人都是知道的,毕竟现在okhttp这么火。其实使用okhttp进行文件上传,也很简单,跟不同的网络请求用法没有多大的区别,无非就是再RequestBody中指定了上传的文件而已。在查看代码之前,我想在这边讲一下不同post请求的区别。

    1. 普通post请求

      我们都知道我们是无法在正常情况下看到post请求的请求参数的,post请求协议规定需要将post请求的请求参数放在http请求头的下面,且两者之间有一个空行隔开,普通的http post请求,请求参数都为基本数据类型,发送请求时,将这些数据通过key=value键值对的方式拼接成字符串,我们可以通过抓包工具看一下

    抓包_post_基本数据.png
    1. 单一文件post请求

      根据上面的,我们可以发现,如果是上传单一文件也一样,只是http请求头后面的不是键值对,而是我们上传到文件的二进制形式。okhttp中需要使用RequestBody.create(媒体类型,文件)方法,封装请求body,请求格式如下,数据并没有截取完全。

    抓包_post_单一文件.png
    1. 复合数据post请求

      这边我们需要考虑还有一种情况,复合数据的post请求,即post请求既有文件,又有键值对,甚至还有其他数据类型的时候,这个时候的post请求body就跟前两者有所区别了,如下,可以发现,它会将每一个请求数据进行分离,并记录每一个字段的信息,如key,value,内容长度,数据流类型等

      --fb12146e-52e3-4b7b-9345-6768dbcad759
      Content-Disposition: form-data; name="file"; filename="xxx.jar"
      Content-Type: application/octet-stream
      Content-Length: 208700
      
      [[二进制文件数据]]
      --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);
      //等价于下面这行代码
      new MultipartBody.Builder()
        .addFormDataPart("params","xxx.jar",fileBody);
      

    讲了上面的知识,下面看一下Andorid端的上传代码,其实很简单,file为我们需要上传的文件,这边不要忘记启动tomcat,同时修改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, "请求成功!");
                }
            });
    

    发送请求后,我们可以在Logcat中看到“请求成功!”的字样,说明请求成了,同时在Eclipse的console中可以看到服务器输出

    请求成功.png

    最后我们可以根据日志中显示的路径,去指定目录下查看对应的文件。

    这篇文章就写到这里,最后祝大家国庆快乐!_

    相关文章

      网友评论

        本文标题:SpringMVC服务+Android端OKHttp文件上传

        本文链接:https://www.haomeiwen.com/subject/yjqxyxtx.html