android上传大文件到服务器客户端和服务器端代码

使用一般的上传方法一般上传不能超过2m的文件,也非常容易中断和出错,于是本人打算使用xutils框架进行文件上传开发,话不多说直接上源码

首先要下载这个类库的jar包,地址:https://github.com/wyouflf/xUtils

android端代码:

添加权限

 <uses-permission android:name="android.permission.INTERNET" />
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />


package com.example.download_test;

import java.io.File;

import com.lidroid.xutils.HttpUtils;
import com.lidroid.xutils.exception.HttpException;
import com.lidroid.xutils.http.RequestParams;
import com.lidroid.xutils.http.ResponseInfo;
import com.lidroid.xutils.http.callback.RequestCallBack;
import com.lidroid.xutils.http.client.HttpRequest;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;

public class UploadActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_upload);
		
		new Thread(){
			public void run() {
				System.out.println("上传线程启动");
				RequestParams params = new RequestParams();
				params.addHeader("head", "1");
				params.addQueryStringParameter("head", "2");

				// 只包含字符串参数时默认使用BodyParamsEntity,
				// 类似于UrlEncodedFormEntity("application/x-www-form-urlencoded")。
				params.addBodyParameter("222", "22");//相当于与文件同时发给服务器的字符串对象,在servlet中可以通过遍历FileItem的list得到

				// 加入文件参数后默认使用MultipartEntity("multipart/form-data"),
				// 如需"multipart/related",xUtils中提供的MultipartEntity支持设置subType为"related"。
				// 使用params.setBodyEntity(httpEntity)可设置更多类型的HttpEntity(如:
				// MultipartEntity,BodyParamsEntity,FileUploadEntity,InputStreamUploadEntity,StringEntity)。
				// 例如发送json参数:params.setBodyEntity(new StringEntity(jsonStr,charset));
				params.addBodyParameter("file", new File("/storage/emulated/0/Trinea/MeiLiShuo-7.apk"));//设置要上传文件的本地路径,<span style="font-family: Arial, Helvetica, sans-serif;">第一个参数就是html中<input>标签中的name属性,是与服务器传输文件字节流以外的文本信息的重要渠道,在servlet中这样获得fileitem.getFieldName();</span>

				HttpUtils http = new HttpUtils();
				http.send(HttpRequest.HttpMethod.POST,
				    "http://192.168.1.112:8080/auto_serve/servlet/UploadImage",//设置要上传到的url
				    params,
				    new RequestCallBack<String>() {

						@Override
						public void onCancelled() {
							// TODO Auto-generated method stub
							super.onCancelled();
							System.out.println("上传终止");
						}

						@Override
						/**
						 * 获取上传进度的方法
						 */
						public void onLoading(long total, long current,//这个方法大约一秒会执行一次
								boolean isUploading) {
							// TODO Auto-generated method stub
							
							System.out.println("目前上传大小"+current+"总大小"+total);
							super.onLoading(total, current, isUploading);
						}

						@Override
						public void onFailure(HttpException arg0, String arg1) {
							// TODO Auto-generated method stub
							System.out.println("android上传失败");
						}

						@Override
						public void onSuccess(ResponseInfo<String> arg0) {
							// TODO Auto-generated method stub
							System.out.println("android上传成功");
						}

				      

				     
				});
				
			};
		}.start();
	}

	
}

如果想要添加一个带进度条的对话框,可以在onLoading方法中更新进度条进度,如下

@Override  
                     /** 
                      * 获取上传进度的方法 
                      */  
                     public void onLoading(long total, long current,//这个方法大约一秒会执行一次  
                             boolean isUploading) {  
                         // TODO Auto-generated method stub  
                           
                         System.out.println("目前上传大小"+current+"总大小"+total); 
                         int process = 0;
                        try {
                            process = (int) (current/(total/100));
                        } catch (Exception e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                         Message message = Message.obtain();
                         message.arg1 = process;
                         handler.sendMessage(message);
                         
                     }  
 
class upLoadHandler extends Handler{
        @Override
        public void handleMessage(Message msg) {
            // TODO Auto-generated method stub
            if(msg.arg1>0)
            mReadProcessDia.setProgress(msg.arg1);
        }
    }

//release是发布按钮Button
release.setOnClickListener(new OnClickListener() {
								
								@Override
								public void onClick(View v) {
									// TODO Auto-generated method stub
								mReadProcessDia=new ProgressDialog(IndexActivity.this);  
							        mReadProcessDia.setProgress(0);  
							        mReadProcessDia.setIndeterminate(false);  
							        mReadProcessDia.setCancelable(false);//设置进度条对话框是否可以被点没,如果为true,相当于后台下载,完毕后不受影响
							        mReadProcessDia.setTitle("上传进度");  
							        mReadProcessDia.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);  
							        mReadProcessDia.setMax(100);  
							        mReadProcessDia.show();  
							        new Thread(runnable).start();
								}
							});


