您的位置:首页 > 教育 > 培训 > 东莞做网页公司_杭州网络科技公司有哪些_互联网宣传方式有哪些_b2b外贸接单平台

东莞做网页公司_杭州网络科技公司有哪些_互联网宣传方式有哪些_b2b外贸接单平台

2024/12/28 15:14:21 来源:https://blog.csdn.net/qq_43350524/article/details/144699561  浏览:    关键词:东莞做网页公司_杭州网络科技公司有哪些_互联网宣传方式有哪些_b2b外贸接单平台
东莞做网页公司_杭州网络科技公司有哪些_互联网宣传方式有哪些_b2b外贸接单平台

HTTP组件库

文章目录

  • HTTP组件库
    • 一:HttpURLConnection
      • 1:使用流程如下
      • 2:HttpURLConnection使用的方法
      • 3:get / post演示
      • 4:其他说明
    • 二:Apache HttpClient
      • 1:获取客户端
      • 2:配置参数
      • 3:请求头的设置
      • 4:get / post请求发送
      • 5:实用功能:上传、下载
      • 6:响应数据
      • 6:会话保持
    • 三:OkHttp
      • 1:方法流程和依赖导入
      • 2:get请求
      • 3:post请求
      • 4:完整工具类,可以直接使用
    • 四:forest:声明式HTTP客户端
      • 1:四步急速入门
      • 2:发送JSON数据
      • 3:发送XML数据
      • 4:发送Protoful数据
      • 5:文件上传和下载
      • 6:auth验证
      • 7:自定义注解

先来了解下 Java 生态中的 HTTP 组件库,大致可以分为三类:

  • JDK 自带的 HttpURLConnection 标准库;
  • Apache HttpComponents HttpClient;
  • OkHttp。

一:HttpURLConnection

使用 HttpURLConnection 发起 HTTP 请求最大的优点是不需要引入额外的依赖

缺点使用起来非常繁琐,也缺乏连接池管理、域名机械控制等特性的支持。

就像直接使用 JDBC 连接数据库那样,需要很多模板代码。

HttpURLConnection是基于http协议的,支持GET、POST、PUT、DELETE等各种请求方式。如果使用HTTPS协议请求,可以使用它的子类HttpsURLConnection完成更安全的请求操作。

1:使用流程如下

在这里插入图片描述

2:HttpURLConnection使用的方法

设置连接参数的方法

方法名说明
setAllowUserInteraction如果为 true,则在允许用户交互的上下文中对此 URL 进行检查
setDoInputURL 连接可用于输入和/或输出
如果打算使用 URL 连接进行输入,则将 DoInput 标志设置为 true;
如果不打算使用,则设置为 false。默认值为 true
setDoOutputURL 连接可用于输入和/或输出。
如果打算使用 URL 连接进行输出,则将 DoOutput 标志设置为 true;
如果不打算使用,则设置为 false。默认值为 false
setIfModifiedSince有些协议支持跳过对象获取,除非该对象在某个特定时间点之后又进行了修改
setUseCaches如果为 true,则只要有条件就允许协议使用缓存。
setDefaultAllowUserInteraction默认值为 “sticky”,它是所有 URLConnection 的其中一种静态状态。
此标志适用于下一个及后续创建的所有 URLConnection。
setDefaultUseCaches将此 URLConnectionuseCaches 字段的值设置为指定的值。

设置请求头或者响应体

方法说明
setRequestProperty(key,value)设置一般请求属性。如果已存在具有该关键字的属性,则用新值改写其值。
注:HTTP 要求所有能够合法拥有多个具有相同键的实例的请求属性,使用以逗号分隔的列表语法,这样可实现将多个属性添加到一个属性中。
addRequestProperty(key,value)添加由键值对指定的一般请求属性。此方法不会改写与相同键关联的现有值

发送URL请求

方法说明
getOutputStream建立实际连接之后,就是发送请求,把请求参数传到服务器
这就需要使用outputStream把请求参数传给服务器

获取响应

方法说明
getContent检索此 URL 连接的内容;
getHeaderField返回第 n 个头字段的值。如果少于 n+1 个字段,则返回 null。此方法可与 getHeaderFieldKey 方法配合使用,以迭代消息中的所有头
getInputStream返回从此打开的连接读取的输入流。
在读取返回的输入流时,如果在数据可供读取之前达到读入超时时间,则会抛出 SocketTimeoutException。
getResponseCode获取服务器的响应代码
getResponseMessage获取服务器的响应消息
getResponseMethod获取发送请求的方法

相应的信息头用以下方法获取

方法说明
getContentEncoding返回 content-encoding 头字段的值
getContentLength返回 content-length 头字段的值。
getContentType返回 content-type 头字段的值。
getDate返回 date 头字段的值。
getExpiration返回 expires 头字段的值。

3:get / post演示

