当我们在进行客户端的api访问服务器端的时候,我们会选择封装请求参数,使用urlconnection进行服务器端的访问,但是urlconnection在涉及到图片上传的时候就比较复杂了,于是,Android推荐了Httpclient一个第三方的开源框架,但是此框架有点太大了,而我们要用的只是其中的一部分功能,所以本功能是将HttpUrlConnection进行了封装,客户端只需调用ApiClient.uploadFile(context, uploadUrl, null,formFiles);将上下文context,url地址,form表单,文件本地路径。具体实现方式见如下代码:
package org.hubu.yiyu.app;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.util.List;
import java.util.Map;
import org.hubu.yiyu.entity.FormFile;
import org.hubu.yiyu.utils.ACache;
import org.hubu.yiyu.utils.StringUtils;
import android.content.Context;
import android.util.Log;
/**
* 客户端网络接口,用于网络访问
*
* @author wk
*
*/
public class ApiClient {
private static final String TAG = "ApiClient";
/**
* 发送POST请求获得输入流
*
* @param context
* @param url
* @param params
* @return
* @throws Exception
*/
public static InputStream sendPOSTRequest(Context context, String url,
Map<String, String> params) throws Exception {
StringBuilder dataBuilder = new StringBuilder();
if (params != null && !params.isEmpty()) {
for (Map.Entry<String, String> entry : params.entrySet()) {
dataBuilder.append(entry.getKey()).append("=");
dataBuilder.append(entry.getValue());
dataBuilder.append("&");
}
dataBuilder.deleteCharAt(dataBuilder.length() - 1);
Log.i(TAG, dataBuilder.toString());
}
byte[] entity = dataBuilder.toString().getBytes();// 生成实体数据
HttpURLConnection conn = getPostConnection(context, url);
OutputStream outStream = conn.getOutputStream();
outStream.write(entity);
if (conn.getResponseCode() == 200) {
String cookies = getCookie(conn);
ACache.get(context).put("cookie", cookies,
StringUtils.ONE_MOUTH_SECONDS);// 保存获得的cookie对象
InputStream inStream = conn.getInputStream();
return inStream;
}
return null;
}
/**
* 获取POST连接对象
*
* @param context
* @param url
* @param entity
* @return
* @throws IOException
* @throws MalformedURLException
* @throws ProtocolException
*/
private static HttpURLConnection getPostConnection(Context context,
String url) throws IOException, MalformedURLException,
ProtocolException {
HttpURLConnection conn = (HttpURLConnection) new URL(url)
.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
conn.setRequestProperty("Connection", "keep-alive");
conn.setRequestProperty("Charset", "UTF-8");
conn.setRequestProperty("Content-Type",
"multipart/form-data;boundary=******");// 必须在Content-Type(表示POST请求的类型)
// 请求头中指定分界符中的任意字符串
String cookie = ACache.get(context).getAsString("cookie");
Log.i(TAG, "本地获得的cookie值" + cookie);
conn.setRequestProperty("Cookie", cookie);
return conn;
}
/**
* 根据创建的连接对象获得cookie值
*
* @param conn
* @return
*/
private static String getCookie(HttpURLConnection conn) {
String sessionId = "";
String cookieVal = "";
String key = null;
// 取cookie
for (int i = 1; (key = conn.getHeaderFieldKey(i)) != null; i++) {
if (key.equalsIgnoreCase("set-cookie")) {
cookieVal = conn.getHeaderField(i);
cookieVal = cookieVal.substring(0, cookieVal.indexOf(";"));
sessionId = sessionId + cookieVal + ";";
}
}
Log.i(TAG, "返回的cookie值" + sessionId);
return sessionId;
}
/**
* 发送get请求并获得返回的输入流
*
* @param context
* @param url
* @param params
* @return
* @throws Exception
*/
public static InputStream sendGETRequest(Context context, String url,
Map<String, String> params) throws Exception {
StringBuilder urlBuilder = new StringBuilder(url);
urlBuilder.append("?");
for (Map.Entry<String, String> entry : params.entrySet()) {
urlBuilder.append(entry.getKey()).append("=");
urlBuilder.append(entry.getValue());
urlBuilder.append("&");
}
urlBuilder.deleteCharAt(urlBuilder.length() - 1);
HttpURLConnection conn = (HttpURLConnection) new URL(
urlBuilder.toString()).openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
if (conn.getResponseCode() == 200) {
InputStream inStream = conn.getInputStream();
return inStream;
}
return null;
}
/**
* 发动post请求获得返回的输入流
*
* @param context 应用程序上下文
* @param url
* 请求的地址
* @param params
* 请求参数
* @param files
* 上传的文件
* @return
* @throws Exception
*/
public static InputStream uploadFile(Context context, String url,
Map<String, String> params, List<FormFile> files) throws Exception {
HttpURLConnection conn = getPostConnection(context, url);
// 定义数据写入流,准备上传文件
DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
String endLine = "\r\n";// 回车换行
String twoHyphens = "--"; // 两个连字符
String boundary = "******"; // 分界符的字符串
if (params != null) {
StringBuilder dataBuilder = new StringBuilder();
for (Map.Entry<String, String> entry : params.entrySet()) {//构造文本类型参数的实体数据
dataBuilder.append("--");
dataBuilder.append("******");
dataBuilder.append("\r\n");
dataBuilder.append("Content-Disposition: form-data; name=\""+ entry.getKey() + "\"\r\n\r\n");
dataBuilder.append(entry.getValue());
dataBuilder.append("\r\n");
}
byte[] entity = dataBuilder.toString().getBytes();// 生成实体数据
dos.write(entity);// 将请求参数进行上传
}
if (files != null) {
for (FormFile formFile : files) {
dos.writeBytes(twoHyphens + boundary + endLine);
// 设置与上传文件相关的信息
dos.writeBytes("Content-Disposition: form-data; name=\""
+ formFile.getParameterName() + "\"; filename=\""
+ formFile.getFilname() + "\"" + endLine);
dos.writeBytes(endLine);
FileInputStream fis = new FileInputStream(
formFile.getFilePath());
byte[] buffer = new byte[2048]; // 2k
int count = 0;
// 读取文件夹内容,并写入OutputStream对象
while ((count = fis.read(buffer)) != -1) {
dos.write(buffer, 0, count);
}
fis.close();// 关闭文件读入流
dos.writeBytes(endLine);
}
// 下面发送数据结束标志,表示数据已经结束
dos.writeBytes(twoHyphens + boundary + twoHyphens + endLine);
}else if(files==null){
dos.writeBytes(twoHyphens + boundary + endLine);
// 设置与上传文件相关的信息
dos.writeBytes("Content-Disposition: form-data; name=\""
+ "file" + "\"; filename=\""
+ "" + "\"" + endLine);
dos.writeBytes(endLine);
dos.writeBytes(endLine);
// 下面发送数据结束标志,表示数据已经结束
dos.writeBytes(twoHyphens + boundary + twoHyphens + endLine);
}
dos.flush();// 关闭输出流
if (conn.getResponseCode() == 200) {
Log.i(TAG, "文件上传成功");
String cookies = getCookie(conn);
ACache.get(context).put("cookie", cookies,
StringUtils.ONE_MOUTH_SECONDS);// 保存获得的cookie对象
// 读取服务端返回的信息并返回
InputStream inStream = conn.getInputStream();
return inStream;
}
return null;
}
}
通过使用A
piClient.uploadFile(context,uploadUrl, “文件本地路径”
, formFiles);将上下文context,url地址,form表单,文件本地路径传给方法uploadFile则可以将表单参数以及本地文件一同上传至服务器,当然,如果没有则可以直接传入null即可。做过web开发的同学肯定一眼就能看出其实这就是按照浏览器上传文件的做法进行模仿的;此处其中的formFiles是一个封装好的实体类如下所示:
package org.hubu.yiyu.entity;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
/**
* 要上传的文件
*
* @author wk
*
*/
public class FormFile {
// 上传文件的路径
private String filePath;
//文件名称
private String fileName = "file";
// 请求参数名称
private String parameterName;
// 内容类型
private String contentType = "application/octet-stream";
public FormFile(String filePath){
this.fileName = filePath.substring(filePath.lastIndexOf("/") + 1);
this.filePath = filePath;
}
public FormFile(String filePath,String parameterName){
this.fileName = filePath.substring(filePath.lastIndexOf("/") + 1);
this.filePath = filePath;
this.parameterName = parameterName;
}
public FormFile(String fileName,String filePath,String parameterName){
this.fileName = fileName;
this.filePath = filePath;
this.parameterName = parameterName;
}
public FormFile(String fileName, String filePath, String parameterName,
String contentType) {
this.filePath = filePath;
this.fileName = fileName;
this.parameterName = parameterName;
if (contentType != null)
this.contentType = contentType;
}
public String getFilePath() {
return filePath;
}
public String getFilname() {
return fileName;
}
public void setFilname(String fileName) {
this.fileName = fileName;
}
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;
}
}
根据uploadFile方法得到服务器返回的输入流,此时可以自定义一个解析输入流的工具类来解析为byte数组:
package org.hubu.yiyu.service;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
public class StreamTool {
/**
* 读取流中的数据
*
* @param inStream
* @return
* @throws Exception
*/
public static byte[] read(InputStream inStream) throws Exception {
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = inStream.read(buffer)) != -1) {
outStream.write(buffer, 0, len);
}
inStream.close();//对输入流进行关闭
return outStream.toByteArray();
}
}
至于接下来是要解析成json还是字符串或是xml,就是业务类要做的事情了。