打造万用的RetrofitManager 从此一个告别一个后台接口一个本地接口

1 篇文章 0 订阅
1 篇文章 0 订阅

 

本人之前一直用的OkHttp, 最近换成了Retrofit, 然后发现一个后台接口要对应一个interface  这也太麻烦了吧!!

为了偷懒,大概研究了Retrofit用法之后 封装了这么一套万能的Retrofit! 

首先是接口数据的bean,一般来说后台的返回格式都是固定的!  如果不是的话 让后台重写!例如下的json格式


/**
 * data : {"email":"","expireTime":"1527738202273","status":""}
 * errors : []
 * reqId :
 * retCode : 2
 * retMsg : 参数异常
 * sessionId : null
 */

data部分为真实的返回部分,剩下的是一些固定的返回  根据返回数据 写一个BaseBean

 

public class BaseBean<T>  implements Serializable {

    private T data;
    private String reqId;
    private int retCode;
    private String retMsg;
    private String sessionId;
    private List<String> errors;

    public String getReqId() {
        return reqId;
    }

    public void setReqId(String reqId) {
        this.reqId = reqId;
    }

    public int getRetCode() {
        return retCode;
    }

    public void setRetCode(int retCode) {
        this.retCode = retCode;
    }

    public String getRetMsg() {
        return retMsg;
    }

    public void setRetMsg(String retMsg) {
        this.retMsg = retMsg;
    }

    public String getSessionId() {
        return sessionId;
    }

    public void setSessionId(String sessionId) {
        this.sessionId = sessionId;
    }

    public List<String> getErrors() {
        return errors;
    }

    public void setErrors(List<String> errors) {
        this.errors = errors;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

OK BaseBean 搞定了 下边撸接口


首先是万用的interface 

public interface InternetService {
    @POST("{path}")
     Observable<BaseBean> requestPost(@Path("path")String path, @Body HashMap<String,Object> body);
    @GET("{path}")
    Observable<BaseBean> requestGet(@Path("path")String path, @Body HashMap<String,Object> body);

    @Multipart
    @POST("{path}")
    Observable<BaseBean<List<ResponseUploadFiles>>> requestFile(@Path("path")String path, @Part List<MultipartBody.Part> list, @PartMap Map<String,RequestBody> requestBodyMap);

}

 


嗯 提供了三种方法 

1.post请求 2.get请求 3.上传请求

那么问题来了 这样写的post和get数据  最后返回的BaseBean 的 data 并不能变成自己想要的!

怎么解决呢!参考了很多资料  然后找到了解决方法 

重写Gson解析工厂 当然用了单例

/**
 *
 * 自定义GsonConverterFactory
 */
public class CustomizeGsonConverterFactory extends Converter.Factory {


    private Gson gson;
    private CustomizeGsonConverterFactory() {
        gson=new GsonBuilder().registerTypeAdapter(BaseBean.class, BaseDeserializer.getInstance()).create();
    }
    private  static class LazyHolder{
        private static final CustomizeGsonConverterFactory INSTANCE=new CustomizeGsonConverterFactory();
    }
    public static final CustomizeGsonConverterFactory getInstance(){
        return LazyHolder.INSTANCE;
    }


    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
                                                            Retrofit retrofit) {
        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        return new CustomizeGsonResponseBodyConverter(gson, adapter);
    }

    @Override
    public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        return new CustomizeGsonRequestBodyConverter(gson,adapter);
    }

}
public class CustomizeGsonRequestBodyConverter<T> implements Converter<T, RequestBody> {

    private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
    private static final Charset UTF_8 = Charset.forName("UTF-8");

    private  final Gson gson;
    private final TypeAdapter<T> adapter;

    CustomizeGsonRequestBodyConverter(Gson gson, TypeAdapter<T> adapter) {
        this.gson = gson;
        this.adapter = adapter;
    }



    @Override
    public RequestBody convert(T value) throws IOException {
        Buffer buffer = new Buffer();
        Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
        JsonWriter jsonWriter = gson.newJsonWriter(writer);
        adapter.write(jsonWriter, value);
        jsonWriter.close();
        return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
    }
}
public class CustomizeGsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {

