Retrofit總結(持續更新)

Get請求

@query

@Query會以key=value的方式拼接在url後面
Query非必填,如果請求參數非必填,可以傳null
如:https://api.douban.com/v2/movie/top250?start=0&count=10

ApiServer.kt

@GET("top250")
fun getTopMovie(@Query("start") start: Int, @Query("count") count: Int): Call<ResponseEntity>

MainActivity.kt

@OnClick(R.id.tv_main)
fun getTopMovie() {
        val retrofit = Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create())
                .baseUrl("https://api.douban.com/v2/movie/")
                .build()

        val apiService = retrofit.create(ApiServer::class.java)
        val call = apiService.getTopMovie(0, 10)
        call.enqueue(object : Callback<ResponseEntity> {
            override fun onFailure(call: Call<ResponseEntity>?, t: Throwable?) {

            }

            override fun onResponse(call: Call<ResponseEntity>?, response: Response<ResponseEntity>?) {
                Log.i("qfxl", "response = ${response?.body()}")
            }

        })
    }

@QueryMap

如果Query參數比較多,那麼可以通過@QueryMap方式將所有的參數集成在一個Map。
如:https://api.douban.com/v2/movie/top250?start=0&count=10
ApiServer.kt

@GET("top250")
fun getTopMovie(@QueryMap params: Map<String, String>): Call<ResponseEntity>

MainActivity.kt

 @OnClick(R.id.tv_main)
    fun getTopMovie() {
        val retrofit = Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create())
                .baseUrl("https://api.douban.com/v2/movie/")
                .build()

        val apiService = retrofit.create(ApiServer::class.java)
        val params = mapOf("start" to "0", "count" to "10")
        val call = apiService.getTopMovie(params)
        call.enqueue(object : Callback<ResponseEntity> {
            override fun onFailure(call: Call<ResponseEntity>?, t: Throwable?) {

            }
            override fun onResponse(call: Call<ResponseEntity>?, response: Response<ResponseEntity>?) {
                Log.i("qfxl", "response = ${response?.body()}")
            }

        })
    }

Query集合

假如需要添加相同Key值,但是value卻有多個的情況,一種方式是添加多個@Query參數,還有一種簡便的方式是將所有的value放置在列表中,然後在同一個@Query下完成添加
如:https://api.douban.com/v2/movie/top250?start=0&start=1
ApiServer.kt

 @GET("top250")
 fun getTopMovie(@Query("start") paramList: List<String>): Call<ResponseEntity>

MainActivity.kt

@OnClick(R.id.tv_main)
    fun getTopMovie() {
        val retrofit = Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create())
                .baseUrl("http://gank.io/api/data/")
                .build()

        val apiService = retrofit.create(ApiServer::class.java)
        val listParam = listOf("0","1")
        val call = apiService.getTopMovie(listParam)
        call.enqueue(object : Callback<ResponseEntity> {
            override fun onFailure(call: Call<ResponseEntity>?, t: Throwable?) {

            }

            override fun onResponse(call: Call<ResponseEntity>?, response: Response<ResponseEntity>?) {
                Log.i("qfxl", "response = ${response?.body()}")
            }

        })
    }

@Path

如果請求的相對地址也是需要調用方傳遞,那麼可以使用@Path註解
@Path可以用於任何請求方式,包括Post,Put,Delete等等
如:http://gank.io/api/data/Android/10/1
ApiServer.kt

@GET("Android/{pageSize}/{page}")
fun getAndroid(@Path("pageSize") pageSize: Int, @Path("page") page: Int): Call<ResponseEntity>

MainActivity.kt

