Retrofit json上传,文本上传,文件上传,多文件上传,文本+文件上传,多文件+多文件上传

get请求:

    //直接添加参数
    @GET(dataUrl)
    fun getData1(@Query("data") data:String):BaseBean<Any>

    //map添加参数
    //@JvmSuppressWildcards
    @GET(dataUrl)
    fun getData2(@QueryMap map:Map<String,Any>):BaseBean<Any>

    //在链接里添加参数
    @GET("$dataUrl/{id}")
    fun getData3(@Path("id") id:Int)

post请求:

    //直接添加参数
    @FormUrlEncoded
    @POST(dataUrl)
    fun postData(@Field("data") data: String):BaseBean<Any>

    //map添加参数
    @JvmSuppressWildcards
    @FormUrlEncoded
    @POST(dataUrl)
    fun postData2(@FieldMap map: Map<String, Any>):BaseBean<Any>

postJson请求



    //直接传对象,@Body会把any转成json
    @POST(dataUrl)
    fun postJson(@Body any:Any):BaseBean<Any>

    //同上,@Body会把map转成json,其实这方法有点多余,因为map也是any的子类
    @POST(dataUrl)
    fun postJson(@Body map:Map<String,Any>):BaseBean<Any>

    
    //如果要传的已经是个String类型的json,或者其他基础数据类型,则需要转成RequestBody再传递
    @POST(dataUrl)
    fun postJson(@Body jsonBody: RequestBody):BaseBean<Any>

    //json转RequestBody的方法
    fun jsonToRequestBody(json:String): RequestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"),json)

当然也可以自己实现Converter来实现直接传String json的方法 

首先实现Converter:

object StringConverterFactory: Converter.Factory(){
    override fun responseBodyConverter(
        type: Type,
        annotations: Array<Annotation>,
        retrofit: Retrofit
    ): Converter<ResponseBody, *>? {
        if(type == String::class.java)
            return object :Converter<ResponseBody, String> {
                override fun convert(value: ResponseBody): String? {
                    return value.string()
                }
            }
        return super.responseBodyConverter(type, annotations, retrofit)
    }

    override fun requestBodyConverter(
        type: Type,
        parameterAnnotations: Array<Annotation>,
        methodAnnotations: Array<Annotation>,
        retrofit: Retrofit
    ): Converter<*, RequestBody>? {
        if(type == String::class.java) return object :Converter<String,RequestBody>{
            override fun convert(value: String): RequestBody? {
                return RequestBody.create(MediaType.parse("application/json; charset=utf-8"),value)
            }
        }
        return super.requestBodyConverter(type, parameterAnnotations, methodAnnotations, retrofit)
    }
}

添加Converter:
        Retrofit.Builder().client(builder.build())
            .baseUrl(baseUrl)
            .addConverterFactory(StringConverterFactory)
            .addConverterFactory(GsonErrorConverterFactory())
            ……


然后就可以直接传json了
@POST(dataUrl)
fun postJson(@Body json: String):BaseBean<Any>

文件上传

//上传文件使用MultipartBody.Part,上传多个文件使用List<MultipartBody.Part>
    //上传单个文件
    @Multipart
    @POST(dataUrl)
    fun upLoadFile(@Part part:MultipartBody.Part):BaseBean<Any>

    //上传多个文件
    @Multipart
    @POST(dataUrl)
    fun upLoadFiles(@Part parts:List<MultipartBody.Part>):BaseBean<Any>

/**
 * 生成上传文件的MultipartBody.Part参数
 * name:上传文件的参数名
 * file:要上传的文件
 */
fun getFilePart(name:String, file:File): MultipartBody.Part{
    val type = getMimeType(file) ?:"multipart/form-data"
    return MultipartBody.Part.createFormData(name,file.name, RequestBody.create(MediaType.parse(type),file))
}

//生成多文件上传的List<MultipartBody.Part>,多文件上传分为两种,一种是多个文件参数对应多个文件,另一种是单个参数对应多个文件
/**
 * 多参数多文件上传参数
 */
fun getParts(fileMay:Map<String,File>):List<MultipartBody.Part>{
    val list = arrayListOf<MultipartBody.Part>()
    fileMay.forEach{list.add(getFilePart(it.key,it.value)) }
    return list
}

/**
 * 同一参数名多图片上传
 */
fun getParts(name:String,files:List<File>):List<MultipartBody.Part>{
    val list = arrayListOf<MultipartBody.Part>()
    files.forEach { list.add(getFilePart(name,it)) }
    return list
}

带文本的文件上传

//带文本的文件上传可以使用MultiaprtBody
    //文本+文件上传
    @POST(dataUrl)
    fun textAndFile(@Body body:MultipartBody):BaseBean<Any>

//根据上传的数据不同,组合成不同的MultipartBody
//文本+文件上传
fun getMultipartBody(params:Map<String,Any>,parts:List<MultipartBody.Part>):MultipartBody{
    val builder = MultipartBody.Builder()
    builder.setType(MultipartBody.FORM)
    params.forEach{
        builder.addFormDataPart(it.key,it.value.toString())
    }
    parts.forEach {
        builder.addPart(it)
    }
    return builder.build()
}

返回文件的mimetype

fun getMimeType(file: File):String? = URLConnection.getFileNameMap().getContentTypeFor(file.name)

//uri文件上传

android10之后,上传文件不可避免地需要调用uri,retrofit也支持直接上传uri,就像上传file一样,只需要重写RequestBody三个方法即可

定义一个UriRequestBody继承RequestBody,并且重写contentType(),writeTo(),contentLength()三个方法

class UriRequestBody(val context: Context, val uri: Uri):RequestBody(){
    override fun contentType(): MediaType = MediaType.get(context.contentResolver.getType(uri)?:"multipart/form-data")
    override fun writeTo(sink: BufferedSink) {
        val ips = context.contentResolver.openInputStream(uri)
        ips?.let {  sink.writeAll(Buffer().readFrom(it,contentLength())) }
    }
    override fun contentLength() = context.contentResolver.openFileDescriptor(uri,"r")?.statSize?:-1L
}

使用:生成上传文件的MultipartBody.Part参数

fun getpart(context: Context,name:String,fileName:String,uri:Uri): MultipartBody.Part{
    return MultipartBody.Part.createFormData(name,"",UriRequestBody(context,uri))
}

猜你喜欢

转载自blog.csdn.net/jingzz1/article/details/107151095
今日推荐