android上传图片(及普通参数)到服务器(j2ee后台服务器,ssh框架)

转载自android上传图片(及普通参数)到服务器(j2ee后台服务器,ssh框架)
最近项目中需要客户端往服务器传输图片,并且还需要附带一些普通参数,研究了几天,把结果记录下。

首先客户端可服务端进行通信一般都是有http请求来发送和接收数据,这里android中有两种HttpClient和HttpURLConnection,这两个都可以和后台服务器进行网络通信,但是如何选择哪个来进行文件传输呢?
谷歌官方是提倡我们使用HttpURLConnection来和服务器进行通信(这个是在android.jar中就有),HttpClient这个是org.apache.http.client.HttpClient下的一个工具类,根据网上的一些测试,得出的一些理论结果是使用HttpURLConnection来传输文件比HttpClient要快一些,在普通参数传输上都差不多。
既然谷歌推荐,所以我么这里就选择HttpURLConnection来实现传输文件。

android客户端
效果图非常简单
这里写图片描述
Android客户端逻辑:
1: 点击选图片—>打开系统的相册选择;
2:点击上传图片,把图片上传到服务器,然后显示进度,以及上传完成后显示服务器返回的json数据。
首先看看项目的结构
这里写图片描述
- 显示的界面在MainAcvtitvity中;
- ConfigParamters是http请求的公共参数配置;
- HttpUrlConn是http请求主要类;
- Uploadllinsener用来监听文件上传的进度,以及上传的状态(成功,失败,进度)。

这里主要是看看HttpUrlConn请求类:

