Android实现上传文件到服务器实例详解
程序员文章站
2024-03-03 21:58:10
本实例实现每隔5秒上传一次,通过服务器端获取手机上传过来的文件信息并做相应处理;采用android+struts2技术。
一、android端实现文件上传
1)、新...
本实例实现每隔5秒上传一次,通过服务器端获取手机上传过来的文件信息并做相应处理;采用android+struts2技术。
一、android端实现文件上传
1)、新建一个android项目命名为androidupload,目录结构如下:
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端上传过来的文件信息
1)、新建一个web项目命名为upload,目录结构如下
注意:记得加入struts2 jar包,需加入的jar如下
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
文件上传成功
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。