package com.example.bootrocketmq.study.wheel.httpclient;import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;/*** @author cui haida* 2024/12/24*/
@Slf4j
public class HttpURLConnectionDemo {public static void main(String[] args) throws IOException {String api = "http://www.baidu.com";getTest(api);testDoPost();}public static void getTest(String api) {HttpURLConnection connection = null;InputStream in = null;BufferedReader reader = null;try {//构造一个URL对象URL url = new URL(api);//获取URLConnection对象connection= (HttpURLConnection) url.openConnection();//getOutputStream会隐含的进行connect(即:如同调用上面的connect()方法,所以在开发中不调用connect()也可以)in = connection.getInputStream();//通过InputStreamReader将字节流转换成字符串,在通过BufferedReader将字符流转换成自带缓冲流reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));StringBuilder sb = new StringBuilder();String line;//按行读取while ((line = reader.readLine()) != null) {sb.append(line);}String response= sb.toString();System.out.println(response);} catch (Exception e) {log.error("error: ", e);} finally {if (connection != null) {connection.disconnect();}if (in != null) {try {in.close();} catch (IOException e) {log.error("error: ", e);}}if (reader != null) {try {reader.close();} catch (IOException e) {log.error("error: ", e);}}}}public static void testDoPost() throws IOException {String apiUrl = "";String username  = "cuihaida";String password  = "123456";String tenantUrl = "";HttpURLConnection conn = null;OutputStream out = null;InputStream in = null;String idToken = null;try{// 构造一个URL对象URL url = new URL(apiUrl);// 获取URLConnection对象conn = (HttpURLConnection) url.openConnection();// 限制socket等待建立连接的时间,超时将会抛出java.net.SocketTimeoutExceptionconn.setConnectTimeout(3000);// 限制输入流等待数据到达的时间,超时将会抛出java.net.SocketTimeoutExceptionconn.setReadTimeout(3000);// 设定请求的方法为"POST",默认是GETconn.setRequestMethod("POST");// 设置传送的内容类型是json格式conn.setRequestProperty("Content-Type", "application/json;charset=utf-8");// 接收的内容类型也是json格式conn.setRequestProperty("Accept", "application/json;charset=utf-8");// 设置是否从httpUrlConnection读入,默认情况下是trueconn.setDoInput(true);// 由于URLConnection在默认的情况下不允许输出,所以在请求输出流之前必须调用setDoOutput(true)。为一个HTTP URL将doOutput设置为true时,请求方法将由GET变为POSTconn.setDoOutput(true);// 是否使用缓存,Post方式不能使用缓存conn.setUseCaches(false);// 准备数据JSONObject json = new JSONObject();json.put("username", username);json.put("password", DigestUtils.md5Hex(password));json.put("tenantUrl", tenantUrl);// 返回一个OutputStream,可以用来写入数据传送给服务器out = conn.getOutputStream();// 将数据写入到输出流中out.write(json.toString().getBytes(StandardCharsets.UTF_8));// 刷新管道out.flush();// 建立连接conn.connect();// 判断数字响应码是否是200int responseCode = conn.getResponseCode();String result="";if (responseCode == 200) {// 获取输入流in = conn.getInputStream();// 获取返回的内容StringWriter sw = new StringWriter();InputStreamReader reader = new InputStreamReader(in, StandardCharsets.UTF_8);char[] buffer = new char[4096];for (int n = 0; -1 != (n = reader.read(buffer)); ) {sw.write(buffer, 0, n);}result = sw.toString();System.out.println(result);}}catch (Exception exception){exception.printStackTrace();}finally {if (conn != null) {conn.disconnect();}if (out != null) {out.close();}if (in != null) {in.close();}}}
}

4:其他说明

HttpURLConnection 发起的 HTTP 请求比较原始,基本上算是对网络传输层的一次浅层次的封装;

有了 HttpURLConnection 对象后,就可以获取到输出流,然后把要发送的内容发送出去;再通过输入流读取到服务器端响应的内容;最后打印。

不过 HttpURLConnection 不支持 HTTP/2.0,为了解决这个问题,Java 9 的时候官方的标准库增加了一个更高级别的 HttpClient,再发起 POST 请求就显得高大上多了,不仅支持异步,还支持顺滑的链式调用。

public class HttpClientDemo {public static void main(String[] args) throws URISyntaxException {HttpClient client = HttpClient.newHttpClient();HttpRequest request = HttpRequest.newBuilder().uri(new URI("https://postman-echo.com/post")).headers("Content-Type", "text/plain;charset=UTF-8").POST(HttpRequest.BodyPublishers.ofString("牛逼")).build();client.sendAsync(request, HttpResponse.BodyHandlers.ofString()).thenApply(HttpResponse::body).thenAccept(System.out::println).join();}
}

二:Apache HttpClient

HttpClient 相比传统 JDK 自带的 URLConnection,增加了易用性和灵活性,它不仅是客户端发送 HTTP 请求变得容易,而且也方便了开发人员测试接口(基于 HTTP 协议的),即提高了开发的效率,也方便提高代码的健壮性

<!-- http client 4.X -->
<dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.13</version>
</dependency><!-- 此处使用的是 5.x 版本,可以根据自身情况引入版本 -->
<dependency><groupId>org.apache.httpcomponents.client5</groupId><artifactId>httpclient5</artifactId><version>5.1.1</version>
</dependency>

1:获取客户端

有下面三种方式可以获取到对应的客户端,分别如下:

// 获取默认配置的 HttpClient 
CloseableHttpClient httpClient = HttpClients.createDefault();// 此种方式是通过 根据 系统配置创建 HttpClient
// 在项目启动时可以通过设置如下JVM启动参数:
// 1:http.agent 配置 userAgent
// 2:http.keepAlive 配置 keepAlive 数据
CloseableHttpClient httpClient = HttpClients.createSystem();// 此种方式可以在创建时 设置一些默认值
CloseableHttpClient  httpClient = HttpClients.custom().setDefaultHeaders(Collections.emptyList())   // 设置默认请求头.setDefaultRequestConfig(RequestConfig.DEFAULT)  // 设置默认配置.build();

2:配置参数

HttpClient 可以通过在创建 HttpClient 对象时就设置全局配置,也可以为单个请求设置请求配置

创建配置对象

