本文根据以下三篇博客总结得出:
小张也是蛮拼的 - Retrofit 2 之自定义Converter实现加密解密
唯鹿 - Android单元测试(五):网络接口测试
majunm - Retrofit2封装之路(请求参数加密解密)(二)
写此文只为方便日后回顾。
首先是自定义的 JsonConverterFactory,在这个转换器工厂类里添加了一个boolean值开关,用户决定是否对传入传出的数据进行加密解密
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Converter;
import retrofit2.Retrofit;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.reflect.TypeToken;
public class JsonConverterFactory extends Converter.Factory {
private static boolean isEncrypt = true;
public static JsonConverterFactory create() {
return create(new GsonBuilder().setLenient().create());
}
/**
* 是否对进入的参数和返回的结果加密解密
* @param encrypt
* @return
*/
public static JsonConverterFactory create(boolean encrypt) {
isEncrypt = encrypt;
return create(new GsonBuilder().setLenient().create());
}
public static JsonConverterFactory create(Gson gson) {
if (gson == null)
throw new NullPointerException("gson == null");
return new JsonConverterFactory(gson);
}
private final Gson gson;
private JsonConverterFactory(Gson gson) {
this.gson = gson;
}
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type,
Annotation[] annotations, Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new JsonResponseBodyConverter(gson, adapter,isEncrypt); // 响应
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations,
Retrofit retrofit) {
System.out.println("#发起请求#");
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new JsonRequestBodyConverter(gson, adapter,isEncrypt); // 请求
}
}
--- 请求体转化器
import com.ee56.scangun.utils.crypto.MyAES;
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import java.io.IOException;
import java.nio.charset.Charset;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import retrofit2.Converter;
/**
* Created by zhang on 2016/5/31.
* <p>
* 自定义请求RequestBody
*/
public class JsonRequestBodyConverter implements Converter<Object, RequestBody> {
private static final MediaType MEDIA_TYPE = MediaType
.parse("application/json; charset=UTF-8");
static final Charset UTF_8 = Charset.forName("UTF-8");
final Gson gson;
final TypeAdapter adapter;
boolean isEncrypt;
JsonRequestBodyConverter(Gson gson, TypeAdapter adapter,boolean isEncrypt) {
this.gson = gson;
this.adapter = adapter;
this.isEncrypt = isEncrypt;
System.out.println("#IRequestBodyConverter初始化#");
}
@Override
public RequestBody convert(Object value) throws IOException {
//将传入的实体类先转成json,再进行加密
String json = gson.toJson(value);
if(isEncrypt) {
System.out.println("#加密前#" + json);
try {
json = MyAES.aesEncryptT(json);
} catch (Exception ex) {
System.out.println("#加密出错#" + ex.getMessage());
json = "";
}
System.out.println("#加密后#" + json);
}
return RequestBody.create(MEDIA_TYPE, json);
}
}
--- 回应体转换器
import com.ee56.scangun.utils.crypto.MyAES;
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import java.io.IOException;
import okhttp3.ResponseBody;
import retrofit2.Converter;
/**
* Created by zhang on 2016/5/31.
* 自定义响应ResponseBody
*/
public class JsonResponseBodyConverter implements Converter<ResponseBody,String> {
private final Gson gson;
private final TypeAdapter adapter;
private boolean isEncrypt;
JsonResponseBodyConverter(Gson gson, TypeAdapter adapter,boolean isEncrypt) {
this.gson = gson;
this.adapter = adapter;
this.isEncrypt = isEncrypt;
}
@Override
public String convert(ResponseBody value) throws IOException {
//得到请求返回体的内容
String string = value.string();
if(isEncrypt) {
System.out.println("#解密前@#" + string);
try {
string = MyAES.aesDecrypt(string);
} catch (Exception e) {
System.out.println("#解密出错@#" + e.getMessage());
string = "";
}
System.out.println("#解密后@#" + string);
}
return string;
}
}
接下来对请求类进行封装,
import okhttp3.OkHttpClient;
import okhttp3.ResponseBody;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import com.google.gson.Gson;
import java.io.IOException;
public class HttpManager {
private static final Gson GSON = new Gson();
private OkHttpClient mOkHttpClient;
private Retrofit mRetrofit;
private HttpManager() {
mOkHttpClient = getOkHttpClient();
mRetrofit = new Retrofit.Builder()
.baseUrl(GithubApi.BASE_URL)
.client(mOkHttpClient)
//添加转换器时,create()不添加参数表示加密
.addConverterFactory(JsonConverterFactory.create())
.build();
}
private static final class HttpManagerHolder {
private static final HttpManager INSTANCE = new HttpManager();
}
public static HttpManager getInstance() {
return HttpManagerHolder.INSTANCE;
}
public static <T> T doGet(String subUrl,Class<T> type){
return getInstance().get(subUrl,type);
}
public static void doPost(Object src, String subURL,final ResultCallback<?> mCallback) {
getInstance().post(src,subURL,mCallback);
}
/**
* url是请求的全路径
* @param url
*/
public <T> T get(String url,Class<T> type) {
//先把请求url拆解成基础路径和子路径
String baseUrl = url.substring(0,url.lastIndexOf("/")+1);
String subUrl = url.substring(url.lastIndexOf("/")+1);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.client(mOkHttpClient)
.build();
GithubApi api = retrofit.create(GithubApi.class);
Call<ResponseBody> doGet = api.doGet(subUrl);
System.out.println("#成功回调#");
String res = "";
try {
Response<ResponseBody> response = doGet.execute();
if(response.isSuccessful()){
res = response.body().string();
}
} catch (IOException e) {
e.printStackTrace();
res = "";
}
if(!isEmpty(res)){
if(type != null && type != String.class){
T o = GSON.fromJson(res, type);
return o;
}
}
return (T) res;
}
private boolean isEmpty(String str){
return str == null || str.equals("") || str.equals("null");
}
/**
* 在ResultCallback中可以指定返回的实体类型
* @param src
* @param subURL
* @param mCallback
* @param <T>
*/
public <T> void post(Object src,String subURL, final ResultCallback<T> mCallback) {
GithubApi api = mRetrofit.create(GithubApi.class);
Call<String> doPost = api.doPost(src,subURL);
doPost.enqueue(new Callback<String>() {
@Override
public void onFailure(Call<String> request, Throwable error) {
System.out.println("#失败回调#" + error.getMessage());
if (mCallback != null) {
mCallback.onError(null, error);
}
}
@Override
public void onResponse(Call<String> call, Response<String> resp) {
System.out.println("#成功回调#");
if (mCallback != null) {
if (resp.isSuccessful()) {
String finalStr = resp.body();
if (mCallback.mType != null) {
if (mCallback.mType == String.class) {
if (isEmpty(finalStr)) {
Exception e = new Exception(
"AesEncryptionUtil.decrypt(string) return null!");
exeFailedCallback(call, e, mCallback);
} else {
exeSuccessCallback(finalStr, mCallback);
}
} else {
Object o = GSON.fromJson(finalStr,
mCallback.mType);
System.out.println("#类型是#" + mCallback.mType);
if (o == null) {
Exception e = new Exception(
"mGson.fromJson(finalStr,callback.mType) return null!");
exeFailedCallback(call, e, mCallback);
} else {
exeSuccessCallback(o, mCallback);
}
}
} else {
Throwable e = new Throwable("mCallback.mType 为空!!!");
exeFailedCallback(call, e, mCallback);
}
} else {
Throwable e = new Throwable(resp.toString());
exeFailedCallback(call, e, mCallback);
}
}
}
});
}
@SuppressWarnings({"rawtypes", "unchecked"})
public void exeFailedCallback(final Call call, final Throwable e,
final ResultCallback<?> callback) {
if (callback != null) {
callback.onError(call, e);
}
}
@SuppressWarnings({"unchecked", "rawtypes"})
public void exeSuccessCallback(Object o, final ResultCallback callback) {
if (callback != null) {
callback.onResponse(o);
}
}
public static OkHttpClient getOkHttpClient() {
// 日志显示级别
HttpLoggingInterceptor.Level level = HttpLoggingInterceptor.Level.BODY;
// 新建log拦截器
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(
new HttpLoggingInterceptor.Logger() {
@Override
public void log(String message) {
System.out.println(message);
}
});
loggingInterceptor.setLevel(level);
// 定制OkHttp
OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
// OkHttp进行添加拦截器loggingInterceptor
httpClientBuilder.addInterceptor(loggingInterceptor);
return httpClientBuilder.build();
}
}
其中在初始化 OkHttpClient 对象的时候,可以添加Interceptor来模拟返回的数据,下面是我修改后的Mock Interceptor,
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.Protocol;
import okhttp3.Response;
import okhttp3.ResponseBody;
public class MockInterceptor implements Interceptor {
@Override
public Response intercept(Interceptor.Chain chain) throws IOException {
String responseString = createResponseBody(chain);
Response response = new Response.Builder()
.code(200)
.message(responseString)
.request(chain.request())
.protocol(Protocol.HTTP_1_0)
.body(ResponseBody.create(MediaType.parse("application/json"), responseString.getBytes()))
.addHeader("content-type", "application/json")
.build();
return response;
}
/**
* 读文件获取json字符串,生成ResponseBody
* 将json文件放在 test/resource/json/ 目录下,如果没有,新建之
* @param chain
* @return
*/
private String createResponseBody(Chain chain) {
String responseString = null;
HttpUrl uri = chain.request().url();
String path = uri.url().getPath();
System.out.println("url :"+path);
if (path.matches("^(/users/)+[^/]*+(/repos)$")) {//匹配/users/{username}/repos
responseString = getResponseString("users_repos.json");
} else if (path.matches("^(/users/)+[^/]+(/following)$")) {//匹配/users/{username}/following
responseString = getResponseString("users_following.json");
} else if (path.matches("^(/users/)+[^/]*+$")) {//匹配/users/{username}
responseString = getResponseString("users.json");
}else if(path.matches("^(/WarehouseServices/WH_UserLoginByHandheld)")){
responseString = getResponseString("login.json");
}
return responseString;
}
//将文件中的json数据读取出来,json文本放在 test/resource/json/目录下
private String getResponseString(String fileName){
FileInputStream fis;
File currentDir = new File("");
File currentFile = new File(currentDir.getAbsolutePath()+"/src/test/resource/json/"+fileName);
try {
fis = new FileInputStream(currentFile);
}catch (FileNotFoundException ffe){
fis = null;
System.out.println("file not found exception :"+ffe.getMessage());
}
StringBuilder stringBuffer = new StringBuilder();
if(fis!=null){
BufferedInputStream bif = new BufferedInputStream(fis);
byte[] buffer = new byte[1024];
try {
while ((bif.read(buffer,0,buffer.length))!=-1){
stringBuffer.append(new String(buffer));
}
}catch (IOException e){
e.printStackTrace();
}finally {
try {
bif.close();
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return stringBuffer.toString();
}
}
对HttpManager进一步封装的调用类
public class HttpRequestFactory {
public static <T> void post(Object src, String subURL,final ResultCallback<T> mCallback) {
HttpManager.doPost(src,subURL, mCallback);
}
public static <T> T get(String url,Class<T> type) {
return HttpManager.doGet(url,type);
}
public static String get(String url) {
return HttpManager.doGet(url,String.class);
}
}
import com.google.gson.internal.$Gson$Types;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import retrofit2.Call;
public abstract class ResultCallback<T> {
public Type mType;
public ResultCallback() {
mType = getSuperclassTypeParameter(getClass());
}
private static Type getSuperclassTypeParameter(Class<?> subclass) {
Type superclass = subclass.getGenericSuperclass();
if (superclass instanceof Class) {
throw new RuntimeException("Missing type parameter.");
}
ParameterizedType parameterized = (ParameterizedType) superclass;
return $Gson$Types
.canonicalize(parameterized.getActualTypeArguments()[0]);
}
public abstract void onError(Call<T> request, Throwable e);
public abstract void onResponse(T response);
}
retrofit Api 接口类
public interface GithubApi {
String BASE_URL = "http://xxx.xxx.com/xxxx/";
@GET("{path}")
Call<ResponseBody> doGet(@Path("path") String path);
/**
* 传入实体类
* @param param
* @return
*/
@POST("{path}")
Call<String> doPost(@Body Object param,@Path("path") String path);
}
最后在Junit测试用例中调用
@RunWith(BlockJUnit4ClassRunner.class)
public class ExampleUnitTest {
private CountDownLatch downLatch;
@Rule
public RxJavaRule rxJavaRule = new RxJavaRule();
@Before
public void setUp() {
downLatch = new CountDownLatch(1);
}
@Test
public void testGet () {
String url = "xxxxxxxxxx";
UpdateBean res = HttpRequestFactory.get(url,UpdateBean.class);
System.out.println("#--x--#" + res.getReleaseDate());
System.out.println("#--x--#" + res.getDownloadUrl());
}
@Test
public void testPost() {
String username = "xxxxxxxxxxx";
String password = "123456";
//构造用户登录json对象
UserLoginPostBean postBean = new UserLoginPostBean();
postBean.setLoginName(username);
postBean.setPassword(password);
HttpRequestFactory.post(postBean,"subURL子路径",
new ResultCallback<String>() {
@Override
public void onError(Call<String> request, Throwable e) {
synchronized (HttpRequestFactory.class) {
HttpRequestFactory.class.notify();
}
}
@Override
public void onResponse(String response) {
synchronized (HttpRequestFactory.class) {
HttpRequestFactory.class.notify();
}
}
});
try {
synchronized (HttpRequestFactory.class) {
HttpRequestFactory.class.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("方法结束,我最后执行");
}
}