@OnClick(R.id.tv_main)
    fun getAndroid() {
        val retrofit = Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create())
                .baseUrl("http://gank.io/api/data/")
                .build()

        val apiService = retrofit.create(ApiServer::class.java)
        val call = apiService.getAndroid(10, 1)
        call.enqueue(object : Callback<ResponseEntity> {
            override fun onFailure(call: Call<ResponseEntity>?, t: Throwable?) {

            }
            override fun onResponse(call: Call<ResponseEntity>?, response: Response<ResponseEntity>?) {
                Log.i("qfxl", "response = ${response?.body()}")
            }

        })
    }

#Post請求

@Field

Post請求需要把請求參數放置在請求體中,而非拼接在url後面。
如:https://gank.io/api/add2gank

字段 描述 備註
url 想要提交的網頁地址
desc 對乾貨內容的描述 單獨的文字描述
who 提交者 ID 乾貨提交者的網絡 ID
type 乾貨類型 可選參數: Android、iOS、休息視頻、福利、拓展資源、前端、瞎推薦、App
debug 當前提交爲測試數據 如果想要測試數據請設置 debug 爲 true! 可選參數: true、false

ApiServer.kt

@FormUrlEncoded
@POST("add2gank")
fun addToGank(@Field("url") url: String, @Field("desc") desc: String, @Field("who") who: String, @Field("type") type: String, @Field("debug") debug: Boolean): Call<ResponseEntity>

MainActivity.kt

 @OnClick(R.id.tv_main)
 fun addToGank() {
        val retrofit = Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create())
                .baseUrl("https://gank.io/api/")
                .build()
        val apiService = retrofit.create(ApiServer::class.java)
        val call = apiService.addToGank("http://gank.io/api", "test", "qfxl", "App", true)
        call.enqueue(object : Callback<ResponseEntity> {
            override fun onFailure(call: Call<ResponseEntity>?, t: Throwable?) {

            }
            override fun onResponse(call: Call<ResponseEntity>?, response: Response<ResponseEntity>?) {
                Log.i("qfxl", "response = ${response?.body()}")
            }

        })
    }

注:@FormUrlEncoded將會自動將請求參數的類型調整爲application/x-www-form-urlencoded
Field註解將每一個請求參數都存放至請求體中,還可以添加encoded參數,該參數爲boolean型,encoded參數爲true的話,key-value-pair將會被編碼,即將中文和特殊字符進行編碼轉換
如:

@FormUrlEncoded
@POST("add2gank")
fun addToGank(@Field("url", encoded = true) url: String):Call<ResponseEntity>

@FieldMap

假如有多個請求參數,這個時候就可以用FieldMap
如:https://gank.io/api/add2gank

字段 描述 備註
url 想要提交的網頁地址
desc 對乾貨內容的描述 單獨的文字描述
who 提交者 ID 乾貨提交者的網絡 ID
type 乾貨類型 可選參數: Android、iOS、休息視頻、福利、拓展資源、前端、瞎推薦、App
debug 當前提交爲測試數據 如果想要測試數據請設置 debug 爲 true! 可選參數: true、false

ApiServer.kt

@FormUrlEncoded
    @POST("add2gank")
    fun addToGank(@FieldMap mapParam: Map<String, String>, @Field("debug") debug: Boolean): Call<ResponseEntity>

MainActivity.kt

 @OnClick(R.id.tv_main)
    fun addToGank() {
        val retrofit = Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create())
                .baseUrl("https://gank.io/api/")
                .build()

        val apiService = retrofit.create(ApiServer::class.java)
        val mapParam = mapOf(
                "url" to "http://gank.io/api",
                "desc" to "test",
                "who" to "qfxl",
                "type" to "App"
        )
        val call = apiService.addToGank(mapParam, true)
        call.enqueue(object : Callback<ResponseEntity> {
            override fun onFailure(call: Call<ResponseEntity>?, t: Throwable?) {

            }
            override fun onResponse(call: Call<ResponseEntity>?, response: Response<ResponseEntity>?) {
                Log.i("qfxl", "response = ${response?.body()}")
            }

        })
    }

注意,Map泛型不接受Any(Java中的Object)

@Body

