之前写过一篇有关使用 Retrofit 上传图片文件的代码,不过如果使用 OkHttp 该如何做呢。相信对于这两者之间有些了解的同学都知道其实 Retrofit 的内部网络请求实现就是 OkHttp,包裹了一层之后只是为了方便开发者写接口并且和 RxJava 结合使用而已,所以代码的差别不是很大。
这里没有很好的封装,只是一个 demo,大家实际使用的时候给 okHttp 封装一层会更好。我自己开发的语言是 Kotlin,不过为了方便起见,我会把 Java 版本的代码也粘贴上去,至于后台的代码其实和上篇文章介绍的一样,不过因为其中名称有所变动所以我还是会都给出。如果有什么问题欢迎指出和提问
// 上传背景图片的方法
fun uploadBgImg(userid: String, imgPath: String, listener: UploadListener) {
var file: File? = null
try {
file = File(imgPath)
} catch (e: URISyntaxException) {
e.printStackTrace()
}
val mOkHttpClent = OkHttpClient()
val requestBody = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("userid", userid) // 上传参数
.addFormDataPart(
"bgImg", file?.name,
RequestBody.create(MediaType.parse("multipart/form-data"), file!!)
) // 上传文件
.build()
val request = Request.Builder()
.url(ConstantConfig.JACKSON_BASE_URL + "phoneUser/uploadBgImg")
.post(requestBody)
.build()
val call = mOkHttpClent.newCall(request)
call.enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
LogUtils.e("yyy" + e.message)
listener.uploadFailed(e.message.toString())
}
override fun onResponse(call: Call, response: Response) {
if (response.isSuccessful) {
listener.uploadSuccess()
} else {
listener.uploadSuccess()
LogUtils.e("tttttt" + response.code() + response.message())
}
}
})
}
接口文件
interface UploadListener {
fun uploadSuccess()
fun uploadFailed(msg: String)
}
实际调用位置
//上传背景图片
private fun uploadBgImg(path: String) {
UploadUtils.uploadBgImg(App.getLoginUser()?.userid!!, path, object : UploadUtils.UploadListener {
override fun uploadSuccess() {
runOnUiThread {
userBgImage.setImageBitmap(BitmapFactory.decodeFile(path))
}
LogUtils.e("ModifyUserInfo 成功")
}
override fun uploadFailed(msg: String) {
LogUtils.e("ModifyUserInfo" + msg)
}
})
}
这里需要注意的就是 okHttp 默认返回的线程是子线程而不是主线程。所以我们如果需要进行一些操作的话还是需要有 runOnUiThread 方法切换到主线程中才可以。大家有空闲的话可以封装一下,具体使用可以通过 Handle,毕竟是 Android 中的异步处理大师。
后台代码,注意这里参数名称和上次那篇不一样,所以如果复制代码使用的话不要对应出错
/**
* 用户背景图片上传
*/
@RequestMapping(value = "/uploadBgImg", method = RequestMethod.POST)
@ResponseBody
public Map uploadBgImg(@RequestParam("userid") String userid, @RequestBody MultipartFile bgImg) {
// 在 spring 家族中上传头像都是使用 MultipartFile 类。多个文件则是数组类型
System.out.println("进入背景图片上传接口");
System.out.println("文件名:" + bgImg.getOriginalFilename() + "\n" + "userid:" + String.valueOf(userid));
Map map = new HashMap<>();
if (!bgImg.isEmpty()) {
String originalFileName = bgImg.getOriginalFilename();
String mimeType = request.getServletContext().getMimeType(originalFileName);
System.out.println("mimeType: " + mimeType);
// 是否图片文件
if (mimeType != null && mimeType.startsWith("image/")) {
try {
String suffix = originalFileName.split("\\.")[1]; // 扩展名
// 上传到项目根目录的 upload 文件夹
String avatarPath = request.getSession().getServletContext().getRealPath("/upload") +
// File.separator + user.getUsername() +
File.separator + "avatar" +
File.separator + System.currentTimeMillis() + "." + suffix;
String savePath = avatarPath.substring(avatarPath.indexOf("\\upload"));
String finPath = savePath.replaceAll("\\\\", "/");
System.out.println("savePath:" + savePath);
System.out.println("finPath:" + finPath);
/**
* 上传到具体的硬盘路径,此时需要配置 tomcat 虚拟路径
*/
// String avatarPath = "I:" + File.separator + "ProjectsFolder" + File.separator + "IdeaProject"
// + File.separator + "MovieProject" + File.separator + "src" + File.separator + "main"
// + File.separator + "webapp" + File.separator + "upload" + File.separator + user.getUsername()
// + File.separator + "avatar" + File.separator + System.currentTimeMillis() + "." + suffix;
System.out.println("tomcatPath: " + avatarPath);
File saveFile = new File(avatarPath);
if (!saveFile.getParentFile().exists()) {
saveFile.getParentFile().mkdirs();
saveFile.createNewFile();
}
bgImg.transferTo(saveFile); //将文件上传到指定的服务器的位置
int rows = userService.updateUserAvatar(userid, finPath.substring(1)); // 存储在数据库中的路径就从 upload 开始就可以了,
// 这里的 sub 是为了去除第一个 ‘/’
if (rows > 0) {
System.out.println("上传背景图片成功");
// // 上传文件成功之后查询 user,之后把最新的 user 返回
PhoneUser user = userService.getUserInfo(userid);
if (user != null) {
map.put("data", user);
map = CommonUtils.operationSucceed(map);
} else {
map = CommonUtils.operationFailed(map, "other error", HttpStatus.NOT_FOUND.value());
}
} else {
System.out.println("上传背景图片失败");
map = CommonUtils.operationFailed(map,
"change data failed", HttpStatus.BAD_REQUEST.value());
}
} catch (IOException e) {
// 上传过程出错
System.out.println(e.getMessage());
map = CommonUtils.operationFailed(map, "upload fail", HttpStatus.INTERNAL_SERVER_ERROR.value());
e.printStackTrace();
}
} else {
// 不是图片文件返回相关信息
map = CommonUtils.operationFailed(map, "please upload an image file", HttpStatus.BAD_REQUEST.value());
}
// 空文件返回相关
} else {
System.out.println("empty file");
map = CommonUtils.operationFailed(map, "empty file", HttpStatus.BAD_REQUEST.value());
}
return map;
}
到此代码完成,其中注释也都比较丰富相信大家都能理解。下面我把 Java 版本的前台代码贴出来供大家参考。
// 上传背景图片的方法
public static void uploadBgImg(String userid, String imgPath, final UploadUtils.UploadListener listener) {
File file = null;
try {
file = new File(imgPath);
} catch (Exception e) {
e.printStackTrace();
}
OkHttpClient mOkHttpClent = new OkHttpClient();
assert file != null;
MultipartBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("userid", userid) // 上传参数
.addFormDataPart(
"bgImg", file.getName(),
RequestBody.create(MediaType.parse("multipart/form-data"), file)
) // 上传文件
.build();
Request request = new Request.Builder()
.url(ConstantConfig.JACKSON_BASE_URL + "phoneUser/uploadBgImg")
.post(requestBody)
.build();
Call call = mOkHttpClent.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
listener.uploadFailed(e.getMessage());
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) {
if (response.isSuccessful())
listener.uploadSuccess();
}
});
}
相信小伙伴们自己也可以写出来,不过可惜 AS 只提供了 Java 转 Kotlin 的插件,没有 Kotlin 转 Java 的插件。所以只能自己手写啦。
愿我们成为真实的自己,一起加油