问题: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();