Android设备通过Heroku上Spring Boot应用传MP4至AWS S3,Android端用何方法?
Android端上传MP4文件到Spring Boot服务的实现方法
你的Spring Boot后端通过POST /add接口接收multipart/form-data类型的请求,需要包含两个核心部分:
- 名为
file的文件参数(对应后端的@RequestParam("file") MultipartFile) - Product实体的各个表单字段参数(对应后端的
@Valid Product)
下面是两种Android端常用的实现方式:
方法一:使用OkHttp实现
OkHttp是Android生态中最常用的网络库,适合灵活构建请求。
1. 添加依赖(Gradle)
implementation("com.squareup.okhttp3:okhttp:4.12.0")
2. 上传代码实现
import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MultipartBody import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.RequestBody.Companion.asRequestBody import java.io.File fun uploadMp4(mp4File: File, productFields: Map<String, String>) { val client = OkHttpClient() // 构建MP4文件请求体 val fileRequestBody = mp4File.asRequestBody("video/mp4".toMediaTypeOrNull()) val filePart = MultipartBody.Part.createFormData("file", mp4File.name, fileRequestBody) // 构建表单请求体,添加文件和Product字段 val requestBody = MultipartBody.Builder() .setType(MultipartBody.FORM) .addPart(filePart) .apply { // 遍历添加Product的所有字段,比如name、price等,需与后端Product类属性名一致 productFields.forEach { (key, value) -> addFormDataPart(key, value) } } .build() val request = Request.Builder() .url("https://你的Heroku服务域名/add") // 替换为实际服务地址 .post(requestBody) .build() // 异步发送请求,避免阻塞主线程 client.newCall(request).enqueue(object : okhttp3.Callback { override fun onFailure(call: okhttp3.Call, e: IOException) { // 处理上传失败逻辑,比如提示用户 e.printStackTrace() } override fun onResponse(call: okhttp3.Call, response: okhttp3.Response) { when { response.isSuccessful -> { // 上传成功,可做后续处理 } else -> { // 处理后端返回的错误,比如读取错误信息 val errorMsg = response.body?.string() } } response.close() } }) }
注意事项
- 替换代码中的服务URL为你Heroku部署的实际地址
productFields需包含Product实体的所有必填字段,键名要和后端Product类的属性名完全匹配- 在AndroidManifest.xml中添加网络权限:
<uses-permission android:name="android.permission.INTERNET" /> - Android 10+需注意文件访问权限,建议通过MediaStore获取MP4文件,避免直接操作外部存储
方法二:使用Retrofit实现
Retrofit是基于OkHttp的封装,代码更简洁,适合结构化的网络请求场景。
1. 添加依赖(Gradle)
implementation("com.squareup.retrofit2:retrofit:2.9.0") implementation("com.squareup.retrofit2:converter-gson:2.9.0") implementation("com.squareup.okhttp3:okhttp:4.12.0")
2. 定义Retrofit接口
import okhttp3.MultipartBody import okhttp3.RequestBody import retrofit2.Call import retrofit2.http.Multipart import retrofit2.http.POST import retrofit2.http.Part import retrofit2.http.PartMap interface ProductUploadApi { @Multipart @POST("add") fun uploadProduct( @Part file: MultipartBody.Part, @PartMap productFields: Map<String, @JvmSuppressWildcards RequestBody> ): Call<Void> }
3. 上传代码实现
import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.MediaType.Companion.toMediaTypeOrNull fun uploadWithRetrofit(mp4File: File, productFields: Map<String, String>) { val retrofit = Retrofit.Builder() .baseUrl("https://你的Heroku服务域名/") // 替换为服务根地址 .addConverterFactory(GsonConverterFactory.create()) .build() val api = retrofit.create(ProductUploadApi::class.java) // 构建文件Part val fileRequestBody = mp4File.asRequestBody("video/mp4".toMediaTypeOrNull()) val filePart = MultipartBody.Part.createFormData("file", mp4File.name, fileRequestBody) // 转换Product字段为RequestBody Map val productBodyMap = mutableMapOf<String, RequestBody>() productFields.forEach { (key, value) -> productBodyMap[key] = value.toRequestBody("text/plain".toMediaTypeOrNull()) } // 发送请求 val call = api.uploadProduct(filePart, productBodyMap) call.enqueue(object : retrofit2.Callback<Void> { override fun onResponse(call: Call<Void>, response: retrofit2.Response<Void>) { if (response.isSuccessful) { // 上传成功处理 } else { // 处理后端错误 } } override fun onFailure(call: Call<Void>, t: Throwable) { // 请求失败处理 t.printStackTrace() } }) }
注意事项
- 若后端返回非空响应,可修改Call的泛型类型(比如
Call<String>)来获取返回内容 - 确保Product字段的键名与后端实体类属性完全一致,否则后端无法正确绑定参数
- 同样需要申请网络权限和文件访问权限
内容的提问来源于stack exchange,提问作者Radek0582
相关产品推荐
相关产品推荐

