封装目录结构
1.首先安装类库
api 'com.squareup.okhttp3:okhttp:3.11.0'
api 'com.zhy:okhttputils:2.6.2'
//Rxlifecycle
api 'com.trello:rxlifecycle:0.3.1'
api 'com.trello:rxlifecycle-components:0.3.1'
api 'com.github.bumptech.glide:glide:4.8.0'
api 'com.squareup.retrofit2:converter-gson:2.+'
//必须使用
api 'com.lzy.net:okgo:3.0.4'
api 'com.squareup.okio:okio:1.5.0'
api 'io.reactivex.rxjava2:rxjava:2.2.2'
api 'io.reactivex.rxjava2:rxandroid:2.1.0'
api 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.+'
api 'com.squareup.retrofit2:retrofit:2.+'
api 'com.squareup.okhttp3:logging-interceptor:3.11.0'
api 'com.squareup.retrofit2:converter-gson:2.+'
api 'com.squareup.retrofit2:converter-scalars:2.0.0'
api 'com.facebook.stetho:stetho:1.4.2'
api 'com.facebook.stetho:stetho-okhttp3:1.4.2'
// 依赖以下两个库,会自动引用基础库与Android库
api 'com.trello.rxlifecycle2:rxlifecycle-components:2.1.0'
api 'com.trello.rxlifecycle2:rxlifecycle-navi:2.1.0'
api 'com.tbruyelle.rxpermissions:rxpermissions:0.7.0@aar'
api 'com.jakewharton.rxbinding:rxbinding:1.+'
// Lifecycles, LiveData 和 ViewModel
//implementation "android.arch.lifecycle:runtime:1.0.0-alpha5"
api "android.arch.lifecycle:extensions:1.1.0"
// 对 RxJava 的支持
api "android.arch.persistence.room:rxjava2:1.0.0-alpha5"
2.创建常量类
[——建议将这个类放在config文件夹——]
package com.ylink.https.config;
/**
* 全局常量
*
* @author twilight
* @Time 2019-07-21
*/
public class HttpsConstant {
/**
* 请求后台的所有API接口都在这里配置;统一管理
*/
public static class Server {
//服务器超时时间 16 秒
public final static int TIME_OUT = 30;
//测试服务器地址
public static final String ROOT_URL = "https://host:port/mobile-adapter/rest/merchant/app/"; //payapisit.fuxunpay.com
// public static final String ROOT_URL = "http://host:port/hibi-mobile-adapter/rest/merchant/app/";
}
/**
* 服务器返回的状态码
*/
public static class RespCode {
//处理成功
public static final String R000 = "R000";
//登录超时
public static final String R097 = "R097";
//令牌无效
public static final String R098 = "R098";
}
/**
* 全局静态变量
*/
public static class Param {
}
/**
* sp 常量
*/
public static class SP {
public static final String SP = "sp";//sp
public static final String SESSION_ID = "session_id";//
}
/**
* 全局常量
*/
public static class FINALVALUE {
}
}
3.创建错误处理类
[——建议将这个类放在exception文件夹——]
package com.ylink.https.exception;
/**
* 前端自定义Exception
*/
public class ApiException extends Exception {
private String statusCode;//错误码
private String statusDesc;//错误信息
public ApiException(Throwable throwable, String statusCode) {
super(throwable);
this.statusCode = statusCode;
}
public ApiException(String statusCode, String statusDesc) {
this.statusCode = statusCode;
this.statusDesc = statusDesc;
}
public String getStatusCode() {
return statusCode;
}
public void setStatusCode(String statusCode) {
this.statusCode = statusCode;
}
public String getStatusDesc() {
return statusDesc;
}
public void setStatusDesc(String statusDesc) {
this.statusDesc = statusDesc;
}
}
package com.ylink.https.exception;
/**
* 服务器返回的Exception
*/
public class ServerException extends RuntimeException {
private String statusCode;//错误码
private String statusDesc;//错误信息
public ServerException(String statusCode, String statusDesc) {
this.statusCode = statusCode;
this.statusDesc = statusDesc;
}
public String getStatusCode() {
return statusCode;
}
public void setStatusCode(String statusCode) {
this.statusCode = statusCode;
}
public String getStatusDesc() {
return statusDesc;
}
public void setStatusDesc(String statusDesc) {
this.statusDesc = statusDesc;
}
}
package com.ylink.https.exception;
import android.net.ParseException;
import android.util.MalformedJsonException;
import com.google.gson.JsonParseException;
import org.json.JSONException;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import retrofit2.HttpException;
public class ExceptionEngine {
//客户端报错
public static final int UN_KNOWN_ERROR = 9000;//未知错误
public static final int ANALYTIC_SERVER_DATA_ERROR = 9001;//解析(服务器)数据错误
public static final int ANALYTIC_CLIENT_DATA_ERROR = 9002;//解析(客户端)数据错误
public static final int CONNECT_ERROR = 9003;//网络连接错误
public static final int TIME_OUT_ERROR = 9004;//网络连接超时
public static final int UNKNOWNHOSTEXCEPTION = 9005;//网络连接超时
public static ApiException handleException(Throwable e) {
ApiException ex;
if (e instanceof HttpException) { //HTTP错误
HttpException httpExc = (HttpException) e;
ex = new ApiException(e, String.valueOf(httpExc.code()));
ex.setStatusDesc("网络错误,请稍后再试"); //均视为网络错误
return ex;
} else if (e instanceof ServerException) { //服务器返回的错误
ServerException serverExc = (ServerException) e;
ex = new ApiException(serverExc, serverExc.getStatusCode());
ex.setStatusDesc(serverExc.getStatusDesc());
return ex;
} else if (e instanceof JsonParseException
|| e instanceof JSONException
|| e instanceof ParseException || e instanceof MalformedJsonException) { //解析数据错误
ex = new ApiException(e, String.valueOf(ANALYTIC_SERVER_DATA_ERROR));
ex.setStatusDesc("客户端异常,请稍后再试");
return ex;
} else if (e instanceof ConnectException) {//连接网络错误
ex = new ApiException(e, String.valueOf(CONNECT_ERROR));
ex.setStatusDesc("网络连接错误,请稍后再试");
return ex;
} else if (e instanceof SocketTimeoutException) {//网络超时
ex = new ApiException(e, String.valueOf(TIME_OUT_ERROR));
ex.setStatusDesc("网络连接超时,请稍后再试");
return ex;
}
else if (e instanceof UnknownHostException) {//网络异常
ex = new ApiException(e, String.valueOf(UNKNOWNHOSTEXCEPTION));
ex.setStatusDesc("网络异常,请检查您的网络连接");
return ex;
}
else { //未知错误
ex = new ApiException(e, String.valueOf(UN_KNOWN_ERROR));
ex.setStatusDesc("系统异常,请稍后再试");
return ex;
}
}
}
4.创建DTO、VO、Subscriber、Repository基类
[——建议将这些类放在base文件夹——]
package com.ylink.https.base;
/**
* 服务器返回公共实体
*
* @param <T>
* @author twilight
* @Time 2019-07-21
*/
public class BaseDto<T> {
private String statusCode;
private String statusDesc;
private T data;
public String getStatusCode() {
return statusCode;
}
public void setStatusCode(String statusCode) {
this.statusCode = statusCode;
}
public String getStatusDesc() {
return statusDesc;
}
public void setStatusDesc(String statusDesc) {
this.statusDesc = statusDesc;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
package com.ylink.https.base;
import java.io.Serializable;
/**
* 请求服务器的公共参数
* 如果有需要可以在这添加公共参数
*
* @author twilight
* @Time 2019-07-21
*/
public class BaseVo implements Serializable {
}
package com.ylink.https.base;
import android.arch.lifecycle.MutableLiveData;
import android.content.Intent;
import android.os.Handler;
import android.util.Log;
import com.ylink.commons.CommonsContext;
import com.ylink.commons.config.CommonsConstant;
import com.ylink.commons.utils.AppManager;
import com.ylink.https.config.HttpsConstant;
import com.ylink.https.exception.ApiException;
import com.ylink.https.exception.ExceptionEngine;
import com.ylink.https.exception.ServerException;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
/**
* 自定义请服务器被观察者
*
* @author twilight
* @Time 2019-07-21
*/
public class BaseHttpSubscriber<T> implements Subscriber<BaseDto<T>> {
//异常类
private ApiException ex;
public BaseHttpSubscriber() {
data = new MutableLiveData();
}
private MutableLiveData<BaseDto<T>> data;
public MutableLiveData<BaseDto<T>> get() {
return data;
}
public void set(BaseDto<T> t) {
this.data.setValue(t);
}
public void onFinish(BaseDto<T> t) {
set(t);
}
@Override
public void onSubscribe(Subscription s) {
// 观察者接收事件 = 1个
s.request(1);
}
@Override
public void onNext(BaseDto<T> t) {
if (t.getStatusCode().equals(HttpsConstant.RespCode.R000)) {
onFinish(t);
} else if(t.getStatusCode().equals(HttpsConstant.RespCode.R097) || //登录超时,重新登录
t.getStatusCode().equals(HttpsConstant.RespCode.R098)){ //令牌无效
CommonsContext.getInstance().reLogin();
AppManager.getInstance().finishAllActivity();//结束所有页面
} else{
ex = ExceptionEngine.handleException(new ServerException(t.getStatusCode(), t.getStatusDesc()));
getErrorDto(ex);
}
}
@Override
public void onError(Throwable t) {
ex = ExceptionEngine.handleException(t);
getErrorDto(ex);
}
/**
* 初始化错误的dto
*
* @param ex
*/
private void getErrorDto(ApiException ex) {
BaseDto dto = new BaseDto();
dto.setStatusCode(ex.getStatusCode());
dto.setStatusDesc(ex.getStatusDesc());
onFinish((BaseDto<T>) dto);
}
@Override
public void onComplete() {
}
}
package com.ylink.https.base;
import io.reactivex.Flowable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
/**
* Repository基类
*
* @author twilight
* @Time 2019-07-21
*/
public class BaseRepository {
/**
* 请求网络
* @param flowable
* @param <T>
* @return
*/
public <T> BaseHttpSubscriber<T> request(Flowable<BaseDto<T>> flowable){
BaseHttpSubscriber<T> baseHttpSubscriber = new BaseHttpSubscriber<>(); //RxJava Subscriber回调
flowable.subscribeOn(Schedulers.io()) //解决背压
.observeOn(AndroidSchedulers.mainThread())
.subscribe(baseHttpSubscriber);
return baseHttpSubscriber;
}
}
5.创建拦截器
[——建议将这个类放在interceptor文件夹——]
package com.ylink.https.interceptor;
import android.util.Log;
import com.alibaba.fastjson.JSONObject;
import com.ylink.commons.utils.SPUtil;
import com.ylink.https.config.HttpsConstant;
import java.io.IOException;
import java.util.List;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
/**
* 自定义拦截器刷新sessionId 非首次请求的处理
* @author twilight
* @Time 2019-07-21
*/
public class AddCookiesInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request.Builder builder = chain.request().newBuilder();
String cookieStr = SPUtil.getData(HttpsConstant.SP.SP, HttpsConstant.SP.SESSION_ID, String.class, null);
List<String> cookies = JSONObject.parseArray(cookieStr, String.class);
if (cookies != null) {
for (String cookie : cookies) {
builder.addHeader("Cookie", cookie);
Log.v("OkHttp", "Adding Header: " + cookie); // This is done so I know which headers are being added; this interceptor is used after the normal logging of OkHttp
}
}
return chain.proceed(builder.build());
}
}
package com.ylink.https.interceptor;
import com.alibaba.fastjson.JSONObject;
import com.ylink.commons.utils.SPUtil;
import com.ylink.https.config.HttpsConstant;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import okhttp3.Interceptor;
import okhttp3.Response;
/**
* 自定义拦截器刷新sessionId 首次请求的处理
* @author twilight
* @Time 2019-07-21
*/
public class ReceivedCookiesInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());
if (!originalResponse.headers("Set-Cookie").isEmpty()) {
List<String> cookies = new ArrayList<>();
for (String header : originalResponse.headers("Set-Cookie")) {
cookies.add(header);
}
String cookieStr = JSONObject.toJSONString(cookies);
SPUtil.putData(HttpsConstant.SP.SP, HttpsConstant.SP.SESSION_ID, cookieStr);
}
return originalResponse;
}
}
6.创建请求类
[——建议将这个类放在http文件夹——]
package com.ylink.https.http;
import android.util.Log;
import com.facebook.stetho.okhttp3.StethoInterceptor;
import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import com.ylink.https.config.HttpsConstant;
import com.ylink.https.interceptor.AddCookiesInterceptor;
import com.ylink.https.interceptor.ReceivedCookiesInterceptor;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
/**
* 普通的网络请求用到的Retrofit
*/
public class RequetRetrofit {
private static final String TAG = "RequetRetrofit";
/**
* 创建okhttp相关对象
*/
private static OkHttpClient okHttpClient;
/**
* 创建Retrofit相关对象
*/
private static Retrofit retrofit;
public static <T> T getInstance(final Class<T> service) {
if (okHttpClient == null) {
synchronized (RequetRetrofit.class) {
if(okHttpClient == null) {
/**
* 创建okhttp相关对象
*/
okHttpClient = new OkHttpClient.Builder()
.addInterceptor(new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
@Override
public void log(String message) { //访问网络请求,和服务端响应请求时。将数据拦截并输出
Log.e(TAG, "log: " + message);
}
}).setLevel(HttpLoggingInterceptor.Level.BODY)) //Log等级
.connectTimeout(HttpsConstant.Server.TIME_OUT, TimeUnit.SECONDS) //超时时间
.readTimeout(HttpsConstant.Server.TIME_OUT, TimeUnit.SECONDS)
.writeTimeout(HttpsConstant.Server.TIME_OUT, TimeUnit.SECONDS)
.addNetworkInterceptor(new StethoInterceptor())
.addInterceptor(new AddCookiesInterceptor()) //
.addInterceptor(new ReceivedCookiesInterceptor())
.build();
}
}
}
if (retrofit == null) {
synchronized (RequetRetrofit.class) {
if(retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl(HttpsConstant.Server.ROOT_URL) //BaseUrl
.client(okHttpClient) //请求的网络框架
.addConverterFactory(GsonConverterFactory.create()) //解析数据格式
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // 使用RxJava作为回调适配器
.build();
}
}
}
return retrofit.create(service);
}
}
网友评论