需要知道的知识
- 在我们写html页面进行文件上传的时候我们必须要在表单form中添加enctype="multipart/form-data"属性并在表单中使用<input type="file" name="file">这样的输入项,如果读者想知道其中的原理请看http协议
- 了解rxjava和retrofit的结合使用
实现图片上传的步骤
- 搭建服务端在这里我使用最简单的servlet和apache提供的文件上传下载的服务端(可自行学习,也可忽略不看)
public class UploadPic extends HttpServlet{
private static final long serialVersionUID = 1L;
public UploadPic() {
super();
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setCharacterEncoding("utf-8");
try {
// 1.进行文件上传
DiskFileItemFactory disk = new DiskFileItemFactory();
disk.setSizeThreshold(1024 * 1024 * 1);
disk.setRepository(new File(this.getServletContext().getRealPath("WEB-INF/temp")));
ServletFileUpload upload = new ServletFileUpload(disk);
if (!ServletFileUpload.isMultipartContent(request)) {
throw new RuntimeException("请使用正确的文件表单上传项");
}
upload.setFileSizeMax(1024 * 1024 * 1);
upload.setSizeMax(1024 * 1024 * 10);
upload.setHeaderEncoding("utf-8");
upload.setProgressListener(new ProgressListener() {
Long beginTime = System.currentTimeMillis();
@Override
public void update(long bytesRead, long contentLength, int items) {
try {
Thread.sleep(500); // 为了显示测试的效果
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
BigDecimal br = new BigDecimal(bytesRead).divide(new BigDecimal(1024), 2, BigDecimal.ROUND_HALF_UP);
BigDecimal cl = new BigDecimal(contentLength).divide(new BigDecimal(1024), 2,
BigDecimal.ROUND_HALF_UP);
// 剩余字节数
BigDecimal ll = cl.subtract(br);
// 上传百分比
BigDecimal per = br.multiply(new BigDecimal(100)).divide(cl, 2, BigDecimal.ROUND_HALF_UP);
// 上传用时
Long nowTime = System.currentTimeMillis();
Long useTime = (nowTime - beginTime) / 1000;
// 上传速度
BigDecimal speed = new BigDecimal(0);
if (useTime != 0) {
speed = br.divide(new BigDecimal(useTime), 2, BigDecimal.ROUND_HALF_UP);
}
// 大致剩余时间
BigDecimal ltime = new BigDecimal(0);
if (!speed.equals(new BigDecimal(0))) {
ltime = ll.divide(speed, 0, BigDecimal.ROUND_HALF_UP);
}
}
});
List<FileItem> items = upload.parseRequest(request);
for (FileItem item2 : items) {
if (item2.isFormField()) {
// 正常的表单项
String name = item2.getFieldName();
String value = item2.getString("utf-8");
System.out.println(name + "====" + value);
} else {
// 文件上传项
// 得到文件名
String name = item2.getName(); // 有时候是一个全路径有时候只是一个文件名
String[] temps = name.split("\\\\");
name = temps[temps.length - 1];
// 使得文件名唯一
String uuidName = UUID.randomUUID().toString() + "_" + name;
// 使得文件夹中只有一个文件
String hash = Integer.toHexString(uuidName.hashCode());
String path = this.getServletContext().getRealPath("WEB-INF/upload");
System.out.println("path==========" + path);
String imgUrl = "/WEB-INF/upload";
for (char c : hash.toCharArray()) {
path += "/" + c;
imgUrl += "/" + c;
}
imgUrl += "/" + uuidName;
// 文件夹不存在则进行创建
File f = new File(path);
if (!f.exists()) {
f.mkdirs();
}
System.out.println("file==========" + f.getPath());
// 进行文件的保存
InputStream in = item2.getInputStream();
OutputStream out = new FileOutputStream(new File(f, uuidName));
IOUtils.In2Out(in, out);
IOUtils.close(in, out);
item2.delete();
}
}
System.out.println("上传成功");
// 上传成功
response.getWriter().write("{\"flag\":1}");
} catch (Exception e) {
e.printStackTrace();
// 上传失败
response.getWriter().write("{\"flag\":0}");
throw new RuntimeException(e);
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
- 实现通过app来进行图片的上传
2.1. 导入依赖的包引入rxjava2 compile 'io.reactivex.rxjava2:rxjava:2.0.4' //引入rxandroid compile \'io.reactivex.rxjava2:rxandroid:2.0.1' //引入retrofit compile 'com.squareup.retrofit2:retrofit:2.1.0' //引入json转换器 compile 'com.squareup.retrofit2:converter-gson:2.1.0' //rxjava适配器 compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
别忘了添加网络等权限哦
2.2. 创建service
public interface ApiService {
@Multipart //enctype="multipart/form-data"
@POST("UploadPic") //图片上传的路径 使用MultipartBody.Part上
传图片
Observable<Flag> uploadPic(@Part List<MultipartBody.Part> parts);
}
2.3. 上传图片
//Flag只是简单的标记了下上传是否成功
private Observable<Flag> upPic(){
RetrofitClient net = RetrofitClient.getInstance(this,"上传的链接");
ApiService service = net.create(ApiService.class); //创建service
List<MultipartBody.Part> parts = new ArrayList<>();
for (File f : files) { //files所要上传的所有文件
RequestBody body = RequestBody.create(MediaType.parse("image/*"),f); //说明该文件为图片类型
//"key"相当与<input type="file" name="key">中的name的值 (其实没有多大的用,在后台可以遍历取出文件,一般要和后台开发人员协商的) f.getName为文件名,这两个是不一样的。
MultipartBody.Part part = MultipartBody.Part.createFormData("key", f.getName(),body);
parts.add(part);
}
return service.uploadPic(parts).compose(RetrofitClient.schedulersTransformer);
}
private void uploadPic(){
Observable<Flag> pics = upPic();
pics.subscribe(new Observer<Flag>() {//进行订阅
@Override
public void onSubscribe(Disposable d) { }
@Override
public void onNext(Flag flag) {
if (flag.getFlag()==1) {
Log.d("MainActivity","上传成功");
}
}
@Override
public void onError(Throwable e) {
Log.d("MainActivity","onError===="+e.getMessage());
}
@Override
public void onComplete() {
}
});
}
4.效果


手机上没有好看的图片还请多多包涵哈!
这是eclipse上打印的

5.源码下载地址
http://pan.baidu.com/s/1hsznqBy
说明
在这个简单的项目里使用了一个图片选择器的开源项目,在源码了已经进行了标注。
RetrofitClient是我对retrofit进行了一个简单的封装,在源码中有
网友评论