目前的图片上传方式有很多种,其中比较常见的好像都是跟阿里有关的,跟阿里相关其中我们直接拿到阿里的key等信息,直接进行jar包的集成进行上传,但是这样对于三方的key等信息容易泄漏,这里不建议使用,接下来就是对于表单的上传,这里也是可以直接上传到阿里的服务器的,首先我们需要定义两个参数,对于我们所获取到的照片进行定义
private String headPath;//本地图片地址
private String imageUrl = "";
然后需要接口先给我们返回到阿里的相关信息,像文件夹、路径地址等这些信息,然后同时我们需要对于表单上传的一些参数进行定义
String boundary = "---------------------------265001916915724";
String lineEnd = "\r\n";
String urlServer = "";
String key = "";
DataOutputStream dos = null;
HashMap map = new HashMap<>();
HttpURLConnection connection = null;
FileInputStream fin = null;
int bytesAvailable, bufferSize, bytesRead;
int maxBufferSize = 1 * 1024 * 512;
byte[] buffer = null;
之后就是表单直接上传到阿里服务的功能了,这里我们需要将接口获取到阿里相关的信息进行转换、存放到上传的参数当中
//OssBean 是我们获取到的接口信息封装类,其中包含了我们所需要的阿里的各种信息
private void doGet(OssBean response) throws Exception {
urlServer = response.getHost();
key = response.getKey();
imageUrl = response.getUrl();
map.put("OSSAccessKeyId", response.getAccess_key_id());
map.put("policy", response.getPolicy());
map.put("Signature", response.getSignature());
map.put("key", response.getKey());
map.put("x-oss-security-token", response.getSts_token());
try {
Looper.prepare();
URL url = new URL(urlServer);
connection = (HttpURLConnection) url.openConnection();
//允许向URL流中读写数据
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setUseCaches(true);
//启动post方法
connection.setRequestMethod("POST");
//设置请求头内容
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("Content-Type", "text/plain");
// 伪造请求头
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
// 开始伪造POST Data里面的数据
dos = new DataOutputStream(connection.getOutputStream());
fin = new FileInputStream(headPath);
Log.e("图片上传", "开始上传images");
// 开始连接
connection.connect();
//--------------------开始伪造上传images.jpg的信息-----------------------------------
Iterator iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry entry = (Map.Entry) iterator.next();
String string = "--" + boundary + "\r\n";
dos.write(string.getBytes());
String one = "Content-Disposition: form-data; name=\"" + entry.getKey() + "\"\r\n\r\n";//map key
dos.write(one.getBytes());
String tw = entry.getValue() + "\r\n";//map value
dos.write(tw.getBytes());
}
int last = key.lastIndexOf("/");
String keyEnd = key.substring(last + 1);//key值后
String fileMeta = "--" + boundary + lineEnd +
"Content-Disposition: form-data; name=\"file\"; filename=\"" + keyEnd + "\"" + lineEnd +
"Content-Type: image/jpeg" + lineEnd + lineEnd;
// 向流中写入fileMeta
dos.write(fileMeta.getBytes());
// 取得本地图片的字节流,向url流中写入图片字节流
bytesAvailable = fin.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
buffer = new byte[bufferSize];
bytesRead = fin.read(buffer, 0, bufferSize);
while (bytesRead > 0) {
dos.write(buffer, 0, bufferSize);
bytesAvailable = fin.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fin.read(buffer, 0, bufferSize);
}
dos.writeBytes(lineEnd + lineEnd);
//--------------------伪造images.jpg信息结束-----------------------------------
Log.e("图片上传", "结束上传");
// POST Data结束
dos.writeBytes("--" + boundary + "--");
// Server端返回的信息
Log.e("图片上传", "code" + connection.getResponseCode());
Log.e("图片上传", "message" + connection.getResponseMessage());
if (dos != null) {
dos.flush();
dos.close();
}
uploadUser("", "", "", "", "", imageUrl);
Looper.loop();
} catch (Exception e) {
e.printStackTrace();
Log.e("图片上传", "上传失败");
}
}
我们自己直接将图片上传到阿里的服务器固然可行,但在实际的测试当中,容易出现错误和失败的情况,而这种情况可以说是五花八门,在项目中定位也是比较困难的,有的时候并没有任何报错但就是上传失败,也是很无奈啊╮(╯▽╰)╭ 所以在接口能够支持的时候,我们最好的方法是通过retrofit进行上传,这种方法不但只需要几行代码就能搞定[比较轻松],而且就前端而言我们不需要拿到任何关于阿里服务器的实质性内容信息,对于信息保密也有一定的好处
Retrofit是一个用于安卓和java的http框架,通常我们会使用其进行网络的连接调用,这里我们说一下他的另一种功能----以form表单上传图片的方法
Retrofit官网
首先需要添加gradle的引用
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
//noinspection GradleDependency 日志的拦截器
implementation 'com.squareup.okhttp3:logging-interceptor:3.14.9'
//noinspection GradleDependency
implementation 'com.google.code.gson:gson:2.8.5'
然后需要定义一下我们的接口请求方式
@Multipart//这里用Multipart,不添加的话会引起崩溃反应
@POST("/url")//请求方法为POST,里面为你要上传的url
//注解用@Part,参数类型为List 方便上传其它需要的参数或多张图片
fun uploadPic(@Part partLis:List ):
CompletableCall
这里我用的图片选择器是PictureSelector,关于PictureSelector网上有很多的介绍,这里就不多做赘述了,有兴趣可以多去了解一下,还是比较好用的一个微信图片选择器的(╹▽╹)
这里看到我们所选择的图片,接下来就是在点击已完成之后的回调进行表单图片上传了
//1.创建MultipartBody.Builder对象
MultipartBody.Builder builder = new MultipartBody.Builder()
//表单类型
.setType(MultipartBody.FORM)
//2.获取图片,创建请求体
File file=new File(path);
//表单类型
RequestBody body=RequestBody.create(MediaType.parse("multipart/form-data"),file);
//3.调用MultipartBody.Builder的addFormDataPart()方法添加表单数据
/**
* ps:builder.addFormDataPart("code","123456");
* ps:builder.addFormDataPart("file",file.getName(),body);
*/
builder.addFormDataPart(key, value);//传入服务器需要的key,和相应value值
builder.addFormDataPart(key,file.getName(),body); //添加图片数据,body创建的请求体
//4.创建List 集合,
// 调用MultipartBody.Builder的build()方法会返回一个新创建的MultipartBody
// 再调用MultipartBody的parts()方法返回MultipartBody.Part集合
List parts=builder.build().parts();
//5.最后进行HTTP请求,传入parts即可
RetrofitHelper.create(ApiService.class)
.uploadPic(parts)
.enqueue(this, new AnimCallback(context) {
@Override
protected void onError(Call call, HttpError error) {
Log.e("图片上传", error.errorMessage);
}
@Override
protected void onSuccess(Call call, UploadPicBean response) {
Log.e("图片上传", response.toString());
}
});
到这里我们的图片就上传完毕了,最后我们打开这个图片链接可以发现和我们一开始所选择的图片是一模一样的,(▽)