只針對Post請求,參數爲json形式的時候使用

上傳(帶進度)

定義上傳進度回調接口

interface UploadListener {
    /**
     * 上傳進度
     *
     * @param progress
     * @param total
     * @param done
     */
    fun onProgress(progress: Long, total: Long, done: Boolean)
}

改造RequestBody

class ProgressRequestBody(private val mRequestBody: RequestBody, private val mUploadListener: UploadListener) : RequestBody() {
    private var mCountingSink: CountingSink? = null

    override fun contentType(): MediaType? {
        return mRequestBody.contentType()
    }

    override fun contentLength(): Long {
        try {
            return mRequestBody.contentLength()
        } catch (e: IOException) {
            e.printStackTrace()
            return -1
        }

    }

    @Throws(IOException::class)
    override fun writeTo(sink: BufferedSink) {
        val bufferedSink: BufferedSink

        mCountingSink = CountingSink(sink)
        bufferedSink = Okio.buffer(mCountingSink!!)

        mRequestBody.writeTo(bufferedSink)
        bufferedSink.flush()
    }

    internal inner class CountingSink(delegate: Sink) : ForwardingSink(delegate) {

        private var bytesWritten: Long = 0

        @Throws(IOException::class)
        override fun write(source: Buffer, byteCount: Long) {
            super.write(source, byteCount)
            bytesWritten += byteCount
            mUploadListener.onProgress(bytesWritten, contentLength(), bytesWritten == contentLength())
        }
    }
}

定義上傳api

interface UploadApi {
    @Multipart
    @POST
    fun upload(@Url url: String, @Part parts: List<MultipartBody.Part>): Call<ResponseBody>
}

定義攔截器

class UploadInterceptor(private val uploadListener: UploadListener) : Interceptor {

    @Throws(IOException::class)
    override fun intercept(chain: Interceptor.Chain): Response {
        val originRequest = chain.request()
        if (null == originRequest.body()) {
            return chain.proceed(originRequest)
        }
        val newRequest = originRequest.newBuilder()
                .method(originRequest.method(), ProgressRequestBody(originRequest.body()!!, uploadListener))
                .build()
        return chain.proceed(newRequest)
    }
}

封裝上傳

class ZbyUploadManager private constructor() {
    private var mRetrofit: Retrofit? = null
    /**
     * 佔位BaseUrl
     */
    private val ZBY_CORP = "http://www.zbycorp.com/"
    /**
     * okHttp的攔截器
     */
    private val interceptors = SparseArray<Interceptor>()

    private var uploadListener: UploadListener? = null
    /**
     * 線程調度
     */
    private val dispatchHandler: Handler

    /**
     * 默認的Retrofit
     *
     * @return
     */
    private val defaultRetrofit: Retrofit
        get() = Retrofit.Builder()
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .baseUrl(ZBY_CORP)
                .client(defaultOkHttp)
                .build()

    /**
     * 默認的okHttpClient
     *
     * @return
     */
    //添加攔截器
    val defaultOkHttp: OkHttpClient
        get() {
            val builder = OkHttpClient.Builder()
            builder.readTimeout(3, TimeUnit.MINUTES)
                    .writeTimeout(3, TimeUnit.MINUTES)
                    .addInterceptor(UploadInterceptor(object : UploadListener {
                        override fun onProgress(progress: Long, total: Long, done: Boolean) {
                            val msg = Message.obtain()
                            msg.arg1 = progress.toInt()
                            msg.arg2 = total.toInt()
                            msg.obj = done
                            dispatchHandler.sendMessage(msg)
                        }

                    }))
            if (interceptorSize > 0) {
                for (i in 0 until interceptorSize) {
                    builder.addInterceptor(interceptors.get(i))
                }
            }
            return builder.build()
        }

