欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android实现上传文件到服务器实例详解

程序员文章站 2024-03-02 15:51:10
本实例实现每隔5秒上传一次,通过服务器端获取手机上传过来的文件信息并做相应处理;采用android+struts2技术。 一、android端实现文件上传 1)、新...

本实例实现每隔5秒上传一次,通过服务器端获取手机上传过来的文件信息并做相应处理;采用android+struts2技术。

一、android端实现文件上传
1)、新建一个android项目命名为androidupload,目录结构如下:

Android实现上传文件到服务器实例详解

2)、新建formfile类,用来封装文件信息

package com.ljq.utils;

import java.io.file;
import java.io.fileinputstream;
import java.io.filenotfoundexception;
import java.io.inputstream;

/**
 * 上传文件
 */
public class formfile {
  /* 上传文件的数据 */
  private byte[] data;
  private inputstream instream;
  private file file;
  /* 文件名称 */
  private string filname;
  /* 请求参数名称*/
  private string parametername;
  /* 内容类型 */
  private string contenttype = "application/octet-stream";
  
  public formfile(string filname, byte[] data, string parametername, string contenttype) {
    this.data = data;
    this.filname = filname;
    this.parametername = parametername;
    if(contenttype!=null) this.contenttype = contenttype;
  }
  
  public formfile(string filname, file file, string parametername, string contenttype) {
    this.filname = filname;
    this.parametername = parametername;
    this.file = file;
    try {
      this.instream = new fileinputstream(file);
    } catch (filenotfoundexception e) {
      e.printstacktrace();
    }
    if(contenttype!=null) this.contenttype = contenttype;
  }
  
  public file getfile() {
    return file;
  }

  public inputstream getinstream() {
    return instream;
  }

  public byte[] getdata() {
    return data;
  }

  public string getfilname() {
    return filname;
  }

  public void setfilname(string filname) {
    this.filname = filname;
  }

  public string getparametername() {
    return parametername;
  }

  public void setparametername(string parametername) {
    this.parametername = parametername;
  }

  public string getcontenttype() {
    return contenttype;
  }

  public void setcontenttype(string contenttype) {
    this.contenttype = contenttype;
  }
  
}

3)、新建sockethttprequester类,封装上传文件到服务器代码

package com.ljq.utils;

import java.io.bufferedreader;
import java.io.inputstreamreader;
import java.io.outputstream;
import java.net.inetaddress;
import java.net.socket;
import java.net.url;
import java.util.map;

/**
 * 上传文件到服务器
 * 
 * @author administrator
 *
 */