public class HttpUrlConn {
//标签
private String TAG=HttpUrlConn;
//HttpURLConnection请求
private HttpURLConnection myhttpconnect;
//结束点
private String end =
;
//分割标记twoHyphens
private String twoHyphens = –;
//分割标记
private String boundary = *;
//数据输出管道
private DataOutputStream ds=null;
//文件上传监听
private UploadLinsener uploadlinsener;
//文件总大小
private double allFilesize=0;
//当前传输了多少
private double curr_ret=0;
/**
* HttpURLConnection连接服务器请求
* @param path :接口地址
* @param param1 :普通参数
* @param paramFiles:需要上传的文件参数
* @param config:连接公共属性配置
* @return
*/
public HttpURLConnection getHttpUrlConnInstances(String path,
HashMap paramString,
HashMap paramFiles,
ConfigParamters config){
try {
//这里可以放普通参数,(第一种方法)
// StringBuffer sb=new StringBuffer(path);
// if(null!=paramString&¶mString.size()>0){
// sb.append(?);
// for(Entry data:paramString.entrySet()){
// sb.append(data.getKey()+=+data.getValue());
// sb.append(&);
// }
// }
// path=sb.substring(0, sb.lastIndexOf(&));
URL url=new URL(path);
myhttpconnect=(HttpURLConnection)
url.openConnection();
/* 允许Input、Output,post中不使用Cache */
myhttpconnect.setDoInput(config.isDoInput());
myhttpconnect.setDoOutput(config.isDoOutput());
myhttpconnect.setUseCaches(config.isUseCaches());
/* 设置传送的method=POST */
myhttpconnect.
setRequestMethod(config.getUseMethod());
/设置属性 setRequestProperty /
myhttpconnect
.setRequestProperty(Connection, Keep-Alive);
myhttpconnect.setRequestProperty(Charset, UTF-8);
myhttpconnect.setRequestProperty(Content-Type, multipart/form-data;boundary= + boundary);
/* 设置DataOutputStream */
ds = new DataOutputStream(
myhttpconnect.getOutputStream());
/把普通参数写到服务器/
if(null!=paramString&¶mString.size()>0){
writeStringParam(ds, paramString);
}
/把文件参数写到服务器/
if(null!=paramFiles&¶mFiles.size()>0){
writeFileParam(ds, paramFiles);
}
//添加结尾标志
paramsEnd(ds);
if(myhttpconnect.getResponseCode()
==HttpURLConnection.HTTP_OK){
InputStream is =
myhttpconnect.getInputStream();
String successMsg=InputStremtoString(is);
//成功
if(uploadlinsener!=null){
uploadlinsener.uploadSucsess(successMsg);
}
}else{
uploadlinsener.uploadFail(错误,错误码
ResponseCode:+
myhttpconnect.getResponseCode());
}
ds.close();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
if(uploadlinsener!=null){
uploadlinsener.uploadFail(e.toString());
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
if(uploadlinsener!=null){
uploadlinsener.uploadFail(e.toString());
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
if(uploadlinsener!=null){
uploadlinsener.uploadFail(e.toString());
}
}
return myhttpconnect;
}
/**
* 把字节输入流转换成字符串
* @return
*/
private String InputStremtoString(InputStream is)throws Exception{
int ch;
StringBuffer b = new StringBuffer();
byte[] bt=new byte[1024];
while ((ch = is.read(bt)) != -1)
{
b.append(new String(bt, 0, ch, UTF-8));
}

    return b.toString();
}

/**
* 传普通参数(第二种方法)
* @param parm:参数
*/
private void writeStringParam(DataOutputStream ds,
HashMap params){
try{
Set keySet = params.keySet();
for (Iterator it =keySet.iterator();
it.hasNext();){
String name = it.next();
String value = params.get(name);
ds.writeBytes(twoHyphens + boundary + end);
ds.writeBytes(Content-Disposition: form-data; name= + name ++ end);
ds.writeBytes(end);
//URLEncoder.encode(value)
ds.writeBytes(new String(value.getBytes(),UTF-8)+ end);
}
}catch(Exception e){
e.printStackTrace();
}
}

/*
* 传输文件
* @param ds :数据传输通道
* @param params :参数
*/
private void writeFileParam(DataOutputStream ds,HashMap params){
try{
Set keySet = params.keySet();
getFilesSize(params);
for (Iterator it =keySet.iterator();
it.hasNext();){
String name = it.next();
File value = params.get(name);
ds.writeBytes(twoHyphens + boundary + end);
ds.writeBytes(Content-Disposition: form-data; name= + name + ; filename= + URLEncoder.encode(value.getName()) + +end);
ds.writeBytes(Content-Type: + getContentType(value) + end);
ds.writeBytes(end);
ds.write(getBytes(value));
ds.writeBytes(end);
}
}catch(Exception e){
e.printStackTrace();
}
}
/**
* 获取要传输文件总共大小
* @param params
*/
private void getFilesSize(HashMap params){
for(Entry data:params.entrySet()){
File f=data.getValue();
allFilesize+=f.length();
}
Log.i(TAG, AllFileSize:+allFilesize);
}
/**
* 获取文件的上传类型,图片格式为image/png,image/jpg等。非图片为application/octet-stream
* @param f 文件
* @return
* @throws Exception
*/
private String getContentType(File f) throws Exception{
return application/octet-stream;
}

/**
* 添加结尾数据
* @param ds:数据传输通道
* * @throws Exception
*/
private void paramsEnd( DataOutputStream ds) throws Exception {
ds.writeBytes(twoHyphens + boundary +
twoHyphens + end);
ds.writeBytes(end);
}

/**
 * 把文件转换成字节数组
 * @param f:文件
 * @return
 * @throws Exception
 */

private byte[] getBytes(File f) throws Exception{
FileInputStream in = new FileInputStream(f);
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int n;
while ((n = in.read(b)) != -1)
{
out.write(b, 0, n);
if(allFilesize>0){
curr_ret+=n;
double level=(curr_ret/allFilesize)*100;
Log.i(result, +level);
if(uploadlinsener!=null){
uploadlinsener.uploading(level);
}
}
}
in.close();
return out.toByteArray();
}

public void setUploadlinsener(UploadLinsener uploadlinsener) {
this.uploadlinsener = uploadlinsener;
}
}
上面的代码是HttpUrlConn的全部代码。
1: getHttpUrlConnInstances()获取并且请求连接服务器;
-方法中主要是获取连接,并且配置连接,然后拼接参数,发送到服务器,然后通过myhttpconnect.getInputStream()获取到服务器返回的数据。
2:InputStremtoString(InputStream)把字节流转换成String;
- 这里主要是为了处理服务器返回的数据。(这里注意编码)
3:writeStringParam(DataOutputStream,HashMap)这个方法主要是为了传输普通的参数;
- 把普通参数装入HashMap中然后循环写出数据,这里的数据是需要拼接的,因为我们提交数据是模拟from表单提交。
4:writeFileParam(DataOutputStream,HashMap)这个方法只要是用来传输文件参数;
- 把需要传输的文件都装在HashMap中,循环遍历hashmap中的文件,一一写到服务器。(在这个方法中获取了所有文件的总大小,用于计算当前的传输进度,还有这里的name和服务器的要一样。)
5:getFilesSize(HashMap)获取文件的总大小;
6:getContentType(File f)获取文件的上传类型,图片格式为image/png,image/jpg等。非图片为application/octet-stream;
7:paramsEnd(DataOutputStream)添加结尾数据;
8:getBytes(File) 把文件转换成字节数组;
9:setUploadlinsener(UploadLinsener)设置传输监听;

J2ee服务端(ssh搭建的环境)
这里我们使用struts2的一个组件来实现配合客户端文件上传。
这里写图片描述
用struts,spring,hibernate三大框架搭建好的项目,这里项目搭建过程就不演示了。
这里的核心代码在FileUploadAction中:

public class FileUploadAction extends ActionSupport{
public String phoneinfo=NXJ570;
public void uploadfielandparam() throws Exception{
System.out.println(upload);
HttpServletRequest request=
ServletActionContext.getRequest();
System.out.println(request.getContentType()); System.out.println(request.getCharacterEncoding());
System.out.println(request.getContentLength());
//临时文件夹,在tomcat项目下的temp
String temp = ServletActionContext
.getServletContext()
.getRealPath()+ \temp;
System.out.println(temp);
//上传文件存放地方
String basepath=ServletActionContext
.getServletContext()
.getRealPath()+\myfile;
//获取Response
HttpServletResponse resp=
ServletActionContext.getResponse();

    DiskFileItemFactory factory =
                     new DiskFileItemFactory();
    //单个文件缓存最大值
    factory.setSizeThreshold(10 * 1024 * 1024);
    // 缓冲区
    factory.setRepository(new File(temp));
    //文件上传组件(关键)
    ServletFileUpload upload1=
            new ServletFileUpload(factory);
    upload1.setFileSizeMax(10000000);
    upload1.setSizeMax(480000000);
    upload1.setHeaderEncoding(UTF-8); 
    // 设置一旦文件大小超过getSizeThreshold()
    //的值时数据存放在硬盘的目录
    // 开始读取上传信息
    int index = 0;
    List fileItems= null;
    try
    {
        fileItems=upload1.parseRequest(request);
        System.out.println(list= + fileItems);

    }
    catch (Exception e)
    {
        e.printStackTrace();
    }
    Iterator iter = fileItems.iterator();
    // 依次处理每个上传的文件
    while (iter.hasNext())
    {
        FileItem item = (FileItem) iter.next();

        // 忽略其他不是文件域的所有表单信息
        if (!item.isFormField())
        {
            String name = item.getName();
            // 获取上传文件名,包括路径
            name = name.substring(
                        name.lastIndexOf(\) + 1);
            // 从全路径中提取文件名
            long size = item.getSize();
            if ((name == null 
                || name.equals()) && size == 0)
            continue;
            int point = name.indexOf(.);
            name = (new Date()).getTime()
                    + name.substring(point, name.length());
            System.out.println(fileName=+name);
            index++;
            File fNew = new File(basepath, name);
            try
            {
                item.write(fNew);
            }
            catch (Exception e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        else
        // 取出不是文件域的所有表单信息
        {
            //如果包含中文应写为:(转为UTF-8编码)
            String key=item.getFieldName();
            String fieldvalue =
                    .getBytes(),UTF-8);//UTF-8    
            System.out  
                     .println(
                        params:+key+=+fieldvalue);
        }
    }

    //把对象转换成json
    Gson gson = new Gson();
    myobj obj1=new myobj(0, seccessed,
                                 服务器已经接收到文件);
    String json = gson.toJson(obj1);
    System.out.println(json);
    //设置格式(必须设置,否则客户端接收到的json中文乱码)
    resp.setContentType(text/html; charset=utf-8);
    PrintWriter out = resp.getWriter();
    out.println(json);

    out.flush();
}
//实体对象
class myobj{
    private String retcode;
    private String retmessage;
    private String retdata;
    public myobj(String retcode, 
            String retmessage, String retdata) {
        super();
        this.retcode = retcode;
        this.retmessage = retmessage;
        this.retdata = retdata;
    }
    public String getRetcode() {
        return retcode;
    }
    public void setRetcode(String retcode) {
        this.retcode = retcode;
    }
    public String getRetmessage() {
        return retmessage;
    }
    public void setRetmessage(String retmessage) {
        this.retmessage = retmessage;
    }
    public String getRetdata() {
        return retdata;
    }
    public void setRetdata(String retdata) {
        this.retdata = retdata;
    }   
}

这个类是核心业务类,当客户端发送请求是进入到这个方法中,并且获取到参数数据。
在服务端有两种方式能后获取到android的普通参数,
一是通过HttpServletRequest的getParameter(arg0)方法来获取;
二是从提交的表单中获取:

//获取key
String key=item.getFieldName();
//获取vaule
String fieldvalue =new 
        String(item.getString().getBytes(),UTF-8);

经过测试传输速度的确挺快的5MB的图片几秒钟就能传输完成,注意这里如果是在android客户端模拟机中调试程序,那里的请求地址中的ip应该为10.0.0.2:8080…..否则找不到服务器,如果是真机上测试可以直接发布到你电脑的tomcat中,然后把ip改成你点击的ip就可以了(这里电脑和android手机需要连接到同一个网络wifi,也就是内网,当然也可以拿到公司的服务器上测试)。
项目测试通过,效果也挺好的,不过这里还有一个问题没解决,就是通过from表单提交上来的普通参数如果是中文这里好像还是会乱码。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值