使用一般的上传方法一般上传不能超过2m的文件,也非常容易中断和出错,于是本人打算使用xutils框架进行文件上传开发,话不多说直接上源码
首先要下载这个类库的jar包,地址:https://github.com/wyouflf/xUtils
android端代码:
添加权限
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"));//设置要上传文件的本地路径,第一个参数就是html中标签中的name属性,是与服务器传输文件字节流以外的文本信息的重要渠道,在servlet中这样获得fileitem.getFieldName();
HttpUtils http = new HttpUtils();
http.send(HttpRequest.HttpMethod.POST,
"http://192.168.1.112:8080/auto_serve/servlet/UploadImage",//设置要上传到的url
params,
new RequestCallBack() {
@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 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.
*
* 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("");
out.println("");
out.println(" A Servlet ");
out.println(" ");
out.print(" This is ");
out.print(this.getClass());
out.println(", using the GET method");
out.println(" ");
out.println("");
out.flush();
out.close();
}
/**
* The doPost method of the servlet.
*
* 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 list = null;
try {
list = (List)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就是标签中的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;
}
}