public class sockethttprequester {
  /**
   * 直接通过http协议提交数据到服务器,实现如下面表单提交功能:
   *  <form method=post action="http://192.168.1.101:8083/upload/servlet/uploadservlet" enctype="multipart/form-data">
      <input type="text" name="name">
      <input type="text" name="id">
      <input type="file" name="imagefile"/>
      <input type="file" name="zip"/>
     </form>
   * @param path 上传路径(注:避免使用localhost或127.0.0.1这样的路径测试,因为它会指向手机模拟器,你可以使用http://www.iteye.cn或http://192.168.1.101:8083这样的路径测试)
   * @param params 请求参数 key为参数名,value为参数值
   * @param file 上传文件
   */
  public static boolean post(string path, map<string, string> params, formfile[] files) throws exception{   
    final string boundary = "---------------------------7da2137580612"; //数据分隔线
    final string endline = "--" + boundary + "--\r\n";//数据结束标志
    
    int filedatalength = 0;
    for(formfile uploadfile : files){//得到文件类型数据的总长度
      stringbuilder fileexplain = new stringbuilder();
       fileexplain.append("--");
       fileexplain.append(boundary);
       fileexplain.append("\r\n");
       fileexplain.append("content-disposition: form-data;name=\""+ uploadfile.getparametername()+"\";filename=\""+ uploadfile.getfilname() + "\"\r\n");
       fileexplain.append("content-type: "+ uploadfile.getcontenttype()+"\r\n\r\n");
       fileexplain.append("\r\n");
       filedatalength += fileexplain.length();
      if(uploadfile.getinstream()!=null){
        filedatalength += uploadfile.getfile().length();
       }else{
         filedatalength += uploadfile.getdata().length;
       }
    }
    stringbuilder textentity = new stringbuilder();
    for (map.entry<string, string> entry : params.entryset()) {//构造文本类型参数的实体数据
      textentity.append("--");
      textentity.append(boundary);
      textentity.append("\r\n");
      textentity.append("content-disposition: form-data; name=\""+ entry.getkey() + "\"\r\n\r\n");
      textentity.append(entry.getvalue());
      textentity.append("\r\n");
    }
    //计算传输给服务器的实体数据总长度
    int datalength = textentity.tostring().getbytes().length + filedatalength + endline.getbytes().length;
    
    url url = new url(path);
    int port = url.getport()==-1 ? 80 : url.getport();
    socket socket = new socket(inetaddress.getbyname(url.gethost()), port);      
    outputstream outstream = socket.getoutputstream();
    //下面完成http请求头的发送
    string requestmethod = "post "+ url.getpath()+" http/1.1\r\n";
    outstream.write(requestmethod.getbytes());
    string accept = "accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*\r\n";
    outstream.write(accept.getbytes());
    string language = "accept-language: zh-cn\r\n";
    outstream.write(language.getbytes());
    string contenttype = "content-type: multipart/form-data; boundary="+ boundary+ "\r\n";
    outstream.write(contenttype.getbytes());
    string contentlength = "content-length: "+ datalength + "\r\n";
    outstream.write(contentlength.getbytes());
    string alive = "connection: keep-alive\r\n";
    outstream.write(alive.getbytes());
    string host = "host: "+ url.gethost() +":"+ port +"\r\n";
    outstream.write(host.getbytes());
    //写完http请求头后根据http协议再写一个回车换行
    outstream.write("\r\n".getbytes());
    //把所有文本类型的实体数据发送出来
    outstream.write(textentity.tostring().getbytes());      
    //把所有文件类型的实体数据发送出来
    for(formfile uploadfile : files){
      stringbuilder fileentity = new stringbuilder();
       fileentity.append("--");
       fileentity.append(boundary);
       fileentity.append("\r\n");
       fileentity.append("content-disposition: form-data;name=\""+ uploadfile.getparametername()+"\";filename=\""+ uploadfile.getfilname() + "\"\r\n");
       fileentity.append("content-type: "+ uploadfile.getcontenttype()+"\r\n\r\n");
       outstream.write(fileentity.tostring().getbytes());
       if(uploadfile.getinstream()!=null){
         byte[] buffer = new byte[1024];
         int len = 0;
         while((len = uploadfile.getinstream().read(buffer, 0, 1024))!=-1){
           outstream.write(buffer, 0, len);
         }
         uploadfile.getinstream().close();
       }else{
         outstream.write(uploadfile.getdata(), 0, uploadfile.getdata().length);
       }
       outstream.write("\r\n".getbytes());
    }
    //下面发送数据结束标志,表示数据已经结束
    outstream.write(endline.getbytes());
    
    bufferedreader reader = new bufferedreader(new inputstreamreader(socket.getinputstream()));
    if(reader.readline().indexof("200")==-1){//读取web服务器返回的数据,判断请求码是否为200,如果不是200,代表请求失败
      return false;
    }
    outstream.flush();
    outstream.close();
    reader.close();
    socket.close();
    return true;
  }
  
  /**
   * 提交数据到服务器
   * @param path 上传路径(注:避免使用localhost或127.0.0.1这样的路径测试,因为它会指向手机模拟器,你可以使用http://www.itcast.cn或http://192.168.1.10:8080这样的路径测试)
   * @param params 请求参数 key为参数名,value为参数值
   * @param file 上传文件
   */
  public static boolean post(string path, map<string, string> params, formfile file) throws exception{
    return post(path, params, new formfile[]{file});
  }
}

4)、新建mainactivity类,实现每隔5秒上传一次

package com.ljq.activity;

import java.io.file;
import java.util.hashmap;
import java.util.map;

import android.app.activity;
import android.os.bundle;
import android.os.environment;
import android.os.handler;
import android.util.log;

import com.ljq.utils.formfile;
import com.ljq.utils.sockethttprequester;

public class mainactivity extends activity {
  private file file;
  private handler handler;
  private static final string tag="mainactivity";