    /**
     * 獲取Retrofit
     *
     * @return
     */
    /**
     * 設置Retrofit(如果有特殊需求的話)
     *
     * @param retrofit
     */
    var retrofit: Retrofit?
        get() = if (mRetrofit == null) {
            defaultRetrofit
        } else mRetrofit
        set(retrofit) = if (retrofit == null) {
            mRetrofit = defaultRetrofit
        } else {
            mRetrofit = retrofit
        }

    /**
     * 獲取攔截器數量
     *
     * @return
     */
    private val interceptorSize: Int
        get() = interceptors.size()

    init {
        dispatchHandler = Handler(Looper.getMainLooper(), Handler.Callback { msg ->
            val progress = msg.arg1.toLong()
            val total = msg.arg2.toLong()
            val done = msg.obj as Boolean
            if (uploadListener != null) {
                //如果需要轉換成100進度的話(100 * progress) / total
                uploadListener!!.onProgress(progress, total, done)
            }
            true
        })
    }

    private object Holder {
        val INSTANCE = ZbyUploadManager()
    }

    /**
     * 添加攔截器
     *
     * @param interceptor
     */
    fun addInterceptor(interceptor: Interceptor) {
        interceptors.put(interceptorSize, interceptor)
    }

    /**
     * 清空所有攔截器
     */
    fun clearInterceptors() {
        interceptors.clear()
    }

    /**
     * 移除指定攔截器
     *
     * @param key
     */
    fun clearInterceptorAt(key: Int) {
        interceptors.removeAt(key)
    }

    /**
     * 上傳
     *
     * @param url
     * @param uploadParams
     */
    fun upload(url: String, uploadParams: UploadParams, callback: Callback<ResponseBody>) {
        val uploadApi = retrofit?.create(UploadApi::class.java)
        val builder = MultipartBody.Builder()
        for (entry in uploadParams.entries) {
            if (entry.value is String) {
                builder.addFormDataPart(entry.key, entry.value)
            } else if (entry.value is File) {
                val file = entry.value
                builder.addFormDataPart(entry.key, file.name, RequestBody.create(MediaType.parse("multipart/form-data"), file))
            }
        }

        val body = builder.build()
        uploadApi?.upload(url, body.parts())
                ?.enqueue(callback)
    }


    /**
     * 上傳帶進度帶回調
     *
     * @param url
     * @param uploadParams
     * @param uploadListener
     * @param callback
     */
    fun upload(url: String, uploadParams: UploadParams, uploadListener: UploadListener, callback: Callback<ResponseBody>) {
        this.uploadListener = uploadListener
        val uploadApi = retrofit?.create(UploadApi::class.java)
        val builder = MultipartBody.Builder()
        for (entry in uploadParams.entries) {
            if (entry.value is String) {
                builder.addFormDataPart(entry.key, entry.value)
            } else if (entry.value is File) {
                val file = entry.value
                builder.addFormDataPart(entry.key, file.name, RequestBody.create(MediaType.parse("multipart/form-data"), file))
            }
        }

        val body = builder.build()
        uploadApi?.upload(url, body.parts())
                ?.enqueue(callback)
    }

    companion object {

        fun get(): ZbyUploadManager {
            return Holder.INSTANCE
        }
    }
}

##UploadParams

class UploadParams {

    val entries = ArrayList<Entry>()

    fun put(key: String, value: Any) {
        entries.add(Entry(key, value))
    }

    inner class Entry(val key: String, val value: Any)
}

下載(帶進度)

定義進度回調接口

interface ProgressListener {
    /**
     * 進度監聽
     *
     * @param progress 當前上傳下載字節數
     * @param total    總的字節數
     * @param done     是否完成
     */
    fun onProgress(progress: Long, total: Long, done: Boolean)
}

改造ResponseBody

class ProgressResponseBody(private val responseBody: ResponseBody, private val progressListener: ProgressListener) : ResponseBody() {
    private var bufferedSource: BufferedSource? = null

    override fun contentType(): MediaType? {
        return responseBody.contentType()
    }