  //  创建请求配置信息
RequestConfig  requestConfig = RequestConfig.custom()// 设置连接超时时间.setConnectTimeout(Timeout.of(3000, TimeUnit.MILLISECONDS))// 设置响应超时时间.setResponseTimeout(3000, TimeUnit.MILLISECONDS) // 设置从连接池获取链接的超时时间.setConnectionRequestTimeout(3000, TimeUnit.MILLISECONDS).build();

全局配置

// 此种方式可以在创建时 设置一些默认值
CloseableHttpClient  httpClient = HttpClients.custom().setDefaultHeaders(Collections.emptyList())   // 设置默认请求头.setDefaultRequestConfig(requestConfig)  // 设置默认配置.build();

单个请求配置

// 创建 GET 请求对象
HttpGet httpGet = new HttpGet(uri);// 设置请求参数
httpGet.setConfig(requestConfig);

3:请求头的设置

在请求时,经常会遇到设置自定义请求头,或者更改 Conent-Type 的值,可以通过如下两种方式设置:

设置公共请求头

List<Header> headers = new ArrayList<>();
headers.add(new BasicHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON));
headers.add(new BasicHeader(HttpHeaders.ACCEPT_ENCODING, "gzip, x-gzip, deflate"));
headers.add(new BasicHeader(HttpHeaders.CONNECTION, "keep-alive"));// 创建 一个默认的 httpClient
CloseableHttpClient  httpClient = HttpClients.custom().setDefaultHeaders(headers)   // 设置默认请求头.build()

设置单个请求的请求头

// 创建 POST 请求
HttpPost httpPost = new HttpPost(uri);
// 添加 Content-Type 请求头
httpPost.addHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED);
// 添加 accept 请求头
httpPost.addHeader(new BasicHeader(HttpHeaders.ACCEPT, "*/*"));

4:get / post请求发送

get请求
GET请求的所有参数是直接拼接在 URL 后面的,在 HttpClient 中 有两种方式可以实现,如下所示:

// ======= 方式一:参数直接拼接在url后面的方式=========
// 此方式表示提供了一个完整的url相当于
String name = URLEncoder.encode("张三", "utf-8");
// 请求路径及参数
String url = "http://localhost:10010/user/params?age=20&name=" + name;// 创建 GET 请求对象
HttpGet httpGet = new HttpGet(url);
// 调用 HttpClient 的 execute 方法执行请求
CloseableHttpResponse response = httpClient.execute(httpGet);
// 获取请求状态
int code = response.getCode();
// 如果请求成功
if(code == HttpStatus.SC_OK){LOGGER.info("响应结果为:{}", EntityUtils.toString(response.getEntity()));
}// ======= 方式二:通过 URIBuilder 构建请求路径 =========
// 构建请求路径,及参数
URL url = new URL("http://localhost:10010/user/params");
URI uri = new URIBuilder().setScheme(url.getProtocol()).setHost(url.getHost()).setPort(url.getPort()).setPath(url.getPath())// 构建参数.setParameters(new BasicNameValuePair("name", "张三"),new BasicNameValuePair("age", "20")).build();// 创建 GET 请求对象
HttpGet httpGet = new HttpGet(uri);
// 调用 HttpClient 的 execute 方法执行请求
CloseableHttpResponse response = httpClient.execute(httpGet);
// 获取请求状态
int code = response.getCode();
// 如果请求成功
if(code == HttpStatus.SC_OK){LOGGER.info("响应结果为:{}", EntityUtils.toString(response.getEntity()));
}

post
HTTP 中的 POST 请求的数据是包含在请求体中的。在 HttpClient 中 POST 请求发送数据是通过,调用 HttpPost 类的 setEntity(HttpEntity entity) 方法设置消息内容的。

1:JSON数据的发送

// HttpClient 中发送 JSON 数据可以使用 StringHttpEntity 类实现,如下所示:// 请求参数
String url = "http://localhost:10010/user/body";
// 创建 GET 请求对象
HttpPost httpPost = new HttpPost(url);
// 构建对象
User user = new User();
user.setName("张三").setAge(20).setAddress(new Address().setCounty("中国").setCity("北京")).setAihao(Arrays.asList("跑步", "爬山", "看书"));// 创建 字符串实体对象
HttpEntity httpEntity = new StringEntity(JSON.toJSONString(user));
httpPost.setEntity(httpEntity);// 发送 POST 请求
httpClient.execute(httpPost);

2:模拟form表单

// 创建 ContentType 对象为 form 表单模式 
ContentType contentType = ContentType.create("application/x-www-form-urlencoded", StandardCharsets.UTF_8);
// 添加到 HttpPost 头中
httpPost.setHeader(HttpHeaders.CONTENT_TYPE, contentType);// 方式一、自己拼接请求数据,并且创建 StringEntity 对象
String query = "name="+ URLEncoder.encode("张三", "utf-8") +"&age=20";
HttpEntity httpEntity = new StringEntity(query);// 方式二、通过UrlEncodedFormEntity 创建 HttpEntity
HttpEntity httpEntity = new UrlEncodedFormEntity(Arrays.asList(new BasicNameValuePair("name", "张三"),new BasicNameValuePair("age", "20")),StandardCharsets.UTF_8
);// 把 HttpEntity 设置到 HttpPost 中
httpPost.setEntity(httpEntity);

完整代码如下:

// 创建 POST 请求对象
HttpPost httpPost = new HttpPost("http://localhost:10010/user/map");
/*String query = "name="+ URLEncoder.encode("张三", "utf-8") +"&age=20";HttpEntity httpEntity = new StringEntity(query);*/HttpEntity httpEntity = new UrlEncodedFormEntity(Arrays.asList(new BasicNameValuePair("name", "张三"),new BasicNameValuePair("age", "20")),StandardCharsets.UTF_8
);// 设置请求数据
httpPost.setEntity(httpEntity);
// 设置请求头
ContentType contentType = ContentType.APPLICATION_FORM_URLENCODED.withCharset(StandardCharsets.UTF_8);
httpPost.setHeader(HttpHeaders.CONTENT_TYPE, contentType);
// 调用 HttpClient 的 execute 方法执行请求
CloseableHttpResponse response = httpClient.execute(httpPost);
// 获取请求状态
int code = response.getCode();
// 如果请求成功
if(code == HttpStatus.SC_OK){LOGGER.info("响应结果为:{}", EntityUtils.toString(response.getEntity()));
}

5:实用功能:上传、下载

上传

//要上传的文件
File file = new File("F:/20150703212056_Yxi4L.jpeg");// 创建对象
MultipartEntityBuilder builder = MultipartEntityBuilder.create();// 添加二进制消息体
builder.addBinaryBody("file", file);// 也可以添加文本消息
ContentType contentType = ContentType.TEXT_PLAIN.withCharset(StandardCharsets.UTF_8);
builder.addTextBody("name", "张三", contentType);// 通过 MultipartEntityBuilder 构建消息体
HttpEntity httpEntity = builder.build();
HttpPost httpPost = new HttpPost("http://localhost:10010/user/upload");
httpPost.setEntity(httpEntity);
CloseableHttpResponse response = httpClient.execute(httpPost);
// 获取请求状态
int code = response.getCode();
// 如果请求成功
if(code == HttpStatus.SC_OK){LOGGER.info("响应结果为:{}", EntityUtils.toString(response.getEntity()));
}

下载

// 请求下载路径
HttpGet httpGet = new HttpGet("http://localhost:10010/user/downLoad");
CloseableHttpResponse response = httpClient.execute(httpGet);// 如果请求成功
if (response.getCode() == HttpStatus.SC_OK){// 获取下载文件的文件名,此处的 File-Name 头信息,需要在服务端进行自定义Header header = response.getFirstHeader("File-Name");String value = header.getValue();// 读取数据byte[] bytes = EntityUtils.toByteArray(response.getEntity());try (OutputStream outputStream = new FileOutputStream("F:/" + value);){outputStream.write(bytes);outputStream.flush();}
}

6:响应数据

在 HttpClient 中把响应封装成了 CloseableHttpResponse 对象,在此对象中可以获取如下数据:

  • getCode() 获取响应状态
  • getEntity() 获取响应数据

HttpClient 提供了 EntityUtils工具类,可以很好的把 响应的 HttpEntity 转换为 字节数组或者字符串

// 转换为字符串
EntityUtils.toString(response.getEntity());// 转换为字节数组
EntityUtils.toByteArray(response.getEntity());

除了上述外,还可以在 调用 HttpClient 的 execute()方法时 传入,响应处理器,返回自定义的数据类型。如下所示,是返回一个 自定义的 Response 对象


// 自定义响应对象
@Data
@Accessors(chain = true)
class  Response {// 响应状态private int code;// 响应描述private String msg;// 响应体private String body;
}// 调用  execute 时自定义 响应处理类Response execute = httpClient.execute(httpGet, response -> {return new Response().setCode(response.getCode()).setMsg(response.getReasonPhrase()).setBody(EntityUtils.toString(response.getEntity(),                 StandardCharsets.UTF_8));});

6:会话保持

在实际项目中,经常会遇到需要先登录然后才能进行访问其他接口,那么, 在 HttpClient 中提供了 HttpClientContext 类,可以很好的实现,会话保持功能。

创建HttpClientContext在 execute() 方法中传入 第一步创建的对象,如下所示:


// 创建 HttpClientContext对象
HttpContext httpContext = new BasicHttpContext();
httpContext.setAttribute("name", "zhangsan");
HttpClientContext httpClientContext = HttpClientContext.adapt(httpContext);// 登录
httpClient.execute(new HttpPost(""), httpClientContext);// 获取数据
httpClient.execute(new HttpGet(""), httpClientContext);

三:OkHttp

OkHttp 是一个执行效率比较高的 HTTP 客户端:

  • 支持 HTTP/2.0,当多个请求对应同一个 Host 地址时,可共用同一个 Socket;
  • 连接池可减少请求延迟;
  • 支持 GZIP 压缩,减少网络传输的数据大小;
  • 支持 Response 数据缓存,避免重复网络请求;

1:方法流程和依赖导入

在这里插入图片描述

<!--okhttp3-->
<dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</artifactId><version>4.9.1</version>
</dependency>
<dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.5</version>
</dependency>

2:get请求

get无参

/*** 以get方式调用第三方接口* @param url*/
public static void doGet1(String url) throws IOException {OkHttpClient okHttpClient = new OkHttpClient();final Request request = new Request.Builder().url(url).get()//默认就是GET请求,可以不写.build();Response response = okHttpClient.newCall(request).execute();String string = response.body().string();System.out.println(string);
}

get有参