  @override
  public void oncreate(bundle savedinstancestate) {
    super.oncreate(savedinstancestate);
    setcontentview(r.layout.main);
    log.i(tag, "oncreate");
    
    file = new file(environment.getexternalstoragedirectory(), "123.rmvb");
    log.i(tag, "照片文件是否存在:"+file);
    handler=new handler();
    handler.post(runnable);
  }
  
  runnable runnable=new runnable() {
  
    public void run() {
      log.i(tag, "runnable run");
      uploadfile(file);
      handler.postdelayed(runnable, 5000);
    }
  
  };
  
  /**
   * 上传图片到服务器
   * 
   * @param imagefile 包含路径
   */
  public void uploadfile(file imagefile) {
    log.i(tag, "upload start");
    try {
      string requesturl = "http://192.168.1.101:8083/upload/upload/execute.do";
      //请求普通信息
      map<string, string> params = new hashmap<string, string>();
      params.put("username", "张三");
      params.put("pwd", "zhangsan");
      params.put("age", "21");
      params.put("filename", imagefile.getname());
      //上传文件
      formfile formfile = new formfile(imagefile.getname(), imagefile, "image", "application/octet-stream");
      
      sockethttprequester.post(requesturl, params, formfile);
      log.i(tag, "upload success");
    } catch (exception e) {
      log.i(tag, "upload error");
      e.printstacktrace();
    }
    log.i(tag, "upload end");
  }
}

5)、修改清单文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
   package="com.ljq.activity"
   android:versioncode="1"
   android:versionname="1.0">
  <application android:icon="@drawable/icon" android:label="@string/app_name">
    <activity android:name=".mainactivity"
         android:label="@string/app_name">
      <intent-filter>
        <action android:name="android.intent.action.main" />
        <category android:name="android.intent.category.launcher" />
      </intent-filter>
    </activity>

  </application>
  <uses-sdk android:minsdkversion="4" />
  <uses-permission android:name="android.permission.internet" /> 

</manifest> 

启动模拟器,运行如下:

Android实现上传文件到服务器实例详解

二、服务器端用来获取android端上传过来的文件信息

1)、新建一个web项目命名为upload,目录结构如下

Android实现上传文件到服务器实例详解

注意:记得加入struts2 jar包,需加入的jar如下

Android实现上传文件到服务器实例详解

2)、新建action类,命名为uploadaction,内容如下

package com.ljq.action;

import java.io.file;
import java.io.fileinputstream;
import java.io.fileoutputstream;
import java.io.ioexception;

import javax.servlet.http.httpservletrequest;

import org.apache.struts2.servletactioncontext;

import com.opensymphony.xwork2.actionsupport;

/**
 * 获取android端上传过来的信息
 * 
 * @author administrator
 *
 */
@suppresswarnings("serial")
public class uploadaction extends actionsupport {
  // 上传文件域
  private file image;
  // 上传文件类型
  private string imagecontenttype;
  // 封装上传文件名
  private string imagefilename;
  // 接受依赖注入的属性
  private string savepath;

  @override
  public string execute() {
    httpservletrequest request=servletactioncontext.getrequest();
    fileoutputstream fos = null;
    fileinputstream fis = null;
    try {
      system.out.println("获取android端传过来的普通信息:");
      system.out.println("用户名:"+request.getparameter("username"));
      system.out.println("密码:"+request.getparameter("pwd"));
      system.out.println("年龄:"+request.getparameter("age"));
      system.out.println("文件名:"+request.getparameter("filename"));
      system.out.println("获取android端传过来的文件信息:");
      system.out.println("文件存放目录: "+getsavepath());
      system.out.println("文件名称: "+imagefilename);
      system.out.println("文件大小: "+image.length());
      system.out.println("文件类型: "+imagecontenttype);
      
      fos = new fileoutputstream(getsavepath() + "/" + getimagefilename());
      fis = new fileinputstream(getimage());
      byte[] buffer = new byte[1024];
      int len = 0;
      while ((len = fis.read(buffer)) != -1) {
        fos.write(buffer, 0, len);
      }
      system.out.println("文件上传成功");
    } catch (exception e) {
      system.out.println("文件上传失败");
      e.printstacktrace();
    } finally {
      close(fos, fis);
    }
    return success;
  }

