Both sides previous revisionPrevious revision | |
retrofit [2021/02/07 03:50] – removed ledyx | retrofit [2021/02/07 05:49] (current) – old revision restored (2017/06/22 14:06) ledyx |
---|
| = Retrofit = |
| |
| http://square.github.io/retrofit/ |
| |
| Retrofit2 + OkHttp3 + Jackson + RxAndroid2/RxJava2 |
| |
| {{tag>Tips Restful web}} |
| |
| |
| = Library = |
| |
| https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp |
| https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp-urlconnection |
| |
| |
| <sxh bash ; title:Gradle> |
| compile 'com.squareup.okhttp3:okhttp:3.8.0' |
| compile 'com.squareup.okhttp3:okhttp-urlconnection:3.8.0' |
| compile 'com.squareup.okhttp3:logging-interceptor:3.8.0' |
| |
| compile 'com.squareup.retrofit2:retrofit:2.3.0' |
| compile 'com.squareup.retrofit2:converter-jackson:2.3.0' |
| compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0' |
| |
| compile 'com.fasterxml.jackson.core:jackson-core:2.8.8' |
| compile 'com.fasterxml.jackson.core:jackson-databind:2.8.8.1' |
| compile 'com.fasterxml.jackson.core:jackson-annotations:2.8.8' |
| |
| //Android |
| compile 'io.reactivex.rxjava2:rxandroid:2.0.1' |
| //Java |
| compile 'io.reactivex.rxjava2:rxjava:2.1.0' |
| </sxh> |
| |
| = Source = |
| |
| <sxh java ; title:Adapter> |
| public class RestfulAdapter { |
| |
| public static final int CONNECT_TIMEOUT = 15; |
| public static final int WRITE_TIMEOUT = 15; |
| public static final int READ_TIMEOUT = 15; |
| |
| private static volatile ConcurrentHashMap<String, Object> services = new ConcurrentHashMap<>(); |
| |
| public static synchronized <T> T getInstance(Class<T> restfulInterface) throws Exception { |
| if(!restfulInterface.isInterface()) |
| throw new IllegalArgumentException("argument must be INTERFACE"); |
| |
| T service = (T) services.get(restfulInterface.getName()); |
| |
| if(service == null) { |
| if(!restfulInterface.isAnnotationPresent(URL.class)) |
| throw new Exception("Must be annotated URL"); |
| |
| URL urlAnnotation = restfulInterface.getDeclaredAnnotation(URL.class); |
| |
| String url = urlAnnotation.value(); |
| if(url.length() <= 0 || !url.substring(0, 4).equals("http")) |
| throw new Exception("Unavailable URL value"); |
| |
| boolean isUnwrapRootValue = urlAnnotation.isUnwrappedRoot(); |
| |
| HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(); |
| httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); |
| |
| CookieManager cookieManager = new CookieManager(); |
| cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL); |
| |
| OkHttpClient client = configureClient() // 인증서 무시 |
| .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS) |
| .writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS) |
| .readTimeout(READ_TIMEOUT, TimeUnit.SECONDS) |
| .cookieJar(new JavaNetCookieJar(cookieManager)) //쿠키 설정 |
| .addInterceptor(httpLoggingInterceptor) //http 로그 확인 |
| .build(); |
| |
| service = new Retrofit.Builder() |
| .baseUrl(url) |
| .client(client) |
| .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) |
| .addConverterFactory(getConverterFactory(isUnwrapRootValue)) |
| .build().create(restfulInterface); |
| |
| services.put(restfulInterface.getName(), service); |
| } |
| |
| return service; |
| } |
| |
| private static JacksonConverterFactory getConverterFactory(boolean isUnwrapRootValue) { |
| ObjectMapper objectMapper = new ObjectMapper(); |
| objectMapper.registerModule(new JodaModule()); |
| objectMapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES); |
| objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); |
| if(isUnwrapRootValue) |
| objectMapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE); // JsonRootName과 연계 |
| |
| return JacksonConverterFactory.create(objectMapper); |
| } |
| |
| /** |
| * 인증서 무시 |
| * @return |
| */ |
| private static OkHttpClient.Builder configureClient() throws Exception { |
| TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); |
| trustManagerFactory.init((KeyStore) null); |
| TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); |
| |
| if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) |
| throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers)); |
| |
| X509TrustManager trustManager = (X509TrustManager) trustManagers[0]; |
| |
| SSLContext sslContext = SSLContext.getInstance("SSL"); |
| sslContext.init(null, new TrustManager[] { trustManager }, new SecureRandom()); |
| |
| OkHttpClient.Builder builder = new OkHttpClient.Builder(); |
| builder.sslSocketFactory(sslContext.getSocketFactory(), trustManager).hostnameVerifier((hostname, session) -> true); |
| |
| return builder; |
| } |
| } |
| </sxh> |
| |
| <sxh java ; title:Service Interface> |
| @URL(value = "http://xxx.com", isUnwrappedRoot = true) |
| public interface DemoService { |
| @GET("{page}") |
| Observable<ContentsVO> read(@Path("page") long page); |
| |
| @PUT("{no}") |
| Observable<ResponseBody> modify(@Path("no") long no, @Body ServiceVO serviceVO); |
| |
| @Multipart |
| @POST(URL) |
| Observable<ResponseBody> write(@PartMap Map<String, RequestBody> params); |
| |
| @DELETE("{no}") |
| Observable<ResponseBody> delete(@Path("no") long no); |
| } |
| </sxh> |
| |
| <sxh java ; title:Custom Annotation> |
| @Target(ElementType.TYPE) |
| @Retention(RetentionPolicy.RUNTIME) |
| public @interface URL { |
| String value() default ""; |
| boolean isUnwrappedRoot() default false; |
| } |
| </sxh> |