retrofit + rxjava 獲取網路資料(以獲取帆軟token作為例子)

語言: CN / TW / HK

retrofit + rxjava 獲取網路資料(以獲取帆軟token作為例子)

技術介紹

本文使用retrofit + rxjava 通過相關url獲取資料並處理,語言使用的是kotlin,構建工具使用maven。以帆軟介面作為例子,帆軟介面返回的其實是jsonp的格式,後端獲取時型別為String

過程介紹

1. 建立服務的介面api物件

interface FineReportApi {

    @GET
    fun getFineReportData(@Url url: String, @Nullable @QueryMap map: HashMap<String, String>): Observable<String>

}

其中@GET表示請求介面方式為get,@Url為請求路徑的相對url(注意,這裡是相對,因為基礎地址我們會在另外一個地方配置。),@QueryMap為查詢引數,此處我們可以以一個HashMap形式直接傳遞。

2. retrofit 具體請求過程

// 此處為log日誌攔截器,可以顯示具體的請求日誌資訊
private val logInterceptor = HttpLoggingInterceptor().apply {
        this.level = HttpLoggingInterceptor.Level.BODY
    }
    
 private val client = OkHttpClient.Builder()
            .addInterceptor(logInterceptor)
            .callTimeout(1, TimeUnit.MINUTES)
            .connectTimeout(1, TimeUnit.MINUTES)
            .readTimeout(1, TimeUnit.MINUTES)
            .writeTimeout(1, TimeUnit.MINUTES)
            .build()
            
            
private fun buildApi(baseUrl: String): FineReportApi {

        return Retrofit.Builder()
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .addConverterFactory(ScalarsConverterFactory.create())
                 //此處需要以‘/’結尾
                .baseUrl(baseUrl)
                .client(client)
                .build()
                .create(FineReportApi::class.java)
    }

注意上面建立FineReportApi物件時addCallAdapterFactory方法新增的是RxJavaCallAdapterFactory,因為介面卡用的是rxjava,而addConverterFactory用的是ScalarsConverterFactory因為我們在FineReportApi介面中返回的是Observable<String>,此處實際轉換的物件是String,不是傳統的json,這和介面的返回值有關。而ScalarsConverterFactory類中實際起作用程式碼如下:

if (type == String.class) {
      return StringResponseBodyConverter.INSTANCE;
    }
/**
     * 獲取帆軟token
     * @param apiInfo ApiInfo
     * @return String?
     */
    fun getFineReportToken(apiInfo: ApiInfo): String? {


        if (StringUtils.isEmpty(apiInfo.baseUrl)) {
            throw IllegalStateException("base url 資訊不能為空!")
        }

        if (StringUtils.isEmpty(apiInfo.credUrl)) {
            throw IllegalStateException("cred url 資訊不能為空!")
        }


        // 此處的map引數為帆軟介面的固定引數
        val paramMap = hashMapOf<String, String>()
        paramMap["fine_username"] = apiInfo.userName
        paramMap["fine_password"] = apiInfo.password
        paramMap["validity"] = "-2"

        val apiObs: Observable<String> =
                api(apiInfo.baseUrl).getFineReportData(apiInfo.credUrl, paramMap)


        var token: String? = null

        apiObs.observeOn(Schedulers.immediate())
                .subscribe ({
                    val result = it

                    val gson = Gson()
                    // 擷取返回的字串並轉成HashMap物件
                    val json = JsonParser().parse(result.substring(result.indexOf("{"),
                            result.lastIndexOf(")"))).asJsonObject

                    val map = gson.fromJson(json, HashMap::class.java)

                    // 對於這個介面,如果有值的話肯定在accessToken裡面
                    if (null == map["accessToken"]) {
                        throw IllegalStateException("無法獲取token!")
                    }

                    token = map["accessToken"] as String
                },{
                    mLogger.error(it.message)
                    throw Exceptions.propagate(it)
                }, {
                    mLogger.info("獲取token完成,【$token】")
                })


        return token

    }

其中ApiInfo類如下:

@JsonIgnoreProperties(ignoreUnknown = true)
public class ApiInfo {
    private String baseUrl;
    private String relaUrl;
    private HashMap<String, String> params;
    private String method;
    private String cred;
    private String credUrl;
    private String userName;
    private String password;
    private String token;
// 省略 get 和 set 方法
}

請求引數如下:

{"baseUrl":"http://ip:port/webreport/decision/","relaUrl":"v10/entries/all","params":{},"method":"GET","credUrl":"login/cross/domain","userName":"yourName","password":"yourPassword"}

其中baseUrl為基礎地址,credUrl為要獲取token的相對地址,relaUrl是我要採集實際資料的相對地址,但是隻有獲取token之後才可以訪問該介面。

以上,我可以就可以獲取帆軟獲取token介面資料了,將獲取的字串擷取並獲取實際的token值。

值得一提的是其實這些程式碼也是在我之前同事寫的類似程式碼的基礎上迭代的。

依賴版本

<properties>
    <kotlin.version>1.4.10</kotlin.version>
</properties>

<!--Retrofit2 related start-->
        <dependency>
            <groupId>com.squareup.retrofit2</groupId>
            <artifactId>retrofit</artifactId>
            <version>2.5.0</version>
        </dependency>
        <dependency>
            <groupId>com.squareup.retrofit2</groupId>
            <artifactId>adapter-rxjava</artifactId>
            <version>2.5.0</version>
        </dependency>
        <dependency>
            <groupId>com.squareup.retrofit2</groupId>
            <artifactId>converter-gson</artifactId>
            <version>2.5.0</version>
        </dependency>
        <dependency>
            <groupId>com.squareup.retrofit2</groupId>
            <artifactId>converter-jackson</artifactId>
            <version>2.5.0</version>
        </dependency>
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>logging-interceptor</artifactId>
            <version>3.12.0</version>
        </dependency>

        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>3.12.0</version>
        </dependency>

        <dependency>
            <groupId>com.squareup.retrofit2</groupId>
            <artifactId>converter-scalars</artifactId>
            <version>2.2.0</version>
        </dependency>
        <!--Retrofit2 related end-->


        <!--kotlin support-->
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-reflect</artifactId>
        </dependency>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-maven-allopen</artifactId>
            <version>${kotlin.version}</version>
        </dependency>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-test-junit</artifactId>
            <version>${kotlin.version}</version>
        </dependency>

        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-stdlib-jdk8</artifactId>
            <version>${kotlin.version}</version>
        </dependency>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-test</artifactId>
            <version>${kotlin.version}</version>
            <scope>test</scope>
        </dependency>
        <!-- kotlin end-->
分享到: