android存储之网络存储和数据库存储

昨天说老师说了android的网络存储,对协议有了一个更深的理解。

数据上传到网络,尽管 b/s 和c/s的架构不一样,但是它们还是能上传数据到网络,因为都遵循协议的规范,c/s存储数据到网络,思想模仿浏览器发送数据服务器的请求头信息,在底层通过android提供的socket去链接网络,发送相应的数据,如果协议没拼接错误的话,能获得正确的相应码,并作出相应的操作。

总的来说,其实android网络存储重点还是对协议的拼接的,在此过程中必须静下心来才能做好拼接操作。

b/s通过访问服务器的网络段的请求头数据如下:·

		POST /ownUploadServer/doupload.action HTTP/1.1
		Host: localhost
		User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:35.0) Gecko/20100101 Firefox/35.0
		Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
		Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
		Accept-Encoding: gzip, deflate
		Referer: http://localhost/ownUploadServer/
		Cookie: JSESSIONID=F0EE9F4C17CB90FCADB60AC34B6AB871; CNZZDATA1000112112=1371504373-1430749960-%7C1430817053; 	
		Hm_lvt_b24307b87f33ce3e55789d58670dbbd5=1430809410; Hm_lvt_21a80e96f6b0bb699ad5f04db22194a4=1430809411; bdshare_firstime=1431935932462
		Connection: keep-alive
通过观察得知,请求头信息比较重要的是:
	POST /ownUploadServer/doupload.action HTTP/1.1 ,它包括了请求的方式,访问的资源地址,协议的版本。
	Host: localhost ip信息
 
  
	Connection: keep-alive 保持连接

传过去的参数:
-----------------------------28332323972849 
Content-Disposition: form-data; name="picdesc" 
12 
-----------------------------28332323972849 
Content-Disposition: form-data; name="size" 
23 
-----------------------------28332323972849 
Content-Disposition: form-data; name="ptype" 人æ 
-----------------------------28332323972849 
Content-Disposition: form-data; name="pic1"; filename="2.png" 
Content-Type: image/png

xxxx

-----------------------------28332323972849-- 
 
  

这里要注意的是协议的拼接非常的严格,一个地方错都会导致程序的崩溃的。

服务器端使用tomcat,客户端是addroid平台,下面实现数据存储:

客户端代码:上传的bean类

public class UploadFile implements Serializable{
	private static final long serialVersionUID = 3445579255260832749L;
	/**
	 *文件的内容
	 */
	private byte[] data;
	/**
	 * 可以通过这个流读数据
	 */
	private InputStream inStream;
	private File file;
	/**
	 * 文件名
	 */
	private String filename;
	/**
	 * 文件类型
	 */
	private String contentType="application/octet-stream";
	private String parameterName;
	
	public UploadFile(byte[] data, String filename, String contentType,
			String parameterName) {
		super();
		this.data = data;
		this.filename = filename;
		this.contentType = contentType;
		this.parameterName = parameterName;
	}

