okhttp+Retrofit+gson实现的基于https的服务器实现范例

来源:互联网 发布:淘宝双色球在哪里 编辑:程序博客网 时间:2024/06/06 03:38

Retrofit使用

使用到的依赖库,使用的时候添加依赖:

compile 'com.google.code.gson:gson:2.7'

//retrofit->resful api
compile 'com.squareup.retrofit2:retrofit:2.0.2'
compile 'com.squareup.retrofit2:converter-gson:2.0.2'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2'
//httpOk
compile 'com.squareup.okhttp3:okhttp:3.2.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.1.2'

1. 先定义好调用的接口。

例子:

public interface RestfulServer{

//用户注册
@POST("/user")
Call<UserSession> register(@Body User user);

//用户登录
@PUT("/user/{user_name}/login")
Call<UserSession> login(@Path("user_name") String user_name,@Body User user);

//上传头像
@Multipart
@POST("/user/{user_name}/avatar")
Call<UserSession> uploadImage(@Header("token") String token,@Path("user_name") String user_name,@Part MultipartBody.Part file);

//获取用户头像
@GET("/user/{user_name}/avatar")
Call<Bitmap> getImage(@Header("token") String token,@Path("user_name") String user_name);

 

 

}

1.@后面是请求的参数:@POST

2.请求后面括号里面的是请求的数据路径:("/user")

由于正式通讯的时候建立通讯的只有一个地址,但是数据是放到服务器下面不同的地址下面的。所以这里添加详细路径。比如

Retrofit.Builder

builder = new Retrofit.Builder().baseUrl("").//前面引号的是连接的网址https;//xxxx,这里删除了

addConverterFactory(GsonConverterFactory.

create());

这个例子:建立连接的时候都是一个地址,请求方法的时候需要加上/user,代表你请求的地址是:https://xxxx/user

比如:https://baidu/nihao,代表百度下面你好的路径。

3.Call是固定的,括号里面自定义的用于gson格式的数据定义。用于调用的时候,回调调用结果的使用的

4.函数名称后面的是需要传递的参数,http请求参数有header,body等如果没有和服务器定义,是可以不用填的。

例子:

//用户注册
@POST("/user")
Call<UserSession> register(@Body User user);

这里只有body需要传递参数(user是自己定义的传递给服务器的用户对象)。

//获取用户头像
@GET("/user/{user_name}/avatar")
Call<Bitmap> getImage(@Header("token") String token,@Path("user_name") String user_name);

这里获取用户头像就带上了header的参数,说明它是需要header数据的。

上面的请求路径:/user/{user_name}/avatar包含大括号

大括号的意思是:路径不是固定的,比如这里的是用户登录的意思,请求路劲根据用户名的不同而不同。在后面@Path("user_name") String user_name把这个不确定的参数赋值。

2. 构造Retrofit.Builder。

Retrofit.Builder builder =

new Retrofit.Builder().

baseUrl("https://api.deplink.net").

addConverterFactory(GsonConverterFactory.create());

1. 这里传入需要连接的服务器地址,(http,https区别是数据加密)这里使用https的带加密的。

2. 这里GsonConverterFactory是定义了和服务器的通讯数据形式,是json格式的。

如果我们和服务器传递的不是json的格式,那要自定义这个ConverterFactory,然后把GsonConverterFactory用你自定义的那个就行了。

下面来看看自定义ConverterFactory

我定义一个获取png图片的ConverterFactory

public class PngConvertFactory  extendsConverter.Factory{
    public static PngConvertFactory create() {
        return new PngConvertFactory();
    }

    private PngConvertFactory() {

    }

    @Override
    publicConverter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
        return new PngResponseBodyConverter();
    }

    @Override
    publicConverter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
        return super.requestBodyConverter(type, parameterAnnotations, methodAnnotations, retrofit);
    }
}

下面是接收数据的类型:

public class PngResponseBodyConverterimplements Converter<ResponseBody, Bitmap> {
    private  static final StringTAG="PngConverter";
    @Override
    publicBitmap convert(ResponseBody value) throwsIOException {
        try {
            return getBitmapFromByte(value.bytes());
        } finally {
            Log.i(TAG,"getBitmapFromByte close");
            value.close();
        }
    }


    public Bitmap getBitmapFromByte(byte[] temp){
        if(temp != null){
            Bitmap bitmap = BitmapFactory.decodeByteArray(temp, 0, temp.length);
            return bitmap;
        }else{
            return null;
        }
    }
}

下面是请求数据的类型:

public class PngRequestBodyConverter  implementsConverter<String, RequestBody> {
    @Override
    publicRequestBody convert(String value) throwsIOException {
        return null;
    }
}

可以看到只特别定义了接收数据的格式,把接收到的数据转成bitmap,对上传的数据没有处理。

 

3. 构造OkHttpClient.Builder。

这里使用的okhhp框架

String ca = "" //ca就是加密的秘钥,就是一串字符串。

OkHttpClient.Builder clientBuilder =

