HTTP客户端工具 okhttp3 form/json/multipart
提供表达、json、混合表单、混合表单文件流传输等HTTP请求调用 支持自定义配置默认客户端,参数列表如下:
okhtt3. config. connectTimeout 连接超时,TimeUnit . SECONDS
okhtt3. config. readTimeOut 读取超时,TimeUnit . SECONDS
okhtt3. config. writeTimeOut 写超时,TimeUnit . SECONDS
okhtt3. config. callTimeout 流程超时,TimeUnit . SECONDS
public interface Okhttp3 {
String postRequest ( OkHttpClient httpClient, RequestBody requestBody, String url, Map < String , String > headers) throws IOException ;
}
然后就是注入我们自定义的okhttpClient,自定义配置参数如下:
@ConfigurationProperties ( prefix = "okhtt3.config" )
public class DefaultOkhttp3ClientProperties {
private Integer connectTimeout = 2 ;
private Integer readTimeout = 10 ;
private Integer writeTimeout = 10 ;
private Integer callTimeOut = 20 ;
public Integer getConnectTimeout ( ) {
return connectTimeout;
}
public void setConnectTimeout ( Integer connectTimeout) {
this . connectTimeout = connectTimeout;
}
public Integer getReadTimeout ( ) {
return readTimeout;
}
public void setReadTimeout ( Integer readTimeout) {
this . readTimeout = readTimeout;
}
public Integer getWriteTimeout ( ) {
return writeTimeout;
}
public void setWriteTimeout ( Integer writeTimeout) {
this . writeTimeout = writeTimeout;
}
public Integer getCallTimeOut ( ) {
return callTimeOut;
}
public void setCallTimeOut ( Integer callTimeOut) {
this . callTimeOut = callTimeOut;
}
}
@Configuration
@EnableConfigurationProperties ( DefaultOkhttp3ClientProperties . class )
public class Okhttp3Configuration {
@Bean
public DefaultOkhttp3 defaultOkhttp3 ( ) {
return new DefaultOkhttp3 ( ) ;
}
@Bean
@ConditionalOnMissingBean
public OkHttpClient okHttpClient ( @Autowired DefaultOkhttp3ClientProperties defaultOkhttp3ClientProperties) {
X509TrustManager x509TrustManager = trustManager ( ) ;
final SSLContext sslContext;
try {
sslContext = SSLContext . getInstance ( "SSL" ) ;
sslContext. init ( null , new TrustManager [ ] { x509TrustManager} , new java. security. SecureRandom( ) ) ;
} catch ( Exception e) {
throw new RuntimeException ( e) ;
}
final SSLSocketFactory sslSocketFactory = sslContext. getSocketFactory ( ) ;
OkHttpClient. Builder builder = new OkHttpClient. Builder ( ) ;
builder. sslSocketFactory ( sslSocketFactory, x509TrustManager) ;
builder. hostnameVerifier ( ( hostname, session) -> true ) ;
builder. connectTimeout ( defaultOkhttp3ClientProperties. getConnectTimeout ( ) , TimeUnit . SECONDS) ;
builder. readTimeout ( defaultOkhttp3ClientProperties. getReadTimeout ( ) , TimeUnit . SECONDS) ;
builder. writeTimeout ( defaultOkhttp3ClientProperties. getWriteTimeout ( ) , TimeUnit . SECONDS) ;
builder. callTimeout ( defaultOkhttp3ClientProperties. getCallTimeOut ( ) , TimeUnit . SECONDS) ;
return builder. build ( ) ;
}
private static X509TrustManager trustManager ( ) {
return new X509TrustManager ( ) {
@Override
public void checkClientTrusted ( X509Certificate [ ] chain, String authType) {
}
@Override
public void checkServerTrusted ( X509Certificate [ ] chain, String authType) {
}
@Override
public X509Certificate [ ] getAcceptedIssuers ( ) {
return new X509Certificate [ 0 ] ;
}
} ;
}
}
下面就是我们应对何种复杂业务的实现了,简单的表单请求、JSON请求,到文件上传,接着就是文件流传输等等,针对大文件的传入,直接通过网络流传递,避免内存问题。下面是各种需求的实现
public class DefaultOkhttp3 implements Okhttp3 {
@Override
public String postRequest ( OkHttpClient httpClient, RequestBody requestBody, String url, Map < String , String > headers) throws IOException {
Call call = makeRequestCall ( httpClient, requestBody, url, headers) ;
return postRequest ( call) ;
}
public String buildUrlIncludeQueryParams ( String url, Map < String , String > queryParams) {
HttpUrl. Builder builder = Objects . requireNonNull ( HttpUrl . parse ( url) ) . newBuilder ( ) ;
queryParams. forEach ( builder:: addQueryParameter ) ;
return builder. build ( ) . toString ( ) ;
}
public RequestBody buildJsonRequestBody ( String json) {
return RequestBody . create ( json, MediaType . parse ( "application/json; charset=utf-8" ) ) ;
}
public RequestBody buildFormRequestBody ( Map < String , String > formBody) {
FormBody. Builder builder = new FormBody. Builder ( ) ;
formBody. forEach ( builder:: add ) ;
return builder. build ( ) ;
}
public RequestBody buildMultipartRequestBodyOfFiles ( Map < String , String > formBody, Map < String , FilePat > fileMap) {
MultipartBody. Builder builder = new MultipartBody. Builder ( ) ;
builder. setType ( MultipartBody . FORM) ;
formBody. forEach ( builder:: addFormDataPart ) ;
fileMap. forEach ( ( k, v) -> builder. addFormDataPart ( k, v. getFile ( ) . getName ( ) , RequestBody . create ( v. getFile ( ) , v. getMediaType ( ) ) ) ) ;
return builder. build ( ) ;
}
public RequestBody buildMultipartFilesRequestBody ( Map < String , String > formBody, Map < String , MultipartFile > fileMap) {
MultipartBody. Builder builder = new MultipartBody. Builder ( ) ;
builder. setType ( MultipartBody . FORM) ;
formBody. forEach ( builder:: addFormDataPart ) ;
fileMap. forEach ( ( k, v) -> {
try {
builder. addFormDataPart ( k, v. getName ( ) , RequestBody . create ( v. getBytes ( ) , MediaType . get ( Objects . requireNonNull ( v. getContentType ( ) ) ) ) ) ;
} catch ( IOException e) {
throw new RuntimeException ( e) ;
}
} ) ;
return builder. build ( ) ;
}
public RequestBody buildMultipartFilesInputStreamRequestBody ( Map < String , String > formBody, Map < String , MultipartFile > fileMap) {
MultipartBody. Builder builder = new MultipartBody. Builder ( ) ;
builder. setType ( MultipartBody . FORM) ;
formBody. forEach ( builder:: addFormDataPart ) ;
fileMap. forEach ( ( k, v) -> {
builder. addFormDataPart ( k, v. getOriginalFilename ( ) , new RequestBody ( ) {
@NotNull
@Override
public MediaType contentType ( ) {
return MediaType . get ( Objects . requireNonNull ( v. getContentType ( ) ) ) ;
}
@Override
public long contentLength ( ) {
return v. getSize ( ) ;
}
@Override
public void writeTo ( @NotNull BufferedSink bufferedSink) throws IOException {
try ( InputStream inputStream = v. getInputStream ( ) ) {
byte [ ] buffer = new byte [ 2048 ] ;
int len;
while ( ( len = inputStream. read ( buffer) ) != - 1 ) {
bufferedSink. write ( buffer, 0 , len) ;
bufferedSink. flush ( ) ;
}
}
}
} ) ;
} ) ;
return builder. build ( ) ;
}
public static class FilePat {
private File file;
private MediaType mediaType;
public File getFile ( ) {
return file;
}
public void setFile ( File file) {
this . file = file;
}
public MediaType getMediaType ( ) {
return mediaType;
}
public void setMediaType ( MediaType mediaType) {
this . mediaType = mediaType;
}
}
private Call makeRequestCall ( OkHttpClient httpClient, RequestBody body, String reqUrl, Map < String , String > headers) {
Request. Builder reqBuilder = new Request. Builder ( ) ;
reqBuilder. url ( reqUrl) . post ( body) ;
if ( headers != null && ! headers. isEmpty ( ) ) {
for ( Map. Entry < String , String > entry : headers. entrySet ( ) ) {
reqBuilder. header ( entry. getKey ( ) , entry. getValue ( ) ) ;
}
}
return httpClient. newCall ( reqBuilder. build ( ) ) ;
}
private String postRequest ( Call call) throws IOException {
try ( Response resp = call. execute ( ) ) {
ResponseBody rb = resp. body ( ) ;
if ( resp. code ( ) != 200 ) {
String msg = null ;
if ( rb != null ) {
msg = rb. string ( ) ;
}
throw new IOException ( "http code: " + resp. code ( ) + ( msg != null ? ",msg:" + msg : "" ) ) ;
}
if ( rb == null ) {
throw new IllegalStateException ( "http response body is null" ) ;
}
return rb. string ( ) ;
}
}
}