    override fun contentLength(): Long {
        return responseBody.contentLength()
    }

    override fun source(): BufferedSource? {
        if (bufferedSource == null) {
            bufferedSource = Okio.buffer(source(responseBody.source()))
        }
        return bufferedSource
    }

    private fun source(source: Source): Source {
        return object : ForwardingSource(source) {
            internal var totalBytesRead = 0L

            @Throws(IOException::class)
            override fun read(sink: Buffer, byteCount: Long): Long {
                val bytesRead = super.read(sink, byteCount)
                totalBytesRead += if (bytesRead != -1L) bytesRead else 0
                progressListener.onProgress(totalBytesRead, responseBody.contentLength(), bytesRead == -1L)
                return bytesRead
            }
        }
    }
}

定義下載API

interface DownloadApi {
    /**
     * 下載
     *
     * @param url 下載的url
     * @return
     */
    @GET
    fun download(@Url url: String): Call<ResponseBody>
}

下載並保存到本地

class DownloadManager {
    private val TAG = DownloadManager::class.java.simpleName
    private var mRetrofit: Retrofit? = null
    /**
     * 進度監聽
     */
    private var mProgressListener: ProgressListener? = null
    /**
     * 佔位BaseUrl
     */
    private val ZBY_CORP = "http://www.zbycorp.com/"
    /**
     * 線程調度
     */
    private val dispatchHandler: Handler
    /**
     * okHttp的攔截器
     */
    private val interceptors = SparseArray<Interceptor>()
    /**
     * 下載回調
     */
    var onDownloadListener: OnDownloadListener? = null
    /**
     * 默認的Retrofit
     *
     * @return
     */
    private val defaultRetrofit: Retrofit
        get() = Retrofit.Builder()
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .baseUrl(ZBY_CORP)
                .client(defaultOkHttp)
                .build()

    /**
     * 獲取攔截器數量
     *
     * @return
     */
    private val interceptorSize: Int
        get() = interceptors.size()

    /**
     * 默認的okHttpClient
     *
     * @return
     */
    //將進度回調到主線程
    //添加攔截器
    val defaultOkHttp: OkHttpClient
        get() {
            val builder = OkHttpClient.Builder()
            builder.readTimeout(3, TimeUnit.MINUTES)
                    .writeTimeout(3, TimeUnit.MINUTES)
                    .networkInterceptors()
                    .add(Interceptor { chain ->
                        val originalResponse = chain.proceed(chain.request())
                        originalResponse.newBuilder().body(
                                ProgressResponseBody(originalResponse.body()!!, object : ProgressListener {
                                    override fun onProgress(progress: Long, total: Long, done: Boolean) {
                                        val msg = Message.obtain()
                                        msg.arg1 = progress.toInt()
                                        msg.arg2 = total.toInt()
                                        msg.obj = done
                                        dispatchHandler.sendMessage(msg)
                                    }

                                })).build()
                    })
            if (interceptorSize > 0) {
                for (i in 0 until interceptorSize) {
                    builder.addInterceptor(interceptors.get(i))
                }
            }
            return builder.build()
        }

    /**
     * 獲取Retrofit
     *
     * @return
     */
    /**
     * 設置Retrofit(如果有特殊需求的話)
     *
     * @param retrofit
     */
    var retrofit: Retrofit?
        get() = if (mRetrofit == null) {
            defaultRetrofit
        } else mRetrofit
        set(retrofit) = if (retrofit == null) {
            mRetrofit = defaultRetrofit
        } else {
            mRetrofit = retrofit
        }

    init {
        dispatchHandler = Handler(Looper.getMainLooper(), Handler.Callback { msg ->
            val progress = msg.arg1.toLong()
            val total = msg.arg2.toLong()
            val done = msg.obj as Boolean
            if (mProgressListener != null) {
                //如果需要轉換成100進度的話(100 * progress) / total
                mProgressListener!!.onProgress(progress, total, done)
            }
            true
        })
    }

    /**
     * 添加攔截器
     *
     * @param interceptor
     */
    fun addInterceptor(interceptor: Interceptor) {
        interceptors.put(interceptorSize, interceptor)
    }

    /**
     * 清空所有攔截器
     */
    fun clearInterceptors() {
        interceptors.clear()
    }

    /**
     * 移除指定攔截器
     *
     * @param key
     */
    fun removeInterceptorAt(key: Int) {
        interceptors.removeAt(key)
    }

    /**
     * 下載帶進度
     *
     * @param url              下載的url
     * @param progressListener 進度監聽
     * @param destFile         存儲目標文件
     */
    fun download(url: String, progressListener: ProgressListener, destFile: File?) {
        mProgressListener = progressListener
        val downloadApi = retrofit!!.create(DownloadApi::class.java)
        downloadApi.download(url)
                .enqueue(object : Callback<ResponseBody> {
                    override fun onResponse(call: retrofit2.Call<ResponseBody>, response: Response<ResponseBody>) {
                        saveFileToLocal(destFile, response.body())
                        onDownloadListener?.onDownloadSuccess(destFile!!)
                    }

                    override fun onFailure(call: retrofit2.Call<ResponseBody>, t: Throwable) {
                        onDownloadListener?.onDownloadFailed(t.message!!)
                    }
                })
    }

    /**
     * 下載不帶進度
     *
     * @param url      下載的url
     * @param destFile 存儲目標文件
     */
    fun download(url: String, destFile: File?) {
        val downloadApi = retrofit!!.create(DownloadApi::class.java)
        downloadApi.download(url)
                .enqueue(object : Callback<ResponseBody> {
                    override fun onResponse(call: retrofit2.Call<ResponseBody>, response: Response<ResponseBody>) {
                        saveFileToLocal(destFile, response.body())
                        onDownloadListener?.onDownloadSuccess(destFile!!)
                    }

                    override fun onFailure(call: retrofit2.Call<ResponseBody>, t: Throwable) {
                        onDownloadListener?.onDownloadFailed(t.message!!)
                    }
                })
    }

    /**
     * 保存文件到本地
     *
     * @param destFile     目標文件
     * @param responseBody 響應體
     */
    private fun saveFileToLocal(destFile: File?, responseBody: ResponseBody?) {
        if (responseBody != null && destFile != null) {
            val ins = responseBody.byteStream()
            destFile.writeBytes(ins.readBytes())
            ins.close()
        }
    }

    interface OnDownloadListener {
        /**
         * 下載成功回調
         */
        fun onDownloadSuccess(file: File)

        /**
         * 下載失敗回調
         */
        fun onDownloadFailed(errorMsg: String)
    }
}

使用

val downloadManager = ZbyDownloadManager()
downloadManager.setOnDownloadListener(object : ZbyDownloadManager.OnDownloadListener {
            override fun downloadSuccess(destFile: File) {
              
            }

            override fun downloadFailed(errorMsg: String) {
          
            }
        })
        val destFileFolder = File(Environment.getExternalStorageDirectory(), "apks")
        if (!destFileFolder.exists()) {
            destFileFolder.mkdirs()
        }
        val destFile = File(destFileFolder, "iWMS.apk")
        downloadManager.download("http://192.168.8.104:8080/apks/iwms.apk", { progress, total, done ->
            updateDialog?.setProgress(((100 * progress) / total).toInt())            
        }, destFile)

參數加密

加密規則
所有請求添加公用參數如下:

client_id=android
ts=時間戳
dev=imei
req_id=uuid
sign=所有參數(不包含sign參數)按key自然升序排序,然後拼接kv(如:a1b2c3),1次md5,全部轉大寫,最後1次md5
MD5(UPPER(MD5(a1b2c3client_idandroiddevuuidts1234567890)))