  /**
   * 文件存放目录
   * 
   * @return
   */
  public string getsavepath() throws exception{
    return servletactioncontext.getservletcontext().getrealpath(savepath); 
  }

  public void setsavepath(string savepath) {
    this.savepath = savepath;
  }

  public file getimage() {
    return image;
  }

  public void setimage(file image) {
    this.image = image;
  }

  public string getimagecontenttype() {
    return imagecontenttype;
  }

  public void setimagecontenttype(string imagecontenttype) {
    this.imagecontenttype = imagecontenttype;
  }

  public string getimagefilename() {
    return imagefilename;
  }

  public void setimagefilename(string imagefilename) {
    this.imagefilename = imagefilename;
  }

  private void close(fileoutputstream fos, fileinputstream fis) {
    if (fis != null) {
      try {
        fis.close();
        fis=null;
      } catch (ioexception e) {
        system.out.println("fileinputstream关闭失败");
        e.printstacktrace();
      }
    }
    if (fos != null) {
      try {
        fos.close();
        fis=null;
      } catch (ioexception e) {
        system.out.println("fileoutputstream关闭失败");
        e.printstacktrace();
      }
    }
  }

}

3)、配置struts.xml

<?xml version="1.0" encoding="utf-8" ?>
<!doctype struts public
  "-//apache software foundation//dtd struts configuration 2.0//en"
  "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
  <!-- 该属性指定需要struts2处理的请求后缀,该属性的默认值是action,即所有匹配*.action的请求都由struts2处理。
    如果用户需要指定多个请求后缀,则多个后缀之间以英文逗号(,)隔开。 -->
  <constant name="struts.action.extension" value="do"/>
  <!-- 设置浏览器是否缓存静态内容,默认值为true(生产环境下使用),开发阶段最好关闭 -->
  <constant name="struts.serve.static.browsercache" value="false"/>
  <!-- 当struts的配置文件修改后,系统是否自动重新加载该文件,默认值为false(生产环境下使用),开发阶段最好打开 -->
  <constant name="struts.configuration.xml.reload" value="true"/>
  <!-- 开发模式下使用,这样可以打印出更详细的错误信息 -->
  <constant name="struts.devmode" value="true"/>
  <!-- 默认的视图主题 -->
  <constant name="struts.ui.theme" value="simple"/>
  <!--<constant name="struts.objectfactory" value="spring" />-->
  <!--解决乱码  -->
  <constant name="struts.i18n.encoding" value="utf-8"/>
  <!-- 指定允许上传的文件最大字节数。默认值是2097152(2m) -->
  <constant name="struts.multipart.maxsize" value="22097152"/>
  <!-- 设置上传文件的临时文件夹,默认使用javax.servlet.context.tempdir -->
  <constant name="struts.multipart.savedir " value="d:/tmp"/>
  
  <package name="upload" namespace="/upload" extends="struts-default">
    <action name="execute" class="com.ljq.action.uploadaction">
      <!-- 动态设置savepath的属性值 -->
      <param name="savepath">/image</param>
      <result name="success">/web-inf/page/message.jsp</result>
    </action>
  </package>
</struts>

4)、配置web.xml

<?xml version="1.0" encoding="utf-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
  xsi:schemalocation="http://java.sun.com/xml/ns/j2ee 
  http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

  <filter>
    <filter-name>struts2</filter-name>
    <filter-class>
      org.apache.struts2.dispatcher.ng.filter.strutsprepareandexecutefilter
    </filter-class>
  </filter>
  <filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  
  <filter>
    <filter-name>strutscleanup</filter-name>
    <filter-class>
      org.apache.struts2.dispatcher.actioncontextcleanup
    </filter-class>
  </filter>
  <filter-mapping>
    <filter-name>strutscleanup</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

运行结构如下:

获取android端传过来的普通信息:
用户名:张三
密码:zhangsan
年龄:21
文件名:123.rmvb
获取android端传过来的文件信息:
文件存放目录: d:\apache-tomcat-6.0.18\webapps\upload\image
文件名称: 123.rmvb
文件大小: 3962649
文件类型: application/octet-stream
文件上传成功

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。