public static void doGet2(String url, Map<String, Object> paramMap) throws IOException {OkHttpClient okHttpClient = new OkHttpClient();Request.Builder requestbuilder = new Request.Builder().get();//默认就是GET请求,可以不写StringBuilder urlbuilder = new StringBuilder(url);if (Objects.nonNull(paramMap)) {urlbuilder.append("?");paramMap.forEach((key, value) -> {try {urlbuilder.append(URLEncoder.encode(key, "utf-8")).append("=").append(URLEncoder.encode((String) value, "utf-8")).append("&");} catch (UnsupportedEncodingException e) {e.printStackTrace();}});urlbuilder.deleteCharAt(urlbuilder.length() - 1);}Request request = requestbuilder.url(urlbuilder.toString()).build();Response response = okHttpClient.newCall(request).execute();String string = response.body().string();System.out.println(string);}

get请求带有参数和请求头

/*** 以get方式调用第三方接口* @param url*/
public static void doGet3(String url, Map<String, Object> paramMap,Map<String, String> heardMap) throws IOException {OkHttpClient okHttpClient = new OkHttpClient();Request.Builder requestbuilder = new Request.Builder().get();//默认就是GET请求,可以不写//增加参数StringBuilder urlbuilder = new StringBuilder(url);if (Objects.nonNull(paramMap)) {urlbuilder.append("?");paramMap.forEach((key, value) -> {try {urlbuilder.append(URLEncoder.encode(key, "utf-8")).append("=").append(URLEncoder.encode((String) value, "utf-8")).append("&");} catch (UnsupportedEncodingException e) {e.printStackTrace();}});urlbuilder.deleteCharAt(urlbuilder.length() - 1);}//增加请求头Request.Builder heardBuilder = requestbuilder.url(urlbuilder.toString());for (Map.Entry<String, String> stringObjectEntry : heardMap.entrySet()) {heardBuilder.addHeader(stringObjectEntry.getKey(),stringObjectEntry.getValue());}Request request = heardBuilder.build();Response response = okHttpClient.newCall(request).execute();System.out.println(response.body().string());System.out.println(response.message());System.out.println(response.code());}

get另一种获取结果的方式

/*** 以get方式调用第三方接口* @param url*/
public static void doGet(String url,Map<String, Object> paramMap,Map<String, String> heardMap) {OkHttpClient okHttpClient = new OkHttpClient();Request.Builder requestbuilder = new Request.Builder().get();//默认就是GET请求,可以不写//增加参数StringBuilder urlbuilder = new StringBuilder(url);if (Objects.nonNull(paramMap)) {urlbuilder.append("?");paramMap.forEach((key, value) -> {try {urlbuilder.append(URLEncoder.encode(key, "utf-8")).append("=").append(URLEncoder.encode((String) value, "utf-8")).append("&");} catch (UnsupportedEncodingException e) {e.printStackTrace();}});urlbuilder.deleteCharAt(urlbuilder.length() - 1);}//增加请求头Request.Builder heardBuilder = requestbuilder.url(urlbuilder.toString());for (Map.Entry<String, String> stringObjectEntry : heardMap.entrySet()) {heardBuilder.addHeader(stringObjectEntry.getKey(),stringObjectEntry.getValue());}Request request = heardBuilder.build();Call call = okHttpClient.newCall(request);// 利用回调方式,call.enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {System.out.println( "onFailure: ");}@Overridepublic void onResponse(Call call, Response response) throws IOException {System.out.println(response.body().string());System.out.println(response.message());System.out.println(response.code());}});
}

3:post请求

post - json

/*** post请求* @param url* @param json*/
public static void doPost(String url, String json, Map<String, String> heardMap) throws IOException {MediaType mediaType = MediaType.parse("application/json; charset=utf-8");String requestBody = json;Request.Builder requestbuilder = new Request.Builder().url(url).post(RequestBody.create(mediaType, requestBody));//增加请求头for (Map.Entry<String, String> stringObjectEntry : heardMap.entrySet()) {requestbuilder.addHeader(stringObjectEntry.getKey(), stringObjectEntry.getValue());}Request request = requestbuilder.build();OkHttpClient okHttpClient = new OkHttpClient();Response response = okHttpClient.newCall(request).execute();System.out.println(response.body().string());System.out.println(response.message());System.out.println(response.code());
}

post-params传参

 /*** post请求* @param url* @param json*/
public static void doPost(String url, String json, Map<String, String> heardMap) throws IOException {MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");String requestBody = json;Request.Builder requestbuilder = new Request.Builder().url(url).post(RequestBody.create(mediaType, requestBody));//增加请求头for (Map.Entry<String, String> stringObjectEntry : heardMap.entrySet()) {requestbuilder.addHeader(stringObjectEntry.getKey(), stringObjectEntry.getValue());}Request request = requestbuilder.build();OkHttpClient okHttpClient = new OkHttpClient();Response response = okHttpClient.newCall(request).execute();System.out.println(response.body().string());System.out.println(response.message());System.out.println(response.code());
}
 /*** post请求* @param url* @param paramMap*/
public static void doPost1(String url, Map<String, Object> paramMap,Map<String,String> heardMap) throws IOException {FormBody.Builder formBody = new FormBody.Builder();if (Objects.nonNull(paramMap)) {paramMap.forEach((x, y) -> formBody.add(x, (String) y));}RequestBody requestBody = formBody.build();Request.Builder requestbuilder = new Request.Builder().url(url).post(requestBody);//增加请求头for (Map.Entry<String, String> stringObjectEntry : heardMap.entrySet()) {requestbuilder.addHeader(stringObjectEntry.getKey(), stringObjectEntry.getValue());}Request request = requestbuilder.build();OkHttpClient okHttpClient = new OkHttpClient();Response response = okHttpClient.newCall(request).execute();System.out.println(response.body().string());System.out.println(response.message());System.out.println(response.code());
}

post - form 文件

在这里插入图片描述

 public static void doPost2(String url,File file) throws IOException {OkHttpClient client = new OkHttpClient();RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM).addFormDataPart("id", "111").addFormDataPart("content", "{\"do_layout\":1}").addFormDataPart("file", file.getName(), RequestBody.create(MediaType.parse("text/plain"), file)).build();Request request = new Request.Builder().url(url).post(body).addHeader("x-tilake-app-key", "").addHeader("x-tilake-ca-timestamp", "").addHeader("x-tilake-ca-signature", "").addHeader("Content-Type", body.contentType().toString()).addHeader("Accept", "*/*").build();try {Response response = client.newCall(request).execute();System.out.println(response.body().string());System.out.println(response.message());System.out.println(response.code());} catch (IOException e) {throw new RuntimeException(e);}
}

4:完整工具类,可以直接使用

package com.example.httpdemo.okhttp;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.commons.io.FileUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;@Slf4j
public class OkHttpUtil {public static final String MEDIA_TYPE_JSON = "application/json; charset=utf-8";private OkHttpUtil() {}/*** 获取默认的OkHttpClient* @return*/public static OkHttpClient getOkHttpClient() {return getOkHttpClient(60, 60, 60);}public static OkHttpClient getOkHttpClient(int connectTimeout, int readTimeOut, int writeTimeOut) {OkHttpClient.Builder builder = new okhttp3.OkHttpClient().newBuilder();builder.connectTimeout(connectTimeout, TimeUnit.SECONDS);builder.readTimeout(readTimeOut, TimeUnit.SECONDS);builder.writeTimeout(writeTimeOut, TimeUnit.SECONDS);return builder.build();}/*** get请求* @param okHttpClient* @param url* @param headers header参数* @return*/public static String get(OkHttpClient okHttpClient, String url, Headers headers) {log.info("okHttpClient get url:{}.", url);Request request = new Request.Builder().url(url).headers(headers).get().build();String responseData = request(okHttpClient, url, request);log.info("okHttpClient get url:{},request responseData====> {}", url, responseData);return responseData;}public static String get(OkHttpClient okHttpClient, String url) {Headers headers = new Headers.Builder().build();return get( okHttpClient, url, headers);}/*** GET请求。使用默认的 okHttpClient 和 headers* @param url* @return*/public static String get(String url) {OkHttpClient okHttpClient = getOkHttpClient();Headers headers = new Headers.Builder().build();return get( okHttpClient, url, headers);}/*** post请求,获取响应结果** @param okHttpClient* @param url* @param bodyJson* @param headers* @return*/public static String post(OkHttpClient okHttpClient, String url, JSONObject bodyJson, Headers headers) {log.info("okHttpClient post url:{}, body====> {}", url, bodyJson);MediaType mediaTypeJson = MediaType.parse(MEDIA_TYPE_JSON);RequestBody requestBody = RequestBody.create(mediaTypeJson, JSON.toJSONString(bodyJson));Request request = new Request.Builder().url(url).headers(headers).post(requestBody).build();String responseData = request(okHttpClient, url, request);log.info("okHttpClient post url:{},post responseData====> {}", url, responseData);return responseData;}public static String post(OkHttpClient okHttpClient, String url, JSONObject bodyJson) {Headers headers = new Headers.Builder().build();return post( okHttpClient,  url,  bodyJson, headers);}/*** post请求。使用默认的 okHttpClient 和 headers* @param url* @param bodyJson* @return*/public static String post( String url, JSONObject bodyJson) {//使用默认的 okHttpClientOkHttpClient okHttpClient = getOkHttpClient();Headers headers = new Headers.Builder().build();//如果需要自定义 okHttpClient或headers传参,可以调用以下方法return post( okHttpClient,  url,  bodyJson, headers);}/*** 获取响应结果** @param okHttpClient* @param url* @param request* @return*/public static String request(OkHttpClient okHttpClient, String url, Request request) {String responseData = "";try (Response response = okHttpClient.newCall(request).execute()) {if (response != null && response.body() != null) {return response.body().string();}} catch (Exception e) {log.error("okHttpClient getResponse error.url:{}", url, e);}return responseData;}/*** 上传文件** @param okHttpClient  okHttp客户端* @param url 上传文件的url* @param fileKey       文件对应的key* @param formDataJson  form-data参数* @param headers* @param file* @return*/public static String uploadFile(OkHttpClient okHttpClient, String url,String fileKey, File file, JSONObject formDataJson, Headers headers) {log.info("uploadFile url:{}, uploadFile formDataJson====> {}", url, formDataJson);// 支持传文件的同时,传参数。MultipartBody requestBody = getMultipartBody(fileKey, file,  formDataJson);// 构建request请求体Request request = new Request.Builder().url(url).headers(headers).post(requestBody).build();String responseData = request(okHttpClient, url, request);// 会在本地产生临时文件,用完后需要删除if (file.exists()) {file.delete();}return responseData;}/*** 上传文件* @param url* @param fileKey form-data文件对应的key* @param multipartFile 文件上传对应的 multipartFile* @param formDataJson form-data参数* @return*/public static String uploadFile(String url,String fileKey, MultipartFile multipartFile, JSONObject formDataJson) {//使用默认的okHttpClientOkHttpClient okHttpClient = getOkHttpClient();Headers headers = new Headers.Builder().build();return uploadFile(okHttpClient, url, fileKey, getFile(multipartFile), formDataJson, headers);}public static String uploadFile(OkHttpClient okHttpClient, String url,String fileKey, File file, JSONObject formDataJson) {Headers headers = new Headers.Builder().build();return uploadFile(okHttpClient, url,  fileKey, file, formDataJson, headers);}/*** 上传文件* 使用默认的okHttpClient** @param url* @param fileKey form-data文件对应的key* @param file 文件* @param formDataJson form-data参数* @return*/public static String uploadFile(String url,String fileKey, File file, JSONObject formDataJson) {//使用默认的okHttpClientOkHttpClient okHttpClient = getOkHttpClient();Headers headers = new Headers.Builder().build();return uploadFile(okHttpClient, url, fileKey, file, formDataJson, headers);}/*** 上传文件用。构建form-data 参数** @param fileKey       文件对应的key* @param file          文件* @param formDataJson  form-data参数* @return*/public static MultipartBody getMultipartBody(String fileKey, File file, JSONObject formDataJson) {RequestBody fileBody = RequestBody.create(MultipartBody.FORM, file);MultipartBody.Builder bodyBuilder = new MultipartBody.Builder();// 设置传参为form-data格式bodyBuilder.setType(MultipartBody.FORM);bodyBuilder.addFormDataPart(fileKey, file.getName(), fileBody);// 添加 form-data参数for (Map.Entry<String, Object> entry : formDataJson.entrySet()) {//参数通过 bodyBuilder.addFormDataPart(key, value) 添加bodyBuilder.addFormDataPart(entry.getKey(), Objects.toString(entry.getValue(),""));}return bodyBuilder.build();}/*** 获取文件* @param multipartFile* @return*/public static File getFile(MultipartFile multipartFile) {File file = new File(Objects.requireNonNull(multipartFile.getOriginalFilename()));try {FileUtils.copyInputStreamToFile(multipartFile.getInputStream(), file);} catch (IOException e) {log.error("copyInputStreamToFile error.", e);}return file;}
}

四:forest:声明式HTTP客户端

在这里插入图片描述
轻量级的 HTTP 客户端框架 Forest,正是基于 Httpclient和OkHttp 的,屏蔽了不同细节的 HTTP 组件库所带来的所有差异。

Forest 的字面意思是森林的意思,更内涵点的话,可以拆成For和Rest两个单词,也就是“为了Rest”(Rest为一种基于HTTP的架构风格)。

而合起来就是森林,森林由很多树木花草组成(可以理解为各种不同的服务),它们表面上看独立,实则在地下根茎交错纵横、相互连接依存,这样看就有点现代分布式服务化的味道了。

最后,这两个单词反过来读就像是Resultful。

项目地址:

https://gitee.com/dromara/forest

Forest 本身是处理前端过程的框架,是对后端 HTTP API 框架的进一步封装。
在这里插入图片描述

1:四步急速入门

1:添加依赖

<!-- forest -->
<dependency><groupId>com.dtflys.forest</groupId><artifactId>forest-spring-boot-starter</artifactId><version>1.6.0</version>
</dependency>

2:创建接口


package com.yoursite.client;import com.dtflys.forest.annotation.Request;
import com.dtflys.forest.annotation.DataParam;public interface AmapClient {/*** @Get注解代表该方法专做GET请求* 在url中的{0}代表引用第一个参数,{1}引用第二个参数*/@Get("http://ditu.amap.com/service/regeo?longitude={0}&latitude={1}")Map getLocation(String longitude, String latitude);
}

3:扫描接口
在Spring Boot的配置类或者启动类上加上@ForestScan注解,并在basePackages属性里填上远程接口的所在的包名

@SpringBootApplication
@Configuration
@ForestScan(basePackages = "com.yoursite.client")
public class MyApplication {public static void main(String[] args) {SpringApplication.run(MyApplication.class, args);}
}

4:进行bean调用

// 注入接口实例
@Autowired
private AmapClient amapClient;
...
// 调用接口
Map result = amapClient.getLocation("121.475078", "31.223577");
System.out.println(result);

2:发送JSON数据

/*** 将对象参数解析为JSON字符串,并放在请求的Body进行传输*/
@Post("/register")
String registerUser(@JSONBody MyUser user);/*** 将Map类型参数解析为JSON字符串,并放在请求的Body进行传输*/
@Post("/test/json")
String postJsonMap(@JSONBody Map mapObj);/*** 直接传入一个JSON字符串,并放在请求的Body进行传输*/
@Post("/test/json")
String postJsonText(@JSONBody String jsonText);

3:发送XML数据

/*** 将一个通过JAXB注解修饰过的类型对象解析为XML字符串* 并放在请求的Body进行传输*/
@Post("/message")
String sendXmlMessage(@XMLBody MyMessage message);/*** 直接传入一个XML字符串,并放在请求的Body进行传输*/
@Post("/test/xml")
String postXmlBodyString(@XMLBody String xml);

4:发送Protoful数据

/*** ProtobufProto.MyMessage 为 Protobuf 生成的数据类* 将 Protobuf 生成的数据对象转换为 Protobuf 格式的字节流* 并放在请求的Body进行传输* * 注: 需要引入 google protobuf 依赖*/
@Post(url = "/message", contentType = "application/octet-stream")
String sendProtobufMessage(@ProtobufBody ProtobufProto.MyMessage message);

5:文件上传和下载

/*** 用@DataFile注解修饰要上传的参数对象* OnProgress参数为监听上传进度的回调函数*/
@Post("/upload")
Map upload(@DataFile("file") String filePath, OnProgress onProgress);// 可以用一个lambda完成对上传进度的监听
Map result = myClient.upload("D:\\TestUpload\\xxx.jpg", progress -> {System.out.println("progress: " + Math.round(progress.getRate() * 100) + "%");  // 已上传百分比if (progress.isDone()) {   // 是否上传完成System.out.println("--------   Upload Completed!   --------");}
});/*** 上传Map包装的文件列表,其中 {_key} 代表Map中每一次迭代中的键值*/
@Post("/upload")
ForestRequest<Map> uploadByteArrayMap(@DataFile(value = "file", fileName = "{_key}") Map<String, byte[]> byteArrayMap);/*** 上传List包装的文件列表,其中 {_index} 代表每次迭代List的循环计数(从零开始计)*/
@Post("/upload")
ForestRequest<Map> uploadByteArrayList(@DataFile(value = "file", fileName = "test-img-{_index}.jpg") List<byte[]> byteArrayList);
/*** 在方法上加上@DownloadFile注解* dir属性表示文件下载到哪个目录* OnProgress参数为监听上传进度的回调函数* {0}代表引用第一个参数*/
@Get("http://localhost:8080/images/xxx.jpg")
@DownloadFile(dir = "{0}")
File downloadFile(String dir, OnProgress onProgress);// 调用下载接口,可监听下载进度的百分比
File file = myClient.downloadFile("D:\\TestDownload", progress -> {System.out.println("progress: " + Math.round(progress.getRate() * 100) + "%");  // 已下载百分比if (progress.isDone()) {   // 是否下载完成System.out.println("--------   Download Completed!   --------");}
});

6:auth验证

@Post("/hello/user?username={username}")
@BasicAuth(username = "{username}", password = "bar")
String send(@DataVariable("username") String username);@OAuth2(tokenUri = "/auth/oauth/token",clientId = "password",clientSecret = "xxxxx-yyyyy-zzzzz",grantType = OAuth2.GrantType.PASSWORD,scope = "any",username = "root",password = "xxxxxx"
)
@Get("/test/data")
String getData();

7:自定义注解

Forest允许您根据需要自行定义注解,不但让您可以简单优雅得解决各种需求,而且极大得扩展了Forest的能力。

定义一个注解

/*** 用Forest自定义注解实现一个自定义的签名加密注解* 凡用此接口修饰的方法或接口,其对应的所有请求都会执行自定义的签名加密过程* 而自定义的签名加密过程,由这里的@MethodLifeCycle注解指定的生命周期类进行处理* 可以将此注解用在接口类和方法上*/
@Documented
/** 重点: @MethodLifeCycle注解指定该注解的生命周期类*/
@MethodLifeCycle(MyAuthLifeCycle.class)
@RequestAttributes
@Retention(RetentionPolicy.RUNTIME)
/** 指定该注解可用于类上或方法上 */
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface MyAuth {/** * 自定义注解的属性:用户名* 所有自定注解的属性可以在生命周期类中被获取到*/String username();/** * 自定义注解的属性:密码* 所有自定注解的属性可以在生命周期类中被获取到*/String password();
}

定义注解生命周期类

/***  MyAuthLifeCycle 为自定义的 @MyAuth 注解的生命周期类* 因为 @MyAuth 是针对每个请求方法的,所以它实现自 MethodAnnotationLifeCycle 接口* MethodAnnotationLifeCycle 接口带有泛型参数* 第一个泛型参数是该生命周期类绑定的注解类型* 第二个泛型参数为请求方法返回的数据类型,为了尽可能适应多的不同方法的返回类型,这里使用 Object*/
public class MyAuthLifeCycle implements MethodAnnotationLifeCycle<MyAuth, Object> {/*** 当方法调用时调用此方法,此时还没有执行请求发送* 次方法可以获得请求对应的方法调用信息,以及动态传入的方法调用参数列表*/@Overridepublic void onInvokeMethod(ForestRequest request, ForestMethod method, Object[] args) {System.out.println("Invoke Method '" + method.getMethodName() + "' Arguments: " + args);}/*** 发送请求前执行此方法,同拦截器中的一样*/@Overridepublic boolean beforeExecute(ForestRequest request) {// 通过getAttribute方法获取自定义注解中的属性值// getAttribute第一个参数为request对象,第二个参数为自定义注解中的属性名String username = (String) getAttribute(request, "username");String password = (String) getAttribute(request, "password");// 使用Base64进行加密String basic = "MyAuth " + Base64Utils.encode("{" + username + ":" + password + "}");// 调用addHeader方法将加密结构加到请求头MyAuthorization中request.addHeader("MyAuthorization", basic);return true;}/*** 此方法在请求方法初始化的时候被调用*/@Overridepublic void onMethodInitialized(ForestMethod method, BasicAuth annotation) {System.out.println("Method '" + method.getMethodName() + "' Initialized, Arguments: " + args);}
}

使用自定义的注解

/*** 在请求接口上加上自定义的 @MyAuth 注解* 注解的参数可以是字符串模板,通过方法调用的时候动态传入* 也可以是写死的字符串*/
@Get("/hello/user?username={username}")
@MyAuth(username = "{username}", password = "bar")
String send(@DataVariable("username") String username);
编程式请求
Forest 的编程式请求支持链式调用,极为方便、高效、简洁// GET 请求访问百度
String baidu = Forest.get("http://www.baidu.com").execute(String.class);// POST 请求注册用户信息
String result = Forest.post("/user/register").contentType("application/json").addBody("username", "公子骏").addBody("password", "12345678").execute(String.class);

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com