问题:Retrofit中为Post请求设置统一参数
情景:使用RequestBody发送Post请求,无法添加统一参数,换成FormBody网上倒是有很多解决方案,但是FormBody一方面MediaType跟后台要求的对应不上(不确定这个对请求有没有影响),另一方面只能传String参数(如果有什么方法可以传递其他参数欢迎留言补充),跟后台的要求对不上。
解决方案:
1.自定义RequestBody
import java.io.IOException; import java.nio.charset.Charset; import javax.annotation.Nullable; import okhttp3.MediaType; import okhttp3.RequestBody; import okhttp3.internal.Util; import okio.BufferedSink; /** *@description 自定义RequestBody,解决POST请求时拦截器添加统一参数问题 *@author mxm *@creatTime 2018/10/24 下午6:13 */ public class PostJsonBody extends RequestBody { private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); private static final Charset charset = Util.UTF_8; private String content; public PostJsonBody(String content) { this.content = content; } public String getContent() { return content; } @Nullable @Override public MediaType contentType() { return JSON; } @Override public void writeTo(BufferedSink sink) throws IOException { byte[] bytes = content.getBytes(charset); if (bytes == null) throw new NullPointerException("content == null"); Util.checkOffsetAndCount(bytes.length, 0, bytes.length); sink.write(bytes, 0, bytes.length); } public static RequestBody create(String content) { return new PostJsonBody(content); } }其实就是个中转站,先把我们的参数用JsonString的方式存着,然后在拦截器中解析出来,加上统一的参数,再重新建立一个RequestBody 发送出去。
2、在拦截器中添加统一参数(这里的Gson设置是为了解决jsonString转map时会出现Int被转成Double的问题)
public class BaseParamsInterceptor implements Interceptor { Gson gson; public BaseParamsInterceptor(TokenProvider tokenProvider) { this.gson = new GsonBuilder() .registerTypeAdapter( new TypeToken<HashMap<String, Object>>(){}.getType(), new JsonDeserializer<HashMap<String, Object>>() { @Override public HashMap<String, Object> deserialize( JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { HashMap<String, Object> hashMap = new HashMap<>(); JsonObject jsonObject = json.getAsJsonObject(); Set<Map.Entry<String, JsonElement>> entrySet = jsonObject.entrySet(); for (Map.Entry<String, JsonElement> entry : entrySet) { hashMap.put(entry.getKey(), entry.getValue()); } return hashMap; } }).create(); } @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); Request.Builder requestBuilder = request.newBuilder(); if (request.method().equals("POST")) { RequestBody requestBody = request.body(); if (requestBody instanceof PostJsonBody) { String content = ((PostJsonBody) requestBody).getContent(); HashMap<String, Object> hashMap = gson.fromJson(content, new TypeToken<HashMap<String, Object>>(){}.getType()); //添加统一参数 hashMap.put("auth_token", tokenProvider.getAuthToken()); //end requestBuilder.post( RequestBody.create(MediaType.parse("application/json; charset=utf-8"), gson.toJson(hashMap))); } } return chain.proceed(requestBuilder.build()); } }3、使用方法没什么变化(记得设置拦截器)
map.put("shop_id", Integer.valueOf(userAuthManager.getShopId())); final RequestBody requestBody = PostJsonBody.create(GsonUtil.toJson(map));2018年11月27日15:20:28
这种方式不太好,不过也能实现功能,目前没有发现什么问题,现在我换了种方式,通过建造者模式(不知道用的对不对,正在学设计模式,如果错了后面改进吧)链式调用添加参数
public class ParamsBuilder { static{ gson=new Gson(); } private static Gson gson; private Map<String,Object> map; ParamsBuilder(){ this.map=new HashMap<>(); } /** * 添加参数 */ public ParamsBuilder addParams(String key, Object value) { if (TextUtils.isEmpty(key)) { throw new NullPointerException("key 不能为空"); } map.put(key, value); return this; } /** * 添加全局参数 */ public ParamsBuilder addCommonMap() { //添加统一参数 addParams("auth_token",UserAuthManager.getInstance().getAuthToken()); return this; } /** * 返回map集合 */ public Map bulid(){ return map; } /** * 返回json字符串 */ public String toJson(){ return gson.toJson(map); } /** * 返回RequestBody */ public RequestBody toRequestBody(){ return RequestBody.create( MediaType.parse("application/json; charset=utf-8"),toJson()); } }BaseModel:
public class BaseModel { protected ApiService service; public BaseModel() { service = ApiManager.getInstance().getApiService(); } /** * 链式添加参数 */ protected ParamsBuilder getBuilder(){ return new ParamsBuilder(); } }使用方式,在Model中继承BaseModel,然后在方法中通过addCommonMap()就能添加统一参数,其实就是简单的写在基类里面了。
RequestBody requestBody = getBuilder() .addCommonMap() .addParams("start_time",startTime) .addParams("end_time",endTime).toRequestBody();