如果要从相册选择一张图片,并且显示在imageView上,有如下代码

//commentPic是个添加图片的按钮
commentPic.setOnClickListener(new OnClickListener() {//点击一下打开相册,从相册获取一个图片的uri
					  
						@Override
						public void onClick(View v) {
							// TODO Auto-generated method stub
							Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);  
							intent.setType("image/*");    //这个参数是确定要选择的内容为图片,
							intent.putExtra("return-data", true);  //是否要返回值。 一般都要。我第一次忘加了,总是取得空值,囧!
							Activity activity = (Activity) context;//获得一个上下文
							activity.startActivityForResult(intent, 2);

						}
					});
					  
					  commentView = (ImageView) popupView.findViewById(R.id.commentView);

//在Activity的onActivityResult方法接受相册选取结果uri
@Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        // TODO Auto-generated method stub
        super.onActivityResult(requestCode, resultCode, data);   
        System.out.println("数据传回了");
        if (resultCode == -1) {  
                    System.out.println("requestCode"+requestCode);  
                 if (requestCode == 2) {  //之前intent设置的自定义码是2
                           Uri uri = data.getData();  //接受相册返回的uri
                          ImageView imageView = TuijianAdapter.commentView;//获取要显示图片的imageView
                           System.out.println("Uri是"+uri.getPath());  
                          System.out.println("真实路径是"+ getRealPathFromURI(this,uri));//从一个uri获取file指针的方法,获取file指针是为了上传
                           ContentResolver cr = getContentResolver();  
                          file = new File(getRealPathFromURI(this,uri));//从一个uri获取file指针的方法
                          System.out.println("图像大小是"+file.length());//检测图像是否加载成功,并判断是否超大
                           try {  
                               Bitmap bmp = BitmapFactory.decodeStream(cr.openInputStream(uri));//把一个uri转换成字节流输入,并显示到imageView
                               imageView.setImageBitmap(bmp);
                               imageView.setVisibility(View.VISIBLE);
                              
                           } catch (FileNotFoundException e) {  
                            // TODO Auto-generated catch block  
                            e.printStackTrace();  
                           }  
                          
                } else {
                    System.out.println("修建失败");
                }
     } else {
        System.out.println("选择失败");
    }






tomcat服务器servlet端代码,需要导入apache的commons-io和commons-lang包

package com.situ.servlet;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.lang.RandomStringUtils;


public class UploadImage extends HttpServlet {