java代碼如下(晚點改爲kotlin)


public class AddParamsInterceptor implements Interceptor {
    /**
     * 公用參數
     */
    private Map<String, String> commonParams = new ArrayMap<>();
    private Context context;

    public AddParamsInterceptor(Context context) {
        String timestamp = String.valueOf(TimeUtils.getServerCurrentTimeMillis());
        String imei = CommonUtil.isEmpty(DeviceUuidFactory.getInstance()
                .getIMEI(context)) ? "" : DeviceUuidFactory.getInstance()
                .getIMEI(context);
        commonParams.put("client_id", "android_mobile");
        commonParams.put("ts", timestamp);
        commonParams.put("dev", imei);
        commonParams.put("req_id", DeviceUuidFactory.getInstance()
                .getDeviceUuidString(context));
        this.context = context;
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request orgRequest = chain.request();
        RequestBody body = orgRequest.body();
        String accessToken = (String) SpUtil.get(context, SpUtil.FILE_USER, SpUtil.KEY_USER_ACCESS_TOKEN, "");
        //收集請求參數,最後用於sign簽名
        StringBuilder paramsBuilder = new StringBuilder();
        if (body != null) {
            RequestBody newBody = null;
            if (body instanceof FormBody) {
                newBody = addParamsToFormBody((FormBody) body, paramsBuilder);
            } else if (body instanceof MultipartBody) {
                newBody = addParamsToMultipartBody((MultipartBody) body, paramsBuilder);
            }
            if (null != newBody) {
                Request.Builder requestBuilder = orgRequest.newBuilder();
                //添加authorization
                if (!TextUtils.isEmpty(accessToken)) {
                    requestBuilder.addHeader("Authorization", accessToken);
                }
                requestBuilder.url(orgRequest.url())
                        .method(orgRequest.method(), newBody)
                        .build();
                return chain.proceed(requestBuilder.build());
            }
        } else {
            if (!TextUtils.isEmpty(orgRequest.method()) && "get".equals(orgRequest.method().toLowerCase())) {
                HttpUrl.Builder authorizedUrlBuilder = orgRequest.url()
                        .newBuilder()
                        .scheme(orgRequest.url().scheme())
                        .host(orgRequest.url().host());
                if (commonParams == null || commonParams.size() == 0) {
                    return chain.proceed(orgRequest);
                }
                Iterator iter = commonParams.entrySet().iterator();
                List<String> keyList = new ArrayList<>();
                ArrayMap<String, String> paramMap = new ArrayMap<>();
                //公用參數
                while (iter.hasNext()) {
                    Map.Entry entry = (Map.Entry) iter.next();
                    keyList.add(entry.getKey().toString());
                    paramMap.put(entry.getKey().toString(), entry.getValue().toString());
                }
                //原始參數
                int originParamsSize = orgRequest.url().queryParameterNames().size();
                for (int i = 0; i < originParamsSize; i++) {
                    String key = orgRequest.url().queryParameterName(i);
                    String value = orgRequest.url().queryParameter(key);
                    keyList.add(key);
                    paramMap.put(key, value);
                }

                Collections.sort(keyList);
                int keySize = keyList.size();
                //添加公用參數
                for (int i = 0; i < keySize; i++) {
                    //防止重複添加k=v
                    if (TextUtils.isEmpty(orgRequest.url().queryParameter(keyList.get(i)))) {
                        authorizedUrlBuilder.addQueryParameter(keyList.get(i), paramMap.get(keyList.get(i)));
                    }
                    paramsBuilder.append(keyList.get(i))
                            .append(paramMap.get(keyList.get(i)));
                }
                //所有參數的k=v
                String originParamStr = paramsBuilder.toString();
                String md5Sign = CommonUtil.getMD5(CommonUtil.getMD5(originParamStr)
                        .toUpperCase());
                authorizedUrlBuilder.addQueryParameter("sign", md5Sign);
                // 新的請求
                Request.Builder requestBuilder = orgRequest.newBuilder();
                //添加authorization
                if (!TextUtils.isEmpty(accessToken)) {
                    requestBuilder.addHeader("Authorization", accessToken);
                }
                requestBuilder.method(orgRequest.method(), orgRequest.body())
                        .url(authorizedUrlBuilder.build())
                        .build();
                return chain.proceed(requestBuilder.build());
            }
        }
        return chain.proceed(orgRequest);
    }

