Android Java中使用Retrofit通过Model类添加文件上传字段实现WebService数据插入的问题求助
解决Retrofit上传文件+表单字段的问题
看起来你遇到的核心问题是:原来的接口用@Body将Model序列化为JSON发送,但File对象无法被JSON序列化,所以直接在Model里加File字段是行不通的。上传文件需要使用Multipart/form-data格式的请求,而不是JSON请求。下面是一步步的解决方案:
1. 修改Retrofit Service接口
首先要把原来的@POST + @Body改成@Multipart + @Part,每个表单字段(包括文件)单独作为@Part参数传递:
public interface swabtestService { @GET("hasil-antigen-list") Call<List<SwabtestModel>> getUsers(); // 改成Multipart请求,每个字段用@Part声明 @Multipart @POST("insert-hantigen") Call<SwabtestModel> addswab( @Part("hasil") RequestBody hasil, @Part("tanggal") RequestBody tanggal, @Part("tempat") RequestBody tempat, @Part("user_id") RequestBody userId, @Part MultipartBody.Part file ); }
注意:@Part里的字符串(比如"hasil")要和服务器端接收的参数名完全一致,包括"file_name"也要对应服务器的文件参数名。
2. 调整SwabtestModel(可选)
你可以保留原来的Model类,但可以移除file_name字段(因为文件会单独用MultipartBody.Part传递),或者保留它用于本地逻辑,上传时不用它即可。
3. 修改Activity中的save方法
现在需要把Model里的每个字段转换成RequestBody,并单独处理文件部分:
public void save(SwabtestModel sw){ // 将普通字符串/数字字段转为RequestBody RequestBody hasilBody = RequestBody.create(MediaType.parse("text/plain"), sw.gethasil()); RequestBody tempatBody = RequestBody.create(MediaType.parse("text/plain"), sw.gettempat()); RequestBody userIdBody = RequestBody.create(MediaType.parse("text/plain"), sw.getuserid().toString()); // 处理日期:将Date转为服务器预期的字符串格式(这里用你原来的dd/MM/yyyy) SimpleDateFormat dateFormatter = new SimpleDateFormat("dd/MM/yyyy"); String tanggalStr = dateFormatter.format(sw.gettanggal()); RequestBody tanggalBody = RequestBody.create(MediaType.parse("text/plain"), tanggalStr); // 处理文件:从Uri创建RequestBody(注意:不要直接依赖filePath,有些Uri无法转为本地文件路径) RequestBody fileRequestBody = null; try { // 获取文件的MIME类型 String mimeType = getContentResolver().getType(uri); // 用InputStream读取文件内容转为字节数组(兼容所有Uri类型) byte[] fileBytes = getBytesFromUri(uri); fileRequestBody = RequestBody.create(MediaType.parse(mimeType), fileBytes); } catch (IOException e) { e.printStackTrace(); Toast.makeText(this, "文件读取失败", Toast.LENGTH_SHORT).show(); return; } // 将文件封装为MultipartBody.Part,参数名要和服务器一致(这里是"file_name") String fileName = uri.getLastPathSegment(); MultipartBody.Part filePart = MultipartBody.Part.createFormData("file_name", fileName, fileRequestBody); // 调用接口 Call<SwabtestModel> call = swabtestService.addswab(hasilBody, tanggalBody, tempatBody, userIdBody, filePart); call.enqueue(new Callback<SwabtestModel>() { @Override public void onResponse(Call<SwabtestModel> call, Response<SwabtestModel> response) { if(response.isSuccessful()){ String status = response.body().getStatus(); Toast.makeText(SwabtestActivity.this, status, Toast.LENGTH_LONG).show(); } else { // 打印错误信息方便调试 try { Log.e("UPLOAD ERROR", response.errorBody().string()); } catch (IOException e) { e.printStackTrace(); } } } @Override public void onFailure(Call<SwabtestModel> call, Throwable t) { Log.e("ERROR: ", t.getMessage()); } }); } // 辅助方法:从Uri读取文件字节数组 private byte[] getBytesFromUri(Uri uri) throws IOException { InputStream inputStream = getContentResolver().openInputStream(uri); ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream(); int bufferSize = 1024; byte[] buffer = new byte[bufferSize]; int len; while ((len = inputStream.read(buffer)) != -1) { byteBuffer.write(buffer, 0, len); } inputStream.close(); return byteBuffer.toByteArray(); }
4. 注意事项
- 确保服务器端接口支持
Multipart/form-data请求,并且参数名和你@Part里的完全匹配; - 日期格式要和服务器预期一致,如果服务器用
yyyy-MM-dd,就修改你的SimpleDateFormat; - 文件的MIME类型尽量准确,比如图片用
image/jpeg,文档用application/pdf等,用getContentResolver().getType(uri)可以自动获取正确类型; - 如果你选择直接用File对象(仅适用于本地文件Uri),可以替换文件部分的代码:
但这种方式不适用于ContentProvider类型的Uri(比如从相册选的图片Uri),所以推荐用字节数组的方式。File file = new File(filePath); RequestBody fileRequestBody = RequestBody.create(MediaType.parse(getContentResolver().getType(uri)), file); MultipartBody.Part filePart = MultipartBody.Part.createFormData("file_name", file.getName(), fileRequestBody);
内容的提问来源于stack exchange,提问作者andreaniwpi
相关产品推荐
相关产品推荐