	/**
	 * The doGet method of the servlet. <br>
	 *
	 * This method is called when a form has its tag value method equals to get.
	 * 
	 * @param request the request send by the client to the server
	 * @param response the response send by the server to the client
	 * @throws ServletException if an error occurred
	 * @throws IOException if an error occurred
	 */
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		response.setContentType("text/html");
		PrintWriter out = response.getWriter();
		out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
		out.println("<HTML>");
		out.println("  <HEAD><TITLE>A Servlet</TITLE></HEAD>");
		out.println("  <BODY>");
		out.print("    This is ");
		out.print(this.getClass());
		out.println(", using the GET method");
		out.println("  </BODY>");
		out.println("</HTML>");
		out.flush();
		out.close();
	}

	/**
	 * The doPost method of the servlet. <br>
	 *
	 * This method is called when a form has its tag value method equals to post.
	 * 
	 * @param request the request send by the client to the server
	 * @param response the response send by the server to the client
	 * @throws ServletException if an error occurred
	 * @throws IOException if an error occurred
	 */
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		System.out.println("收到上传请求");
		  //获得磁盘文件条目工厂    
        DiskFileItemFactory factory = new DiskFileItemFactory();    
        //获取文件缓存文件夹的路径    
        String tempPath = request.getRealPath("/temp");    
        System.out.println("path为"+tempPath); //C:\apache-tomcat-7.0.61/webapps/auto_serve/upload
        String path2 = request.getContextPath();
        System.out.println("contextPath为"+path2);//:/auto_serve
        //如果没以下两行设置的话,上传大的 文件 会占用 很多内存,    
        //设置暂时存放的 存储室 , 这个存储室,可以和 最终存储文件 的目录不同    
        /**  
         * 原理 它是先存到 暂时存储室,然后在真正写到 对应目录的硬盘上,   
         * 按理来说 当上传一个文件时,其实是上传了两份,第一个是以 .tem 格式的   
         * 然后再将其真正写到 对应目录的硬盘上  
         */    
        File tempFolder = new File(tempPath);
        if(tempFolder.exists()==false){
        	tempFolder.mkdirs();
        }
        //设置缓存文件夹
        factory.setRepository(tempFolder);    
        //设置 缓存的大小,当上传文件的容量超过该缓存时,直接放到 暂时存储室    
        factory.setSizeThreshold(1024*1024) ;    
            
        //大文件的上传处理    
        ServletFileUpload upload = new ServletFileUpload(factory);   
        List<FileItem> list = null;  
        try {  
            list = (List<FileItem>)upload.parseRequest(request);  
            System.out.println("上传文件的数量是"+list.size());
        } catch (FileUploadException e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }    
        for(FileItem item : list)    
        {    
            //获取表单的属性名字    
            String name = item.getFieldName();  //这个name就是<input>标签中的name属性,是很重要与服务器通信的方式  
              
            System.out.println("传来的filedName是"+name);    
            //如果获取的 表单信息是普通的 文本 信息    
            if(item.isFormField())    
            {      
            	System.out.println("传来一个文本");
               System.out.println(item);  
            }    
            //对传入的非 简单的字符串进行处理 ,比如说二进制的 图片,电影这些    
            else    
            {    System.out.println("传来一个文件");
                /**  
                 * 以下三步,主要获取 上传文件的名字  
                 */    
                //获取路径名    
                String value = item.getName() ;    
                //索引到最后一个反斜杠    
                int start = value.lastIndexOf("\\");    
                //截取 上传文件的 原来的名字,加1是 去掉反斜杠,    
                String filename = value.substring(start+1);  
                
                //虽然上面已经获取了文件原本的名字,但是服务器一般用随机数命名
                String randomName = RandomStringUtils.random(10);//用apche commons-long包中的类生成随机字符串
                //将文件写入服务器,第二个参数是文件名(不加扩展名),第三个参数是要写入的文件夹  
                writeFile(item, randomName, "item_imgs");  
                  
            }              
        }  
        PrintWriter out = response.getWriter();  
        out.print("{}");//返回空json字符串代表上传成功,同时在浏览器收到后会出现绿色的对勾,如果失败就传输一个"{error:'错误信息'}",这样的话进图条就走不到100%并且还会锁死  
        out.flush();  
        out.close();  
    }  
      
   

/** 
 * 传入一个fileitem,并且按照给出的文件名前缀,文件名后缀(索引),文件存储相对目录来写入从互联网的到的文件 
 * @param fileItem 传来的文件对象 
 * @param firstName 文件名前缀 
 * @param parentFolder 相对存储目录,如:"imgs" 根目录C:\apache-tomcat-7.0.61\webapps\项目名\+parentFolder\ 
 * @return 
 * @throws IOException 
 */  
public boolean writeFile(FileItem fileItem,String firstName,String parentFolder) throws IOException{  
    //用原来的文件名做文件名,用项目目录的绝对地址/attachment作为目录地址  
      
    File file1 = new File(this.getServletContext().getRealPath(parentFolder+"/"),firstName);  
    if(file1.getParentFile().exists()==false){  
        file1.getParentFile().mkdirs();  
    }  
    file1.createNewFile();  
      
    InputStream ins = fileItem.getInputStream();  
    OutputStream ous = new FileOutputStream(file1);  
      
    try{  
        byte[] buffer = new byte[1024];  
        System.out.println("开始写文件");  
        int len = 0;  
        while((len = ins.read(buffer)) > -1)  
            ous.write(buffer,0,len);  
        System.out.println("已保存的文件"+file1.getAbsolutePath());  
    }finally{  
        ous.close();  
        ins.close();  
    }  
    return true;  
}  
}


本servlet服务器端代码同样适用于html的文件上传表单,详细请参考本人另一篇博文《 bootstrap3 文件上传插件fileinput中文说明文档》


你可能感兴趣的:(android,服务器,上传)