From ef75e3988a0936829e92d6f35085143970d0a66d Mon Sep 17 00:00:00 2001 From: hekaiyu <13673834656@163.com> Date: Tue, 9 Dec 2025 13:00:56 +0800 Subject: [PATCH] =?UTF-8?q?httpclient=E8=B0=83=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../properties/HttpClientHostProperties.java | 17 + .../controller/OceanFeignController.java | 63 +++ .../org/jeecg/ocean/entity/AlarmRecord.java | 38 ++ .../java/org/jeecg/utils/HttpClientUtil.java | 377 ++++++++++++++++++ 4 files changed, 495 insertions(+) create mode 100644 jeecg-boot-base-core/src/main/java/org/jeecg/common/properties/HttpClientHostProperties.java create mode 100644 jeecg-module-large-screen/src/main/java/org/jeecg/ocean/controller/OceanFeignController.java create mode 100644 jeecg-module-large-screen/src/main/java/org/jeecg/ocean/entity/AlarmRecord.java create mode 100644 jeecg-module-large-screen/src/main/java/org/jeecg/utils/HttpClientUtil.java diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/common/properties/HttpClientHostProperties.java b/jeecg-boot-base-core/src/main/java/org/jeecg/common/properties/HttpClientHostProperties.java new file mode 100644 index 0000000..da68ea9 --- /dev/null +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/common/properties/HttpClientHostProperties.java @@ -0,0 +1,17 @@ +package org.jeecg.common.properties; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Data +@Component +@ConfigurationProperties(prefix = "http-client-host") +public class HttpClientHostProperties { + + /** + * 服务器ip + */ + private String oceanHost; + +} diff --git a/jeecg-module-large-screen/src/main/java/org/jeecg/ocean/controller/OceanFeignController.java b/jeecg-module-large-screen/src/main/java/org/jeecg/ocean/controller/OceanFeignController.java new file mode 100644 index 0000000..af8380f --- /dev/null +++ b/jeecg-module-large-screen/src/main/java/org/jeecg/ocean/controller/OceanFeignController.java @@ -0,0 +1,63 @@ +package org.jeecg.ocean.controller; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.v3.oas.annotations.Operation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.jeecg.common.api.vo.Result; +import org.jeecg.common.properties.HttpClientHostProperties; +import org.jeecg.ocean.entity.AlarmRecord; +import org.jeecg.sync.feign.SyncFeignClient; +import org.jeecg.utils.HttpClientUtil; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * @Description: 海洋接口 + * @Author: jeecg-boot + * @Date: 2022-12-19 + * @Version: V1.0 + */ +@RestController +@RequestMapping("/oceanFeign") +@Slf4j +@RequiredArgsConstructor +public class OceanFeignController { + + private final HttpClientHostProperties hostProperties; + + @Operation(summary = "大屏-同步记录") + @GetMapping(value = "/getAlarmRecords") + public Result getAlarmRecords() throws IOException { + String getUrl = hostProperties.getOceanHost() + "bizAlarmRecords/list?pageNo=1&pageSize=10000"; + Map getHeaders = Map.of("Authorization", ""); + String getResult = HttpClientUtil.doGet(getUrl, getHeaders, true); // 启用 SSL + try { + // 创建 ObjectMapper 实例 + ObjectMapper objectMapper = new ObjectMapper(); + // 使用 TypeReference 来指定泛型类型 + Result> pageResult = objectMapper.readValue(getResult, new TypeReference<>() {}); + // 检查响应是否成功 + if (pageResult.getCode() == 200) { // 假设 200 表示成功,根据实际 API 文档调整 + IPage alarmRecordList = pageResult.getResult(); + return Result.OK(pageResult); + } else { + return Result.error("API 请求失败, 错误码: " + pageResult.getCode() + ", 消息: " + pageResult.getMessage()); + } + + } catch (Exception e) { + e.printStackTrace(); + return Result.error("JSON 解析失败: " + e.getMessage()); + } + } + +} diff --git a/jeecg-module-large-screen/src/main/java/org/jeecg/ocean/entity/AlarmRecord.java b/jeecg-module-large-screen/src/main/java/org/jeecg/ocean/entity/AlarmRecord.java new file mode 100644 index 0000000..a9f6562 --- /dev/null +++ b/jeecg-module-large-screen/src/main/java/org/jeecg/ocean/entity/AlarmRecord.java @@ -0,0 +1,38 @@ +package org.jeecg.ocean.entity; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +@Data +public class AlarmRecord { + public AlarmRecord() {} + /**id*/ + private String id; + /**任务名称*/ + private String taskName; + /**报警状态*/ + private Integer alarmStatus; + /**经度*/ + private Double longitude; + /**纬度*/ + private Double latitude; + /**采样时间*/ + @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") + private Date samplingTime; + /**报警时间*/ + @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") + private Date alarmTime; + /**数据来源*/ + private Integer sourceType; + /**数据表外接*/ + private String dataId; + /**报警值*/ + private Double alarmValue; + /**阈值*/ + private Double thresholdValue; +} diff --git a/jeecg-module-large-screen/src/main/java/org/jeecg/utils/HttpClientUtil.java b/jeecg-module-large-screen/src/main/java/org/jeecg/utils/HttpClientUtil.java new file mode 100644 index 0000000..1d657c2 --- /dev/null +++ b/jeecg-module-large-screen/src/main/java/org/jeecg/utils/HttpClientUtil.java @@ -0,0 +1,377 @@ +package org.jeecg.utils; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.http.*; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.conn.ssl.TrustStrategy; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.ssl.SSLContextBuilder; +import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.net.ssl.SSLContext; +import java.io.IOException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + + +/** + * 基于 Apache HttpClient 的工具类 + * 提供简单的 GET 和 POST (JSON/Form) 请求功能 + */ +public class HttpClientUtil { + + private static final Logger logger = LoggerFactory.getLogger(HttpClientUtil.class); + + // 默认连接超时时间 (毫秒) + private static final int DEFAULT_CONNECT_TIMEOUT = 5000; + // 默认读取超时时间 (毫秒) + private static final int DEFAULT_SOCKET_TIMEOUT = 10000; + // 默认请求配置 + private static final RequestConfig DEFAULT_REQUEST_CONFIG = RequestConfig.custom() + .setConnectTimeout(DEFAULT_CONNECT_TIMEOUT) + .setSocketTimeout(DEFAULT_SOCKET_TIMEOUT) + .build(); + + private static final ObjectMapper objectMapper = new ObjectMapper(); // 用于 JSON 序列化/反序列化 + + /** + * 创建一个支持 HTTPS (信任所有证书) 的 CloseableHttpClient 实例 + * + * @param connectTimeout 连接超时时间 (毫秒),若小于等于0则使用默认值 + * @param socketTimeout 读取超时时间 (毫秒),若小于等于0则使用默认值 + * @return CloseableHttpClient 实例 + */ + public static CloseableHttpClient createSSLClient(int connectTimeout, int socketTimeout) { + try { + // 信任所有证书的策略 - 仅用于测试环境!生产环境应严格验证证书 + TrustStrategy acceptingTrustStrategy = new TrustStrategy() { + @Override + public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { + return true; // 信任所有 + } + }; + + SSLContext sslContext = SSLContextBuilder.create() + .loadTrustMaterial(acceptingTrustStrategy) + .build(); + + // NoopHostnameVerifier 会跳过主机名验证 - 仅用于测试环境! + SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory( + sslContext, + NoopHostnameVerifier.INSTANCE); // 使用 NoopHostnameVerifier + + RequestConfig config = DEFAULT_REQUEST_CONFIG; + if (connectTimeout > 0 || socketTimeout > 0) { + RequestConfig.Builder configBuilder = RequestConfig.copy(DEFAULT_REQUEST_CONFIG); + if(connectTimeout > 0) { + configBuilder.setConnectTimeout(connectTimeout); + } + if(socketTimeout > 0) { + configBuilder.setSocketTimeout(socketTimeout); + } + config = configBuilder.build(); + } + + return HttpClients.custom() + .setSSLSocketFactory(sslSocketFactory) + .setDefaultRequestConfig(config) + .build(); + + } catch (Exception e) { + logger.error("创建支持SSL的HttpClient实例失败", e); + throw new RuntimeException("Failed to create SSL HttpClient", e); + } + } + + /** + * 创建一个标准的 CloseableHttpClient 实例 + * + * @param connectTimeout 连接超时时间 (毫秒),若小于等于0则使用默认值 + * @param socketTimeout 读取超时时间 (毫秒),若小于等于0则使用默认值 + * @return CloseableHttpClient 实例 + */ + public static CloseableHttpClient createStandardClient(int connectTimeout, int socketTimeout) { + RequestConfig config = DEFAULT_REQUEST_CONFIG; + if (connectTimeout > 0 || socketTimeout > 0) { + RequestConfig.Builder configBuilder = RequestConfig.copy(DEFAULT_REQUEST_CONFIG); + if(connectTimeout > 0) { + configBuilder.setConnectTimeout(connectTimeout); + } + if(socketTimeout > 0) { + configBuilder.setSocketTimeout(socketTimeout); + } + config = configBuilder.build(); + } + return HttpClients.custom().setDefaultRequestConfig(config).build(); + } + + + /** + * 发送 GET 请求 + * + * @param url 请求地址 + * @param headers 请求头 (可为 null) + * @param enableSSL 是否启用 SSL (信任所有证书) + * @return 响应字符串 + * @throws IOException IO 异常 + */ + public static String doGet(String url, Map headers, boolean enableSSL) throws IOException { + return doGet(url, headers, enableSSL, DEFAULT_CONNECT_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); + } + + /** + * 发送 GET 请求 (指定超时) + * + * @param url 请求地址 + * @param headers 请求头 (可为 null) + * @param enableSSL 是否启用 SSL (信任所有证书) + * @param connectTimeout 连接超时时间 (毫秒) + * @param socketTimeout 读取超时时间 (毫秒) + * @return 响应字符串 + * @throws IOException IO 异常 + */ + public static String doGet(String url, Map headers, boolean enableSSL, int connectTimeout, int socketTimeout) throws IOException { + CloseableHttpClient httpClient = enableSSL ? createSSLClient(connectTimeout, socketTimeout) : createStandardClient(connectTimeout, socketTimeout); + HttpGet httpGet = new HttpGet(url); + + // 设置请求头 + if (headers != null && !headers.isEmpty()) { + for (Map.Entry entry : headers.entrySet()) { + httpGet.setHeader(entry.getKey(), entry.getValue()); + } + } + + CloseableHttpResponse response = null; + try { + response = httpClient.execute(httpGet); + HttpEntity entity = response.getEntity(); + if (entity != null) { + return EntityUtils.toString(entity, Consts.UTF_8); + } + } finally { + closeResponse(response); + closeClient(httpClient); + } + return null; // 或抛出异常表示无响应体 + } + + + /** + * 发送 POST 请求 (发送 JSON 数据) + * + * @param url 请求地址 + * @param jsonBody JSON 请求体 + * @param headers 请求头 (可为 null) - Content-Type 会被自动设置为 application/json + * @param enableSSL 是否启用 SSL (信任所有证书) + * @return 响应字符串 + * @throws IOException IO 异常 + */ + public static String doPostJson(String url, String jsonBody, Map headers, boolean enableSSL) throws IOException { + return doPostJson(url, jsonBody, headers, enableSSL, DEFAULT_CONNECT_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); + } + + /** + * 发送 POST 请求 (发送 JSON 数据) (指定超时) + * + * @param url 请求地址 + * @param jsonBody JSON 请求体 + * @param headers 请求头 (可为 null) - Content-Type 会被自动设置为 application/json + * @param enableSSL 是否启用 SSL (信任所有证书) + * @param connectTimeout 连接超时时间 (毫秒) + * @param socketTimeout 读取超时时间 (毫秒) + * @return 响应字符串 + * @throws IOException IO 异常 + */ + public static String doPostJson(String url, String jsonBody, Map headers, boolean enableSSL, int connectTimeout, int socketTimeout) throws IOException { + CloseableHttpClient httpClient = enableSSL ? createSSLClient(connectTimeout, socketTimeout) : createStandardClient(connectTimeout, socketTimeout); + HttpPost httpPost = new HttpPost(url); + + // 设置请求头 + if (headers != null) { + for (Map.Entry entry : headers.entrySet()) { + httpPost.setHeader(entry.getKey(), entry.getValue()); + } + } + // 设置 Content-Type 为 JSON + httpPost.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.getMimeType()); + + // 设置请求体 + if (jsonBody != null) { + StringEntity entity = new StringEntity(jsonBody, ContentType.APPLICATION_JSON); + httpPost.setEntity(entity); + } + + CloseableHttpResponse response = null; + try { + response = httpClient.execute(httpPost); + HttpEntity entity = response.getEntity(); + if (entity != null) { + return EntityUtils.toString(entity, Consts.UTF_8); + } + } finally { + closeResponse(response); + closeClient(httpClient); + } + return null; // 或抛出异常表示无响应体 + } + + + /** + * 发送 POST 请求 (发送表单数据 application/x-www-form-urlencoded) + * + * @param url 请求地址 + * @param params 表单参数 + * @param headers 请求头 (可为 null) - Content-Type 会被自动设置为 application/x-www-form-urlencoded + * @param enableSSL 是否启用 SSL (信任所有证书) + * @return 响应字符串 + * @throws IOException IO 异常 + */ + public static String doPostForm(String url, Map params, Map headers, boolean enableSSL) throws IOException { + return doPostForm(url, params, headers, enableSSL, DEFAULT_CONNECT_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); + } + + /** + * 发送 POST 请求 (发送表单数据 application/x-www-form-urlencoded) (指定超时) + * + * @param url 请求地址 + * @param params 表单参数 + * @param headers 请求头 (可为 null) - Content-Type 会被自动设置为 application/x-www-form-urlencoded + * @param enableSSL 是否启用 SSL (信任所有证书) + * @param connectTimeout 连接超时时间 (毫秒) + * @param socketTimeout 读取超时时间 (毫秒) + * @return 响应字符串 + * @throws IOException IO 异常 + */ + public static String doPostForm(String url, Map params, Map headers, boolean enableSSL, int connectTimeout, int socketTimeout) throws IOException { + CloseableHttpClient httpClient = enableSSL ? createSSLClient(connectTimeout, socketTimeout) : createStandardClient(connectTimeout, socketTimeout); + HttpPost httpPost = new HttpPost(url); + + // 设置请求头 + if (headers != null) { + for (Map.Entry entry : headers.entrySet()) { + httpPost.setHeader(entry.getKey(), entry.getValue()); + } + } + // 设置 Content-Type 为 Form + httpPost.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED.getMimeType()); + + // 设置表单参数 + if (params != null && !params.isEmpty()) { + List formParams = new ArrayList<>(); + for (Map.Entry entry : params.entrySet()) { + formParams.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); + } + UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formParams, Consts.UTF_8); + httpPost.setEntity(entity); + } + + CloseableHttpResponse response = null; + try { + response = httpClient.execute(httpPost); + HttpEntity entity = response.getEntity(); + if (entity != null) { + return EntityUtils.toString(entity, Consts.UTF_8); + } + } finally { + closeResponse(response); + closeClient(httpClient); + } + return null; // 或抛出异常表示无响应体 + } + + /** + * 关闭 HttpResponse + * @param response CloseableHttpResponse + */ + private static void closeResponse(CloseableHttpResponse response) { + if (response != null) { + try { + response.close(); + } catch (IOException e) { + logger.warn("关闭 HttpResponse 时发生异常", e); + } + } + } + + /** + * 关闭 HttpClient + * @param client CloseableHttpClient + */ + private static void closeClient(CloseableHttpClient client) { + if (client != null) { + try { + client.close(); + } catch (IOException e) { + logger.warn("关闭 HttpClient 时发生异常", e); + } + } + } + + // --- 示例用法 --- + /* + public static void main(String[] args) { + try { + // GET 请求示例 + String getUrl = "https://api.example.com/data"; + Map getHeaders = Map.of("Authorization", "Bearer your_token_here"); + String getResult = HttpClientUtil.doGet(getUrl, getHeaders, true); // 启用 SSL + System.out.println("GET Response:\n" + getResult); + + // POST JSON 请求示例 + String postJsonUrl = "https://api.example.com/create"; + Map postJsonHeaders = Map.of("Authorization", "Bearer your_token_here"); + YourDataObject dataToSend = new YourDataObject("value1", "value2"); // 假设你有一个数据对象 + String jsonPayload = objectMapper.writeValueAsString(dataToSend); + String postJsonResult = HttpClientUtil.doPostJson(postJsonUrl, jsonPayload, postJsonHeaders, true); + System.out.println("POST JSON Response:\n" + postJsonResult); + + // POST Form 请求示例 + String postFormUrl = "https://api.example.com/login"; + Map formParams = Map.of("username", "user123", "password", "pass456"); + Map postFormHeaders = Map.of("User-Agent", "MyApp/1.0"); + String postFormResult = HttpClientUtil.doPostForm(postFormUrl, formParams, postFormHeaders, true); + System.out.println("POST Form Response:\n" + postFormResult); + + } catch (Exception e) { + e.printStackTrace(); + } + } + */ + + // --- 你的数据对象示例 (用于 JSON 序列化) --- + /* + public static class YourDataObject { + private String field1; + private String field2; + + public YourDataObject() {} + + public YourDataObject(String field1, String field2) { + this.field1 = field1; + this.field2 = field2; + } + + // Getters and Setters + public String getField1() { return field1; } + public void setField1(String field1) { this.field1 = field1; } + public String getField2() { return field2; } + public void setField2(String field2) { this.field2 = field2; } + } + */ +} \ No newline at end of file