    private final Gson gson;
    private final TypeAdapter<T> adapter;

    CustomizeGsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
        this.gson = gson;
        this.adapter = adapter;
    }

    @Override
    public T convert(ResponseBody value) throws IOException {
        //把responsebody转为string

        String response = value.string();
        if (BuildConfig.DEBUG) {
            //打印后台数据
            System.out.println("response"+response);
        }
        HttpStatus status=gson.fromJson(response,HttpStatus.class);
       //全局捕获token错误 
        if(status.isCodeInvalid()){
            value.close();
            throw new ApiException(status.getCode(),status.getMessage());
        }
//        BaseBean baseResponse = gson.fromJson(response, BaseBean.class);
        // 这里只是为了检测code是否!=1,所以只解析HttpStatus中的字段,因为只要code和message就可以了

        try {
            return adapter.fromJson(response);
        } finally {
            value.close();
        }
    }
}

关于CustomizeGsonRequestBodyConverter 类之所以那么写是因为请求数据都是用的json形式

本来我的想法是 把Gson  对象json 动态设置的!结果经过测试 responseBodyConverter 和requestBodyConverter只会调用一次!

此路不通  换个思路  这里就涉及到一个东东自定义的JsonDeserializer   先上代码:

public class BaseDeserializer<Bean>implements JsonDeserializer<BaseBean> {
    private BaseDeserializer(){}
    private static class LazyHolder{
        private static final BaseDeserializer INSTANCE=new BaseDeserializer();
    }
    public static BaseDeserializer getInstance(){
        return LazyHolder.INSTANCE;
    }
    private Class<Bean> beanClass;

    public BaseDeserializer setBeanClass(Class<Bean> beanClass) {
        this.beanClass = beanClass;
        return this;
    }


    @Override  
    public BaseBean<Bean> deserialize(JsonElement json, Type typeOfT,
                              JsonDeserializationContext context) throws JsonParseException {

         JsonObject jsonObject = json.getAsJsonObject();
        JsonArray errors=jsonObject.getAsJsonArray("errors");
        JsonElement dataElement=jsonObject.get("data");
        List<String> list=new ArrayList<>();
         BaseBean baseBean=new BaseBean<>();
         if(dataElement.isJsonArray()){
            List<Bean> datas=new ArrayList<>();
             JsonArray jsonDatas=jsonObject.getAsJsonArray("data");
             for(JsonElement jsonElement:jsonDatas){
                 Bean data=context.deserialize(jsonElement,beanClass);
                 datas.add(data);
             }
             baseBean.setData(datas);
         }else if(dataElement.isJsonNull()){
             baseBean.setData(null);
         }else{
             baseBean.setData( context.deserialize(jsonObject.get("data").getAsJsonObject(),beanClass));
         }
        for(JsonElement jsonElement:errors){
            JsonObject jsonOb = jsonElement.getAsJsonObject();
            String error=jsonOb.getAsString();
            errors.add(error);
        }
         JsonElement reqId=jsonObject.get("reqId");
        JsonElement retCode=jsonObject.get("retCode");
        JsonElement retMsg=jsonObject.get("retMsg");
        JsonElement sessionId=jsonObject.get("sessionId");
        baseBean.setReqId(reqId.isJsonNull()?"":reqId.getAsString());
        baseBean.setRetCode(retCode.isJsonNull()?0:retCode.getAsInt());
        baseBean.setRetMsg(retMsg.isJsonNull()?"":retMsg.getAsString());
        baseBean.setSessionId(sessionId.isJsonNull()?"":sessionId.getAsString());
        baseBean.setErrors(list);
        return baseBean;
    }  
}  

同样使用了单例  然后动态持有一个class对象  就是data的真正的bean  !

主要是重写  deserialize方法  就是解析bean的过程 很简单 各位根据自己需要 自行更改 

 

到这里问题已经解决了 上代码:

package com.nhcz500.base.net;