new OkHttpClient.Builder();
clientBuilder

.connectTimeout(15 * 1000, TimeUnit.MILLISECONDS)
        .readTimeout(20 * 1000, TimeUnit.MILLISECONDS)
        .sslSocketFactory(SslUtil.getSocketFactory(ca));

OkHttpClient okClient = clientBuilder.build();

这里是构建sslsockeet的https请求。

 

public static SSLSocketFactory getSocketFactory(String certificate) {
    SSLSocketFactory socketFactory = null;
    try {
        // Loading CAs from an InputStream
        
CertificateFactory cf =null;
        cf = CertificateFactory.getInstance("X.509");
        X509Certificate ca;
        InputStream cert = new ByteArrayInputStream(certificate.getBytes());
        ca = (X509Certificate)cf.generateCertificate(cert);
              cert.close();
        // Creating a KeyStore containing our trusted CAs
        
String keyStoreType = KeyStore.getDefaultType();
        KeyStore keyStore   = KeyStore.getInstance(keyStoreType);
        keyStore.load(null,null);
        keyStore.setCertificateEntry("ca-certificate", ca);
        // Creating a TrustManager that trusts the CAs in our KeyStore.
        
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
        tmf.init(keyStore);
        // Creating an SSLSocketFactory that uses our TrustManager
        
SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, tmf.getTrustManagers(),null);

        socketFactory = sslContext.getSocketFactory();
    } catch(Exception e) {
        e.printStackTrace();
    }

    return socketFactory;
}

4. OkHttpClient.Builder设置给Retrofit.Builder

 

builder.client(okClient);

 

5. 下面就是把之前定义好的服务接口(RestfulServer)给其他类使用。

private volatile static RestfulServerapiService;

(这里使用volatile关键字是数据同步需要使用

Retrofit retrofit = builder.build();
apiService = retrofit.create(RestfulServer.class);

6. .下面把服务接口都封装到一个sdk里面。

例子;登录接口
public Call<UserSession> login(String username, String password, Callback<UserSession> cll) {
    User user = new User();
    user.setName(username);
    user.setPassword(password);
    user.setApplication_key(DeplinkSDK.getAppKey());
    Call<UserSession> call = apiService.login(username, user);
    if (cll != null) {
        call.enqueue(cll);
    }
    return call;
}

这样界面activity调用的时候就需要传递参数调用。

这里可以看到,函数设计的是,调用参数,然后加上返回结果的回调。

函数体中apiService,使用之前定义好的接口调用http或者https请求。

 if (cll != null) {
        call.enqueue(cll);
    }
如果设置了回调,就把回调给放到队列中去。

 

难点例子:上传图片

接口:

//上传头像
@Multipart
@POST("/user/{user_name}/avatar")
Call<UserSession> uploadImage(@Header("token") String token,@Path("user_name") String user_name,@Part MultipartBody.Part file);

调用:

public Call<UserSession> uploadImage( String imagePath, Callback<UserSession> cll) {
    File file = new File(imagePath);
    RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file);
    MultipartBody.Part body = MultipartBody.Part.createFormData("avatar", file.getName(), requestFile);
   

    Call<UserSession> call = apiService.uploadImage(token,username,body);
    if (cll != null) {
        call.enqueue(cll);
    }
    return call;
}

遇到的问题:服务器端说没有传递cookies给他。

在获取到cookies数据后保存起来,然后在连接的时候设置保存的cookies

例子:

RestfulToolsPng.getSingleton(LoginActivity.this).getCaptcha(newCallback<Bitmap>() {
    @Override
    public voidonResponse(Call<Bitmap> call, Response<Bitmap> response) {
        int code = response.code();
        String token = response.headers().get("Set-Cookie");
        Log.i(TAG,"cookies=" + token);
        SharedPreferences sp = LoginActivity.this.getSharedPreferences("user_login",MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.putString("token_login", token);
        editor.apply();
                 }

    @Override
    public voidonFailure(Call<Bitmap> call, Throwable t) {

    }
});

cookies设置给okhttp

OkHttpClient.Builder clientBuilder = newOkHttpClient.Builder().cookieJar(newCookieJar() {
    @Override
    public voidsaveFromResponse(HttpUrl url, List<Cookie> cookies) {
        StringBuilder sb=new StringBuilder();
        for(inti=0;i<cookies.size();i++){
            sb.append(cookies.get(i).toString());
        }
        Log.i("saveFromResponse",""+sb.toString());

    }

    @Override
    publicList<Cookie> loadForRequest(HttpUrl url) {
        List<Cookie> cookies = new ArrayList<>();
        SharedPreferences sp = mContext.getSharedPreferences("user_login", Context.MODE_PRIVATE);
        String token = sp.getString("token_login",null);
        if (token != null) {

            Cookie cookie = Cookie.parse(url, token);

            cookies.add(cookie);
        }
        return cookies;
    }
});

 



阅读全文
0 0
原创粉丝点击