	public UploadFile(File file, String filename, String contentType,
			String parameterName) {
		super();
		this.file = file;
		this.filename = filename;
		this.contentType = contentType;
		this.parameterName = parameterName;
		try {
			this.inStream=new FileInputStream(this.file);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}

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

	public void setData(byte[] data) {
		this.data = data;
	}

	public InputStream getInStream() {
		return inStream;
	}

	public void setInStream(InputStream inStream) {
		this.inStream = inStream;
	}

	public File getFile() {
		return file;
	}

	public void setFile(File file) {
		this.file = file;
	}

	public String getFilename() {
		return filename;
	}

	public void setFilename(String filename) {
		this.filename = filename;
	}

	public String getContentType() {
		return contentType;
	}

	public void setContentType(String contentType) {
		this.contentType = contentType;
	}

	public String getParameterName() {
		return parameterName;
	}

	public void setParameterName(String parameterName) {
		this.parameterName = parameterName;
	}

}
上传帮助类:

package com.yc.utils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Map;
import com.yc.bean.UploadFile;;

public class WebUtil {
	/**
	 * 文件上传
	 * @param address
	 * @param params
	 * @param uploadFiles
	 * @throws IOException 
	 * @throws UnknownHostException 
	 */
	public String postFileToServer(String address,Map params,List uploadFiles) throws UnknownHostException, IOException{
		final String BOUNDARY="---------------------------1123240313494";
		final String SEPARATOR="--"+BOUNDARY;
		final String BREAKLINE="\r\n";
		final String ENDLINE=BREAKLINE+SEPARATOR+"--";
		
		long totalLength=0;
		long fileTotalLength=0;
		//计算uploadFiles部分的总长度
		if(uploadFiles!=null&&uploadFiles.size()>0){
			for(UploadFile uf:uploadFiles){
				StringBuffer sb=new StringBuffer();
				sb.append(SEPARATOR);
				sb.append(BREAKLINE);
				sb.append("Content-Disposition: form-data; name=\""+uf.getParameterName()+"\"; filename=\""+ uf.getFilename()+"\"");
				sb.append(BREAKLINE);
				sb.append("Content-Type: "+uf.getContentType());
				sb.append(BREAKLINE).append(BREAKLINE);
				//因为图片数据的后面也要加入一个\r\n
				sb.append(BREAKLINE);
				fileTotalLength+=sb.toString().getBytes().length;
				
				//计算这个uf的真实长度
				if(uf.getInStream()==null){
					fileTotalLength+=uf.getData().length;
				}else{
					fileTotalLength+=uf.getFile().length();
				}
			}
		}
		//计算文本参数部分的总长度
		StringBuffer textEntity=new StringBuffer();
		if(params!=null&¶ms.size()>0){
			for(Map.Entry entry:params.entrySet()){
				textEntity.append(SEPARATOR);
				textEntity.append(BREAKLINE);
				textEntity.append("Content-Disposition: form-data; name=\""+entry.getKey()+"\"");
				textEntity.append(BREAKLINE);
				textEntity.append(BREAKLINE);
				textEntity.append(entry.getValue());
				textEntity.append(BREAKLINE);
			}
		}
		
		//总长度
		totalLength=fileTotalLength+textEntity.toString().getBytes().length+ENDLINE.getBytes().length;
		
		//访问网络,发送协议
		URL url=new URL(address);
		//取出端口
		int port=url.getPort()==-1?80:url.getPort();
		//创建socket,以socket套接字访问服务器
		Socket s=new Socket(InetAddress.getByName(url.getHost()),port);
		//取出输入流
		OutputStream oos=s.getOutputStream();
		
		//拼接请求头
		String requestCommand="POST "+url.getPath()+" HTTP/1.1"+BREAKLINE;
		oos.write(requestCommand.getBytes());
		String hostword="Host: "+url.getHost()+BREAKLINE;
		oos.write(hostword.getBytes());
		String connectionword="Connection: keep-alive"+BREAKLINE;
		oos.write(connectionword.getBytes());
		String contenttypeword="Content-Type: multipart/form-data; boundary="+BOUNDARY+BREAKLINE;
		oos.write(contenttypeword.getBytes());
		String contentlength="Content-Length: "+totalLength+BREAKLINE;
		oos.write(contentlength.getBytes());
		//请求头与请求实体间的空行
		oos.write(BREAKLINE.getBytes());
		
		//发出文本实体
		oos.write(textEntity.toString().getBytes());
		
		//发出文件
		//计算出uploadFiles部分的总长度
		if(uploadFiles!=null&&uploadFiles.size()>0){
			for(UploadFile uf:uploadFiles){
				StringBuffer sb=new StringBuffer();
				sb.append(SEPARATOR);
				sb.append(BREAKLINE);
				sb.append("Content-Disposition: form-data; name=\""+uf.getParameterName()+"\"; filename=\""+ uf.getFilename()+"\"");
				sb.append(BREAKLINE);
				sb.append("Content-Type: "+uf.getContentType());
				sb.append(BREAKLINE).append(BREAKLINE);

				//以上是这个文件的文本信息部分
				oos.write(sb.toString().getBytes());
				
				if(uf.getInStream()!=null){
					//以流的形式先读,再用oos写
					byte[] buffer=new byte[1024];
					int length=-1;
					while((length=uf.getInStream().read(buffer,0,buffer.length))!=-1){
						oos.write(buffer,0,length);
					}
				}else{
					oos.write(uf.getData(),0,uf.getData().length);
				}
				oos.write(BREAKLINE.getBytes());
				oos.flush();
			}
		}
		//还有一个结束行
		oos.write(ENDLINE.getBytes());
		oos.flush();
		
		//接收服务器的回应
		InputStream iis=s.getInputStream();
		String result=new String();
		int len=-1;
		byte[] b=new byte[1024];
		while((len=iis.read(b,0,b.length))!=-1){
			result+=new String(b,0,len);
		}
		oos.close();
		iis.close();
		s.close();
		
		return result;
	}
}

然后在主界面调用的如下:这个要注意的是android在高版本的时候在上传文件到网络的时候,必须要开启新的线程而不能再主线程中操作。

我用的是handler类通过消息机制操作线程,也是可以通过AsyncTask操作。

线程代码如下:

btn4.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View arg0) {
				new Thread(new Runnable() {
					@Override
					public void run() {
						Mapparams=new HashMap();
						Person p =(Person)FilesUtils.getObjectFromFile("xiaofeng", MainActivity2.this);
						params.put("name", p.getName());
						params.put("age", p.getAge()+"");
						params.put("sex", p.getSex());
						ListuploadFiles=new ArrayList();
						File headFile=new File(p.getHeadpic());
						String filename=headFile.getName();
						uploadFiles.add(new UploadFile(headFile, filename, "image/jpeg", "headpic"));

						WebUtil wu=new WebUtil();
						try {
							String responseprotocol=wu.postFileToServer("http://211.69.255.66/ownUploadServer/doupload.action", params, uploadFiles);
							Message m=new Message();
							m.what=1;
							m.obj=responseprotocol;
							handler.sendMessage(m);
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				}).start();
Hannler的实例如下:

private Handler handler=new Handler(){
		public void handleMessage(android.os.Message msg) {
			switch(msg.what){
			case 1:
				String response=(String) msg.obj;
				if(response.indexOf("200")>0){
					Toast.makeText(MainActivity2.this, "上传云端成功", 3000).show();
				}
			}
		}
	};
值得一提的是:android在发送数据到服务器的时候,一定不能写localhost,因为localhost已经被android模拟器占用了,只能用ip地址,而且如果是真机测试的话,还要保证手机的网段和电脑的网段一致,并且关闭防火墙。才能测试成功。。


通过学习android的网络存储,对协议有更深的了解了,加油






你可能感兴趣的:(android存储之网络存储和数据库存储)