    /**
     * 爲MultipartBody類型請求體添加參數
     *
     * @param body
     * @param paramsBuilder
     * @return
     */
    private MultipartBody addParamsToMultipartBody(MultipartBody body, StringBuilder paramsBuilder) {
        MultipartBody.Builder builder = new MultipartBody.Builder();
        builder.setType(MultipartBody.FORM);
        List<String> keyList = new ArrayList<>();
        ArrayMap<String, String> paramsMap = new ArrayMap<>();
        //動態添加新的參數
        if (commonParams == null || commonParams.size() == 0) {
            return builder.build();
        }
        Iterator iter = commonParams.entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry entry = (Map.Entry) iter.next();
            keyList.add(entry.getKey().toString());
            paramsMap.put(entry.getKey().toString(), entry.getValue().toString());
        }
        Collections.sort(keyList);
        int keySize = keyList.size();
        for (int i = 0; i < keySize; i++) {
            builder.addFormDataPart(keyList.get(i), paramsMap.get(keyList.get(i)));
            paramsBuilder.append(keyList.get(i))
                    .append(paramsMap.get(keyList.get(i)));
        }
        //所有參數的k=v
        String originParamStr = paramsBuilder.toString();
        String md5Sign = CommonUtil.getMD5(CommonUtil.getMD5(originParamStr)
                .toUpperCase());
        //添加sign
        builder.addFormDataPart("sign", md5Sign);
        //添加原請求體
        for (int i = 0; i < body.size(); i++) {
            builder.addPart(body.part(i));
        }
        return builder.build();
    }

    /**
     * 爲FormBody類型請求體添加參數
     *
     * @param body
     * @param paramsBuilder
     * @return
     */
    private FormBody addParamsToFormBody(FormBody body, StringBuilder paramsBuilder) {
        FormBody.Builder builder = new FormBody.Builder();
        //動態添加新的參數
        if (commonParams == null || commonParams.size() == 0) {
            return builder.build();
        }
        Iterator iter = commonParams.entrySet().iterator();
        List<String> keyList = new ArrayList<>();
        ArrayMap<String, String> paramsMap = new ArrayMap<>();
        while (iter.hasNext()) {
            Map.Entry entry = (Map.Entry) iter.next();
            keyList.add(entry.getKey().toString());
            paramsMap.put(entry.getKey().toString(), entry.getValue().toString());
        }
        //添加原請求體
        for (int i = 0; i < body.size(); i++) {
            keyList.add(body.encodedName(i));
            paramsMap.put(body.encodedName(i), body.encodedValue(i));
        }
        Collections.sort(keyList);
        int keySize = keyList.size();
        for (int i = 0; i < keySize; i++) {
            builder.addEncoded(keyList.get(i), paramsMap.get(keyList.get(i)));
            paramsBuilder.append(keyList.get(i))
                    .append(paramsMap.get(keyList.get(i)));
        }
        //所有請求參數的k=v
        String originParamStr = paramsBuilder.toString();
        String md5Sign = CommonUtil.getMD5(CommonUtil.getMD5(originParamStr)
                .toUpperCase());
        builder.addEncoded("sign", md5Sign);
        return builder.build();
    }
    
}

最後添加到okHttp的攔截器中。

okHttpClientBuilder.addInterceptor(new AddParamsInterceptor(context));
發佈了75 篇原創文章 · 獲贊 127 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章