import com.nhcz500.base.Constants;
import com.nhcz500.base.model.BaseBean;
import com.nhcz500.base.model.ResponseUploadFiles;
import com.nhcz500.base.net.customize.BaseDeserializer;
import com.nhcz500.base.net.customize.CustomizeGsonConverterFactory;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.xml.transform.Transformer;

import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.ObservableTransformer;
import io.reactivex.functions.Function;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.RequestBody;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;

/**
 * 单例retrofit工厂
 */
public class RetrofitManager {
    private Retrofit retrofit;
    private static long CONNECT_TIMEOUT = 10;
    private AppInterceptor interceptor;
    private RetrofitManager() {
        interceptor=new AppInterceptor();
        retrofit = new Retrofit.Builder()
                .baseUrl(Constants.BASE_URL) // 设置 网络请求 Url
                .client(getOkHttpClient())
                .addConverterFactory(CustomizeGsonConverterFactory.getInstance())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // 支持RxJava
                .build();
    }

    private static final class LazyHolder {
        private static final RetrofitManager INSTANCE = new RetrofitManager();
    }


    public static final RetrofitManager getInstance() {
        return LazyHolder.INSTANCE;
    }

    /**
     *获取返回类型
     * @return
     */
    public  <T>Observable<BaseBean<T>> getRetrofitObservable(boolean post, String path, HashMap<String, Object> params, final Class beanClass) {   //这里beanClass 之所以不用T 是为了防止有List类型的data部分

        interceptor.setForm(false); //设置提交表单类型
        InternetService service = retrofit.create(InternetService.class);
        Observable<BaseBean> observable;
        BaseDeserializer.getInstance().setBeanClass(beanClass);
//        params.put("sessionId",RequestSingleton.getInstance().getSessionId());
        if(post){
            observable=service.requestPost(path, params);
        }else{
            observable=service.requestGet(path,params);
        }
            return observable.map(new Function<BaseBean,BaseBean<T>>() {

                @Override
                public BaseBean<T> apply(BaseBean baseBean) throws Exception {
                    return baseBean;
                }
            }).onTerminateDetach();
    }


    public Observable<BaseBean<List<ResponseUploadFiles>>>  uploadFiles(String path, String fileParamsName,Map<String,String> params, String... filePaths) {
       //我的项目中只有上传图片请求,上传其自行更改逻辑
        interceptor.setForm(true);//设置提交表单类型
        InternetService service = retrofit.create(InternetService.class);
        BaseDeserializer.getInstance().setBeanClass(ResponseUploadFiles.class);
        Map<String,RequestBody> map=new HashMap<>();
        List<MultipartBody.Part> list=new ArrayList<>();
        for (String filePath : filePaths) {
            File file = new File(filePath);
            //2、创建RequestBody,其中`multipart/form-data`为编码类型
            RequestBody requestFile = RequestBody.create(MediaType.parse("image/jpeg"), file);
            MultipartBody.Part body = MultipartBody.Part.createFormData(fileParamsName, file.getName(), requestFile);
            System.out.println("file:"+file.getName());
            list.add(body);

        }
        if(params!=null) {
            for (String key : params.keySet()) {
                map.put(key, createRequestBody(params.get(key)));
            }
        }
        RequestBody sessionId = RequestBody.create(MediaType.parse("text/plain"),RequestSingleton.getInstance().getSessionId());
        map.put("sessionId",sessionId);
        return service.requestFile(path,list,map );
    }

    private RequestBody createRequestBody(String value){
        RequestBody requestBody = RequestBody.create(MediaType.parse("text/plain"),value);
        return requestBody;
    }

    private OkHttpClient getOkHttpClient(){
      return   new OkHttpClient.Builder()
                .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
                .readTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
                .writeTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
                .addInterceptor(interceptor)
//                .cookieJar(new CookiesManager())
                .build();
    }
}

OJBK 完美收工 怎么用?

HashMap<String,Object> params=new HashMap<>();
Observable<BaseBean<ResponseLanguage>>observable=RetrofitManager.getInstance()
.getRetrofitObservable(true,Constants.SYSTEM_LOCATION,params,ResponseLanguage.class);

是不是很简单!!

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值