使用一般的上传方法一般上传不能超过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("选择失败"); }
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; } }