当前位置: 首页 > news >正文

OkHttp3.X 工具类封装:链式调用,支持HTTPS、重试、文件上传【内含常用设计模式设计示例】

OkHttp3.X 工具类封装:链式调用,支持HTTPS、重试、文件上传

基于OkHttp3.X封装,提供链式调用API,简化GET/POST请求,支持HTTPS、自动重试、文件上传等功能,提升开发效率。


在 Android 和 Java 开发中,OkHttp 是最常用的网络请求库之一。为了简化日常开发中的重复配置,提升开发效率,本文将分享一个线程安全、支持默认与自定义配置、链式调用的 OkHttp 工具类,并详细解析其核心功能与实现细节。

一、工具类核心优势

  1. 双重配置模式
    • 默认配置:预定义通用参数(超时时间、连接池、重试策略),适用于大多数场景。
    • 自定义配置:基于默认配置扩展,支持添加拦截器、修改超时参数、配置 HTTPS 证书等。
  2. 线程安全
    • 使用双重检查锁定实现单例,确保多线程环境下实例唯一。
  3. 链式请求构建
    • 支持 GET/POST 请求,灵活拼接 URL 参数、请求头、请求体(FormData、JSON、二进制等)。
  4. HTTPS 安全适配
    • 支持调试模式(跳过证书验证)、自定义证书(自签名证书)、系统默认证书三种模式。
  5. 统一异常处理
    • 自动关闭响应体,封装非 2xx 状态码为 HttpException,简化错误处理逻辑。

二、快速开始

1. 引入依赖

<dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</artifactId><version>4.12.0</version>
</dependency>

2. 工具类核心功能

2.1 GET请求
// 带URL参数和Headers
String result = OkHttp_Util.get("https://api.example.com").addUrlParam("page", "1").addHeader("Authorization", "Bearer token123").execute_Pro();// 批量添加参数
Map<String, String> params = new HashMap<>();
params.put("key1", "value1");
params.put("key2", "value2");
String result = OkHttp_Util.get("https://api.example.com").addUrlParam(params).execute_Pro();
2.2 POST请求
// 提交JSON
String json = "{\"name\":\"Dolphin\",\"age\":25}";
String result = OkHttp_Util.post("https://api.example.com").jsonBody(json).execute_Pro();// FormData表单
Map<String, String> formData = new HashMap<>();
formData.put("username", "admin");
formData.put("password", "123456");
String result = OkHttp_Util.post("https://api.example.com").formData(formData).execute_Pro();// 文件上传
File file = new File("avatar.jpg");
MediaType mediaType = MediaType.parse("image/jpeg");
String result = OkHttp_Util.post("https://api.upload.com").formData("file", file, mediaType).execute_Pro();
2.3 自定义配置
// 创建自定义Client(添加拦截器+长超时)
OkHttpClient.Builder builder = OkHttp_Util.customBuilder().addInterceptor(new OkHttp_Util.LoggingInterceptor()).connectTimeout(30, TimeUnit.SECONDS);OkHttp_Util.buildCustomInstance(builder);
OkHttpClient customClient = OkHttp_Util.getCustomInstance();// 使用自定义Client发起请求
String result = OkHttp_Util.get("https://api.example.com", customClient).addUrlParam("debug", "true").execute_Pro();
2.4 异步请求
OkHttp_Util.get("https://api.example.com").enqueue(new Callback() {@Overridepublic void onResponse(Call call, Response response) throws IOException {String body = OkHttp_Util.parseResponse(response);// 处理响应}@Overridepublic void onFailure(Call call, IOException e) {// 处理失败}});

三、核心设计解析

3.1 单例模式管理

// 默认配置单例
private static volatile OkHttpClient defaultInstance;// 自定义配置单例
private static volatile OkHttpClient customInstance;public static OkHttpClient getDefaultInstance() {if (defaultInstance == null) {synchronized (OkHttp_Util.class) {if (defaultInstance == null) {defaultInstance = defaultBuilder().build();}}}return defaultInstance;
}

3.2 HTTPS安全配置

支持三种模式:

  • 调试模式:跳过证书验证(仅测试环境)
  • 自定义证书:指定PEM证书
  • 系统默认:使用系统CA证书
private static OkHttpClient.Builder configSSL(OkHttpClient.Builder builder, OkHttpConfig config) {// 调试模式:信任所有证书if (config.debugMode) {builder.sslSocketFactory(createInsecureSocketFactory(), new TrustAllManager());}// 自定义证书else if (config.trustedCertificates != null) {X509TrustManager trustManager = createCustomTrustManager(config.trustedCertificates);builder.sslSocketFactory(trustManager.getSocketFactory(), trustManager);}// 系统默认证书else {X509TrustManager trustManager = getSystemTrustManager();builder.sslSocketFactory(trustManager.getSocketFactory(), trustManager);}return builder;
}

3.3 重试拦截器

private static class RetryInterceptor implements Interceptor {private final int maxRetries;@Overridepublic Response intercept(Chain chain) throws IOException {Request request = chain.request();IOException exception = null;for (int i = 0; i <= maxRetries; i++) {try {Response response = chain.proceed(request);if (response.isSuccessful()) return response;} catch (IOException e) {exception = e;}}throw exception != null ? exception : new IOException("请求失败");}
}

四、注意事项

  1. HTTPS安全:生产环境务必使用系统证书或自定义证书
  2. 资源释放:同步请求自动关闭响应体,异步需手动关闭
  3. 超时配置:根据业务需求调整默认超时时间
  4. 线程安全:OkHttpClient实例线程安全,建议复用
  5. 异常处理:使用execute_Pro()自动处理非200响应

五、完整代码

package com.dolphin.util;import okhttp3.*;import javax.net.ssl.*;
import java.io.File;
import java.io.IOException;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;/*** OkHttp 工具类(线程安全)* <p>* 提供两种 OkHttpClient 实例管理模式:* <ul>*     <li>【默认配置】预定义通用网络参数,适用于大多数场景:*         <ul>*             <li>连接/读取/写入超时:10 秒</li>*             <li>允许重定向和失败重试(最大 3 次)</li>*             <li>连接池:5 个空闲连接,保持 10 分钟</li>*             <li>系统默认证书信任策略(非调试模式)</li>*         </ul>*     </li>*     <li>【自定义配置】基于默认配置扩展,支持灵活定制:*         <ul>*             <li>添加拦截器(日志、签名、认证等)</li>*             <li>修改超时参数、连接池配置</li>*             <li>配置 HTTPS 证书信任策略(调试模式/自定义证书/系统默认)</li>*         </ul>*     </li>* </ul>* <p>* 使用示例:* <pre>* // 1. 使用默认配置发起 GET 请求* String resultDefault = OkHttp_Util.get("https://api.example.com")*     .addUrlParam("page", "1")*     .addHeader("User-Agent", "OkHttp-Util/1.0")*     .execute_Pro(); // 自动处理响应和异常** // 2. 自定义配置(添加日志拦截器+长连接超时)* OkHttpClient.Builder customBuilder = OkHttp_Util.customBuilder()*     .addInterceptor(new OkHttp_Util.LoggingInterceptor()) // 添加自定义拦截器*     .connectTimeout(60, TimeUnit.SECONDS); // 延长连接超时时间* OkHttp_Util.buildCustomInstance(customBuilder); // 初始化自定义单例* OkHttpClient customClient = OkHttp_Util.getCustomInstance(); // 获取到 一个 单例,并且是自定义配置的 OkHttpClient 实例* String resultCustom = OkHttp_Util.get("https://api.example.com", customClient)*     .addUrlParam("page", "1")*     .addHeader("User-Agent", "OkHttp-Util/1.0")*     .execute_Pro(); // 自动处理响应和异常** // 3. 上传文件(multipart/form-data)* File file = new File("example.pdf");* String uploadResult = OkHttp_Util.post("https://api.upload.com")*     .addHeader("Authorization", "Bearer YOUR_TOKEN")*     .formData("file", file, MediaType.parse("application/pdf")) // 上传文件*     .execute_Pro();** // 4. 处理异步请求* OkHttp_Util.get("https://api.async.com")*     .enqueue(new Callback() {*         @Override*         public void onResponse(Call call, Response response) throws IOException {*             String body = OkHttp_Util.parseResponse(response);*             // 处理成功响应*         }*         @Override*         public void onFailure(Call call, IOException e) {*             // 处理失败(网络异常)*         }*     });* </pre>** @author DolphinHome* @date 2025/04/30*/
public class OkHttp_Util {/*
// 使用 Log4j 记录日志
private static final Logger log = LoggerFactory.getLogger(OkHttp_Util.class);*/// ------------------------------ 单例实例 ------------------------------/*** 默认配置的 OkHttpClient 单例(线程安全,双重检查锁定实现)*/private static volatile OkHttpClient defaultInstance;/*** 自定义配置的 OkHttpClient 单例(线程安全,按需初始化)*/private static volatile OkHttpClient customInstance;// ------------------------------ 构造方法 ------------------------------/*** 私有构造方法,禁止类实例化* <p>* 通过断言错误防止反射创建实例,强化工具类设计* </p>** @throws AssertionError 始终抛出,明确禁止实例化*/private OkHttp_Util() {throw new AssertionError("不可实例化工具类");}// ------------------------------ 配置类 ------------------------------/*** OkHttp 配置参数容器* <p>* 包含网络请求核心配置,所有参数均有默认值:* <ul>*     <li>超时:连接/读取/写入默认 10 秒</li>*     <li>重定向:默认允许</li>*     <li>重试:默认允许,最大 3 次</li>*     <li>连接池:5 个空闲连接,保持 10 分钟</li>*     <li>HTTPS:默认使用系统证书,调试模式可跳过验证</li>* </ul>** <p>*  自定义证书信任(生产环境):* <pre>* // 1. 加载 PEM 证书文件* X509Certificate cert = loadCertificateFromFile("trusted.crt");* OkHttpConfig config = new OkHttpConfig();* config.setTrustedCertificates(new X509Certificate[]{cert}); // 设置自定义证书** // 2. 通过自定义构建器应用配置(需修改 defaultBuilder 逻辑,此处仅示例)* OkHttpClient.Builder builder = OkHttp_Util.customBuilder();* configSSL(builder, config); // 内部方法,实际通过 OkHttpConfig 传递* </pre>* <p>*  调试模式(测试环境):* <pre>* OkHttpConfig debugConfig = new OkHttpConfig();* debugConfig.setDebugMode(true); // 跳过所有证书验证(危险!仅测试用)* </pre>*/public static class OkHttpConfig {// 超时配置(单位:秒)private int connectTimeout; // 连接超时:建立 TCP 连接的最大等待时间private int readTimeout;    // 读取超时:等待服务器响应数据的最大时间private int writeTimeout;   // 写入超时:发送请求体到服务器的最大时间// 重定向策略private boolean followRedirects; // 是否允许自动跟随重定向(默认允许)// 重试策略private boolean retryOnConnectionFailure; // 连接失败时是否重试(默认允许)private int maxRetryCount;                // 最大重试次数(默认 3 次)// 连接池配置private int maxIdleConnections = 5;  // 最大空闲连接数(默认 5 个)private long keepAliveDuration = 10; // 连接存活时间(默认 10 分钟)private TimeUnit keepAliveUnit = TimeUnit.MINUTES; // 存活时间单位// HTTPS 安全配置private boolean debugMode;         // 调试模式(跳过证书验证,默认关闭)private X509Certificate[] trustedCertificates; // 自定义信任证书(PEM 格式,默认 null)/*** 无参构造:使用全默认配置*/public OkHttpConfig() {this(10,10,10,true,true,3,5,10,TimeUnit.MINUTES,false,null);}public OkHttpConfig(int connectTimeout,int readTimeout,int writeTimeout,boolean followRedirects,boolean retryOnConnectionFailure,int maxRetryCount,int maxIdleConnections,int keepAliveDuration,TimeUnit keepAliveUnit,boolean debugMode,X509Certificate[] trustedCertificates) {this.connectTimeout = connectTimeout;this.readTimeout = readTimeout;this.writeTimeout = writeTimeout;this.followRedirects = followRedirects;this.retryOnConnectionFailure = retryOnConnectionFailure;this.maxRetryCount = maxRetryCount;this.maxIdleConnections = maxIdleConnections;this.keepAliveDuration = keepAliveDuration;this.keepAliveUnit = keepAliveUnit;this.debugMode = debugMode;this.trustedCertificates = trustedCertificates;}// region get/set 方法public int getConnectTimeout() {return connectTimeout;}public void setConnectTimeout(int connectTimeout) {this.connectTimeout = connectTimeout;}public int getReadTimeout() {return readTimeout;}public void setReadTimeout(int readTimeout) {this.readTimeout = readTimeout;}public int getWriteTimeout() {return writeTimeout;}public void setWriteTimeout(int writeTimeout) {this.writeTimeout = writeTimeout;}public boolean isFollowRedirects() {return followRedirects;}public void setFollowRedirects(boolean followRedirects) {this.followRedirects = followRedirects;}public boolean isRetryOnConnectionFailure() {return retryOnConnectionFailure;}public void setRetryOnConnectionFailure(boolean retryOnConnectionFailure) {this.retryOnConnectionFailure = retryOnConnectionFailure;}public int getMaxRetryCount() {return maxRetryCount;}public void setMaxRetryCount(int maxRetryCount) {this.maxRetryCount = maxRetryCount;}public int getMaxIdleConnections() {return maxIdleConnections;}public void setMaxIdleConnections(int maxIdleConnections) {this.maxIdleConnections = maxIdleConnections;}public long getKeepAliveDuration() {return keepAliveDuration;}public void setKeepAliveDuration(long keepAliveDuration) {this.keepAliveDuration = keepAliveDuration;}public TimeUnit getKeepAliveUnit() {return keepAliveUnit;}public void setKeepAliveUnit(TimeUnit keepAliveUnit) {this.keepAliveUnit = keepAliveUnit;}public boolean isDebugMode() {return debugMode;}public void setDebugMode(boolean debugMode) {this.debugMode = debugMode;}public X509Certificate[] getTrustedCertificates() {return trustedCertificates;}public void setTrustedCertificates(X509Certificate[] trustedCertificates) {this.trustedCertificates = trustedCertificates;}// endregion}// ------------------------------ 自定义配置单例 ------------------------------/*** 获取自定义配置的 OkHttpClient 单例* <p>* 必须先通过 {@link #buildCustomInstance(OkHttpClient.Builder)} 初始化* </p>* <p>* 使用示例:* </p>* <pre>* OkHttpClient.Builder customBuilder = OkHttp_Util.customBuilder()*     .addInterceptor(new OkHttp_Util.LoggingInterceptor()) // 添加自定义拦截器*     .connectTimeout(60, TimeUnit.SECONDS); // 延长连接超时时间* OkHttp_Util.buildCustomInstance(customBuilder); // 初始化自定义单例* OkHttpClient customClient = OkHttp_Util.getCustomInstance(); // 获取到 一个 单例,并且是自定义配置的 OkHttpClient 实例* String resultCustom = OkHttp_Util.get("https://api.example.com", customClient)*     .addUrlParam("page", "1")*     .addHeader("User-Agent", "OkHttp-Util/1.0")*     .execute_Pro(); // 自动处理响应和异常* </pre>** @return 自定义配置的 OkHttpClient 实例(线程安全单例)* @throws IllegalStateException 未初始化自定义配置时抛出*/public static OkHttpClient getCustomInstance() {if (customInstance == null) {throw new IllegalStateException("自定义 OkHttpClient 未初始化,请先调用 buildCustomInstance()");}return customInstance;}/*** 初始化自定义配置单例* <p>* 基于默认配置构建器扩展,支持添加拦截器、修改超时等* <p>* <b>线程安全</b>:采用双重检查锁定,确保单例唯一性* </p>* <p>* 使用示例:* </p>* <pre>* OkHttpClient.Builder customBuilder = OkHttp_Util.customBuilder()*     .addInterceptor(new OkHttp_Util.LoggingInterceptor()) // 添加自定义拦截器*     .connectTimeout(60, TimeUnit.SECONDS); // 延长连接超时时间* OkHttp_Util.buildCustomInstance(customBuilder); // 初始化自定义单例* OkHttpClient customClient = OkHttp_Util.getCustomInstance(); // 获取到 一个 单例,并且是自定义配置的 OkHttpClient 实例* String resultCustom = OkHttp_Util.get("https://api.example.com", customClient)*     .addUrlParam("page", "1")*     .addHeader("User-Agent", "OkHttp-Util/1.0")*     .execute_Pro(); // 自动处理响应和异常* </pre>** @param builder OkHttpClient 构建器(不可为 null)* @throws NullPointerException builder 为 null 时抛出*/public static void buildCustomInstance(OkHttpClient.Builder builder) {if (builder == null) throw new NullPointerException("builder 不能为 null");if (customInstance == null) {synchronized (OkHttp_Util.class) {if (customInstance == null) {customInstance = builder.build();}}}}/*** 获取可扩展的 OkHttpClient 构建器(基于默认配置)* <p>* 每次调用返回新的构建器实例,不影响现有单例:* - 包含默认的超时时间、连接池和重试策略* - 支持添加自定义拦截器(如签名、认证、日志等)* - 可修改 HTTPS 证书信任策略* </p>* <p>* 使用示例:* </p>* <pre>* // 自定义配置 OkHttpClient 单例* OkHttpClient.Builder customBuilder = OkHttp_Util.customBuilder()*     .addInterceptor(new OkHttp_Util.LoggingInterceptor()) // 添加自定义拦截器*     .connectTimeout(60, TimeUnit.SECONDS); // 延长连接超时时间* OkHttp_Util.buildCustomInstance(customBuilder); // 初始化自定义单例* OkHttpClient customClient = OkHttp_Util.getCustomInstance(); // 获取到 一个 单例,并且是自定义配置的 OkHttpClient 实例【注意:此客户端是单例的,调用后会将其设置为单例实例】* String resultCustom = OkHttp_Util.get("https://api.example.com", customClient)*     .addUrlParam("page", "1")*     .addHeader("User-Agent", "OkHttp-Util/1.0")*     .execute_Pro(); // 自动处理响应和异常*** // 另一个 OkHttpClient 实例(非单例)* OkHttpClient customClient = OkHttp_Util.customBuilder()*      .addInterceptor(new XXXXXInterceptor())*      .connectTimeout(60, TimeUnit.SECONDS)*      .build(); // 获取到了一个自定义配置的 OkHttpClient 实例【注意:此客户端不是单例的,每次调用都会创建一个新的客户端】* String resultCustom = OkHttp_Util.get("https://api.example.com", customClient)*     .addUrlParam("page", "1")*     .addHeader("User-Agent", "OkHttp-Util/1.0")*     .execute_Pro(); // 自动处理响应和异常* </pre>** @return 预配置默认参数的 OkHttpClient.Builder 实例*/public static OkHttpClient.Builder customBuilder() {// 通过newBuilder()方法克隆默认配置,保证原实例不受影响return getDefaultInstance().newBuilder();}// ------------------------------ 默认配置单例 ------------------------------/*** 获取默认配置的 OkHttpClient 单例* <p>* 首次调用时初始化,采用双重检查锁定保证线程安全* <p>* 默认配置详情:* <ul>*     <li>超时:10 秒(连接/读取/写入)</li>*     <li>连接池:5 个空闲连接,保持 10 分钟</li>*     <li>重试策略:3 次失败重试(通过 {@link RetryInterceptor} 实现)</li>*     <li>HTTPS:使用系统默认证书信任策略(非调试模式)</li>* </ul>* </p>* <p>* 使用示例:* </p>* <pre>* OkHttpClient client = OkHttp_Util.getDefaultInstance(); // 获取到 一个 单例,并且默认配置过的 OkHttpClient 实例* Request request = new Request.Builder()*     .url("https://api.default.com")*     .get()*     .build();* try (Response response = client.newCall(request).execute()) {*     String body = OkHttp_Util.parseResponse(response);* }* </pre>** @return 预配置的 OkHttpClient 单例(线程安全)*/public static OkHttpClient getDefaultInstance() {// 第一次检查:避免每次访问都进行同步if (defaultInstance == null) {synchronized (OkHttp_Util.class) {// 第二次检查:防止重复创建if (defaultInstance == null) {defaultInstance = defaultBuilder().build(); // 使用默认的自定义配置}}}return defaultInstance;}/*** 创建默认配置的 OkHttpClient.Builder* <p>* 包含以下核心配置:* <ol>*     <li>基础超时参数(10 秒)</li>*     <li>连接池配置(5 个空闲连接,10 分钟存活)</li>*     <li>重试拦截器(最大 3 次重试)</li>*     <li>HTTPS 证书信任策略(根据 {@link OkHttpConfig} 动态配置)</li>* </ol>* </p>** @return 预配置默认参数的构建器实例*/private static OkHttpClient.Builder defaultBuilder() {// 自定义配置OkHttpConfig config = new OkHttpConfig();OkHttpClient.Builder builder = new OkHttpClient.Builder()// 设置连接超时(建立TCP连接的最大等待时间).connectTimeout(config.connectTimeout, TimeUnit.SECONDS)// 设置读取超时(等待服务器返回数据的最大时间).readTimeout(config.readTimeout, TimeUnit.SECONDS)// 设置写入超时(发送请求体到服务器的最大时间).writeTimeout(config.writeTimeout, TimeUnit.SECONDS)// 设置是否允许重定向.followRedirects(config.followRedirects)// 设置是否允许失败重试.retryOnConnectionFailure(config.retryOnConnectionFailure)// 配置连接池(复用HTTP/HTTP2连接,减少延迟).connectionPool(new ConnectionPool(config.maxIdleConnections, // 最大空闲连接数config.keepAliveDuration, // 保持连接时间config.keepAliveUnit)) // 保持连接时间单位// TODO: 通过 Interceptor 实现 最大重试次数.addInterceptor(new RetryInterceptor(config.maxRetryCount));// 设置信任证书(PEM格式)【测试环境中 debug=true 时,不设置信任证书】configSSL(builder, config);return builder;}// ------------------------------ HTTPS 安全配置 ------------------------------/*** 配置 HTTPS 证书信任策略* <p>* 支持三种模式:* <ul>*     <li><b>调试模式</b>({@code debugMode=true}):*         <ul>*             <li>跳过所有证书验证(存在严重安全风险,仅限测试环境!)</li>*             <li>警告:可能导致中间人攻击,绝不能用于生产环境</li>*         </ul>*     </li>*     <li><b>自定义证书</b>({@code trustedCertificates 非空}):*         <ul>*             <li>仅信任指定的 PEM 格式证书</li>*             <li>适用于双向认证或自签名证书场景</li>*         </ul>*     </li>*     <li><b>系统默认</b>(默认模式):*         <ul>*             <li>使用设备/系统预装的 CA 证书</li>*             <li>适用于生产环境的标准 HTTPS 通信</li>*         </ul>*     </li>* </ul>* </p>** @param builder OkHttpClient 构建器实例* @param config  配置参数(包含 HTTPS 相关配置)* @return 应用证书策略后的构建器实例* @throws RuntimeException 证书配置失败时抛出(包装底层异常)*/private static OkHttpClient.Builder configSSL(OkHttpClient.Builder builder, OkHttpConfig config) {try {SSLContext sslContext;X509TrustManager trustManager;if (config.debugMode) {// 调试模式:禁用证书验证(风险提示:仅用于测试环境!)sslContext = SSLContext.getInstance("TLSv1.3");trustManager = new TrustAllManager();sslContext.init(null, new TrustManager[]{trustManager}, new SecureRandom());builder.sslSocketFactory(sslContext.getSocketFactory(), trustManager);} else if (config.trustedCertificates != null && config.trustedCertificates.length > 0) {// 自定义证书模式:使用指定的 PEM 证书trustManager = createCustomTrustManager(config.trustedCertificates);sslContext = SSLContext.getInstance("TLSv1.3");sslContext.init(null, new TrustManager[]{trustManager}, null);builder.sslSocketFactory(sslContext.getSocketFactory(), trustManager);} else {// 生产环境默认:使用系统信任的证书trustManager = getSystemTrustManager();sslContext = SSLContext.getInstance("TLSv1.3");sslContext.init(null, new TrustManager[]{trustManager}, null);builder.sslSocketFactory(sslContext.getSocketFactory(), trustManager);}// 允许所有主机名验证(需根据实际需求调整,此处为演示简化)builder.hostnameVerifier((hostname, session) -> true);} catch (Exception e) {throw new RuntimeException("HTTPS 证书配置失败", e);}return builder;}// region 安全组件/*** 调试模式专用:信任所有证书的管理器* <p>* 重写证书验证方法,跳过所有客户端和服务器证书检查* 警告:此实现存在严重安全漏洞,仅限测试环境使用!* </p>*/@Deprecatedprivate static class TrustAllManager implements X509TrustManager {@Overridepublic void checkClientTrusted(X509Certificate[] chain, String authType) {// 客户端证书验证(此处无需处理)}@Overridepublic void checkServerTrusted(X509Certificate[] chain, String authType) {// 跳过服务器证书验证(调试模式专用)}@Overridepublic X509Certificate[] getAcceptedIssuers() {return new X509Certificate[0]; // 返回空列表表示接受所有颁发者}}/*** 调试模式专用:创建忽略证书验证的 SSLSocketFactory* <p>* 警告:此模式会绕过所有证书验证,存在中间人攻击风险,仅限测试环境使用!* </p>** @return 不安全的 SSLSocketFactory 实例* @throws Exception SSL 上下文初始化失败时抛出*/private static SSLSocketFactory createInsecureSocketFactory() throws Exception {SSLContext context = SSLContext.getInstance("TLSv1.3");context.init(null, new TrustManager[]{new TrustAllManager()}, new SecureRandom());return context.getSocketFactory();}/*** 获取系统默认的证书信任管理器* <p>* 使用设备或系统预装的证书颁发机构 (CA) 列表* </p>** @return 系统默认的 X509TrustManager 实例* @throws Exception 信任管理器初始化失败时抛出*/private static X509TrustManager getSystemTrustManager() throws Exception {TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());factory.init((KeyStore) null);return (X509TrustManager) factory.getTrustManagers()[0];}/*** 创建自定义证书信任管理器(PEM 格式)* <p>* 将指定的证书添加到信任列表,用于验证服务器证书* </p>** @param certificates PEM 格式的 X509 证书数组* @return 自定义的 X509TrustManager 实例* @throws Exception 密钥库或信任管理器初始化失败时抛出*/private static X509TrustManager createCustomTrustManager(X509Certificate[] certificates)throws Exception {KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());keyStore.load(null, null);for (int i = 0; i < certificates.length; i++) {keyStore.setCertificateEntry("cert-" + i, certificates[i]);}TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());factory.init(keyStore);return (X509TrustManager) factory.getTrustManagers()[0];}// endregion// region 拦截器private static class LoggingInterceptor implements Interceptor {@Overridepublic Response intercept(Chain chain) throws IOException {Request request = chain.request();long startNs = System.nanoTime();// 记录请求详情// log.debug("Request => {} {}\nHeaders: {}", request.method(), request.url(), request.headers());Response response = chain.proceed(request);long costMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs);// 记录响应指标// log.info("Response <= {} {} ({}ms)\nCode: {}", request.method(), request.url(), costMs, response.code());return response;}}/*** 失败重试拦截器(基于默认配置的最大重试次数)* <p>* 实现逻辑:* <ul>*     <li>对每个请求尝试 {@code maxRetries + 1} 次(包括首次)</li>*     <li>仅处理 {@link IOException}(网络层异常)</li>*     <li>成功响应({@code response.isSuccessful()})立即返回</li>* </ul>* </p>*/private static class RetryInterceptor implements Interceptor {private final int maxRetries;  // 最大重试次数(不包含首次请求)/*** @param maxRetries 最大重试次数(建议 0-5,默认 3)*/public RetryInterceptor(int maxRetries) {this.maxRetries = maxRetries;}@Overridepublic Response intercept(Chain chain) throws IOException {Request request = chain.request();IOException exception = null;for (int i = 0; i <= maxRetries; i++) {  // 包括首次请求,总尝试次数 maxRetries + 1try {Response response = chain.proceed(request);if (response.isSuccessful()) return response;// 非成功响应不重试(如 4xx/5xx 错误,由上层处理)return response;} catch (IOException e) {exception = e;// log.warn("请求失败(尝试 {}/{}): {}", i + 1, maxRetries + 1, e.getMessage());System.out.println(String.format("请求失败(尝试 %d/%d): %s", i + 1, maxRetries + 1, e.getMessage()));}}throw exception != null ? exception : new IOException("网络请求无响应");}}// endregion// region 统一响应处理/*** 解析响应并处理异常* <p>* 自动关闭响应体,封装非成功状态码为 {@link HttpException}* </p>** @param response OkHttp 响应实例(不可为 null)* @return 响应正文(UTF-8 字符串)* @throws IOException   网络异常或响应体为空* @throws HttpException 非 2xx 状态码(包含状态码和消息)*/public static String parseResponse(Response response) throws IOException {try {if (!response.isSuccessful()) {throw new HttpException(response.code(),"HTTP错误: " + response.code() + " - " + response.message());}ResponseBody body = response.body();if (body == null) throw new HttpException(500, "响应体为空");return body.string();} finally {response.close();}}/*** 自定义 HTTP 异常(包含状态码)*/public static class HttpException extends IOException {private final int statusCode;  // HTTP 状态码(如 404, 500)public HttpException(int statusCode, String message) {super(message);this.statusCode = statusCode;}public int getStatusCode() {return statusCode;}}// endregion// region 链式调用/*** 链式请求构建器(支持 GET/POST 请求)* <p>* POST 提交 JSON 数据示例:* <pre>* String jsonBody = "{\"name\":\"Dolphin\",\"age\":18}";* String result = OkHttp_Util.post("https://api.post.com")*     .addHeader("Content-Type", "application/json")*     .jsonBody(jsonBody) // 设置 JSON 请求体*     .execute_Pro(); // 自动处理 200 以外状态码* </pre>* <p>* GET 请求带查询参数示例:* <pre>* Map<String, String> params = new HashMap<>();* params.put("key1", "value1");* params.put("key2", "value2");* String result = OkHttp_Util.get("https://api.get.com")*     .addUrlParam(params) // 批量添加查询参数*     .execute_Pro();* </pre>*/public static class RequestChainBuilder {// region MediaType 常量// 定义 JSON 数据的媒体类型,字符集为 UTF-8private static final MediaType JSON_TYPE = MediaType.get("application/json; charset=utf-8");// 定义表单数据的媒体类型,字符集为 UTF-8private static final MediaType FORM_URLENCODED_TYPE = MediaType.get("application/x-www-form-urlencoded; charset=utf-8");// 定义纯文本数据的媒体类型,字符集为 UTF-8private static final MediaType TEXT_PLAIN_TYPE = MediaType.get("text/plain; charset=utf-8");// 定义 XML 数据的媒体类型,字符集为 UTF-8private static final MediaType XML_TYPE = MediaType.get("application/xml; charset=utf-8");// endregionprivate final OkHttpClient client;       // 使用的 OkHttpClient 实例(默认或自定义)private final HttpUrl.Builder urlBuilder; // URL 构建器(包含基础 URL 和查询参数)private final Request.Builder requestBuilder; // 请求构建器(包含头信息和方法)private RequestBody requestBody;         // 请求体(仅 POST/PUT 等方法需要)/*** 私有构造方法(内部使用,外部通过工厂方法创建)** @param url    基础 URL(不可为 null,需包含协议如 http://)* @param client OkHttpClient 实例(默认或自定义)* @throws NullPointerException 当 url 或 client 为 null 时抛出*/private RequestChainBuilder(String url, OkHttpClient client) {// 确保 client 不为 null,若为 null 则抛出异常this.client = Objects.requireNonNull(client, "client 不能为 null");// 解析 URL 并创建 URL 构建器,若 URL 格式错误则抛出异常this.urlBuilder = Objects.requireNonNull(HttpUrl.parse(url), "url 格式错误").newBuilder();// 创建请求构建器this.requestBuilder = new Request.Builder();}/*** 添加单个 URL 查询参数(链式调用)。** @param key   参数名,不可为 null* @param value 参数值,可为 null(将被编码为空字符串)* @return 当前构建器实例,支持链式调用* @throws IllegalArgumentException 当 key 为 null 时抛出*/public RequestChainBuilder addUrlParam(String key, String value) {// 确保参数名不为空,若为空则抛出异常if (key == null) throw new IllegalArgumentException("参数名不能为空");// 向 URL 构建器中添加查询参数,若值为 null 则编码为空字符串urlBuilder.addQueryParameter(key, value != null ? value : "");// 返回当前构建器实例,以支持链式调用return this;}/*** 添加单个请求头字段(链式调用)。** @param key   头字段名,不可为 null* @param value 头字段值,可为 null(OkHttp 会自动处理 null 值)* @return 当前构建器实例,支持链式调用* @throws IllegalArgumentException 当 key 为 null 时抛出*/public RequestChainBuilder addHeader(String key, String value) {if (key == null) throw new IllegalArgumentException("头字段名不能为空");requestBuilder.addHeader(key, value);return this;}/*** 批量添加 URL 参数** @param params 包含要添加的 URL 参数的 Map* @return 当前构建器实例*/public RequestChainBuilder addUrlParam(Map<String, String> params) {// 若参数不为空,则遍历参数并调用 addUrlParam 方法添加每个参数if (params != null) {for (Map.Entry<String, String> entry : params.entrySet()) {addUrlParam(entry.getKey(), entry.getValue());}}// 返回当前构建器实例,以支持链式调用return this;}/*** 批量添加请求头** @param headers 包含要添加的请求头的 Map* @return 当前构建器实例*/public RequestChainBuilder addHeaders(Map<String, String> headers) {// 若头信息不为空,则遍历头信息并调用 addHeader 方法添加每个头信息if (headers != null) {for (Map.Entry<String, String> entry : headers.entrySet()) {addHeader(entry.getKey(), entry.getValue());}}// 返回当前构建器实例,以支持链式调用return this;}/****************** GET请求封装 ********************//*** 设置请求方法为 GET* GET 请求不需要请求体,调用后可继续添加查询参数或请求头** @return 当前构建器实例*/public RequestChainBuilder get() {// 向请求构建器中设置请求方法为 GETrequestBuilder.get();// 返回当前构建器实例,以支持链式调用return this;}/****************** POST请求封装 ********************//*** 设置请求方法为 POST* 调用后需通过 {@link #formData(Map)}、{@link #jsonBody(String)} 等方法设置请求体** @return 当前构建器实例*/public RequestChainBuilder post() {// 默认设置空请求体this.requestBody = RequestBody.create(null, new byte[0]);// 返回当前构建器实例,以支持链式调用return this;}// ------------------------------ Body 参数配置 ------------------------------/*** 设置 FormData 表单参数(multipart/form-data)* 自动构建 {@link MultipartBody},媒体类型为 {@code multipart/form-data}** @param params 表单参数(键值对)* @return 当前实例*/public RequestChainBuilder formData(Map<String, String> params) {// 参数校验if (params == null) throw new IllegalArgumentException("参数 params 不能为空");// 创建 MultipartBody 构建器,并设置媒体类型为 multipart/form-dataMultipartBody.Builder bodyBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);// 遍历参数并添加到 MultipartBody 构建器中params.forEach(bodyBuilder::addFormDataPart);// 构建请求体this.requestBody = bodyBuilder.build();// 返回当前构建器实例,以支持链式调用return this;}/*** 设置 multipart/form-data 表单参数(含文件上传)* <p>* 示例:上传单个文件* <pre>* File avatar = new File("avatar.png");* MediaType imageType = MediaType.parse("image/png");* String uploadResult = OkHttp_Util.post("https://api.upload.com")*     .formData("file", avatar, imageType) // 文件参数*     .addFormDataPart("username", "dolphin") // 普通表单参数(需配合 MultipartBody.Builder)*     .execute_Pro();* </pre>** @param key       表单字段名* @param file      上传文件* @param mediaType 文件类型(如 MediaType.parse("image/png"))* @return 当前构建器实例*/public RequestChainBuilder formData(String key, File file, MediaType mediaType) {// 参数校验if (key == null) throw new IllegalArgumentException("参数 key 不能为空");if (file == null) throw new IllegalArgumentException("参数 file 不能为空");if (mediaType == null) throw new IllegalArgumentException("参数 mediaType 不能为空");// 创建 MultipartBody 构建器,并设置媒体类型为 multipart/form-dataMultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM)// 添加文件部分,设置 Content-Disposition 头信息.addPart(Headers.of("Content-Disposition", "form-data; name=\"" + key + "\"; filename=\"" + file.getName() + "\""),RequestBody.create(mediaType, file));// 构建请求体this.requestBody = builder.build();// 返回当前构建器实例,以支持链式调用return this;}/*** 设置 x-www-form-urlencoded 表单参数* 自动构建 {@link FormBody},媒体类型为 {@code application/x-www-form-urlencoded}** @param params 表单参数(键值对)* @return 当前实例*/public RequestChainBuilder formUrlEncoded(Map<String, String> params) {// 参数校验if (params == null) throw new IllegalArgumentException("参数 params 不能为空");// 创建 FormBody 构建器FormBody.Builder bodyBuilder = new FormBody.Builder();// 遍历参数并添加到 FormBody 构建器中params.forEach(bodyBuilder::add);// 构建请求体this.requestBody = bodyBuilder.build();// 返回当前构建器实例,以支持链式调用return this;}/*** 设置 Raw JSON 数据* 自动设置媒体类型为 {@code application/json; charset=utf-8}** @param json JSON 字符串* @return 当前实例*/public RequestChainBuilder jsonBody(String json) {// 参数校验if (json == null) throw new IllegalArgumentException("参数 json 不能为空");// 创建 JSON 格式的请求体this.requestBody = RequestBody.create(json, JSON_TYPE);// 返回当前构建器实例,以支持链式调用return this;}/*** 设置 Raw 文本数据* 自动设置媒体类型为 {@code text/plain; charset=utf-8}** @param text 文本内容* @return 当前实例*/public RequestChainBuilder rawText(String text) {// 参数校验if (text == null) throw new IllegalArgumentException("参数 text 不能为空");// 创建纯文本格式的请求体this.requestBody = RequestBody.create(text, TEXT_PLAIN_TYPE);// 返回当前构建器实例,以支持链式调用return this;}/*** 设置 Raw XML 数据* 自动设置媒体类型为 {@code application/xml; charset=utf-8}** @param xml XML 字符串* @return 当前实例*/public RequestChainBuilder rawXml(String xml) {// 参数校验if (xml == null) throw new IllegalArgumentException("参数 xml 不能为空");// 创建 XML 格式的请求体this.requestBody = RequestBody.create(xml, XML_TYPE);// 返回当前构建器实例,以支持链式调用return this;}/*** 设置二进制数据* 媒体类型为 {@code application/octet-stream}** @param data 二进制字节数组* @return 当前实例*/public RequestChainBuilder binaryBody(byte[] data) {// 参数校验if (data == null) throw new IllegalArgumentException("参数 data 不能为空");// 创建二进制格式的请求体this.requestBody = RequestBody.create(data, MediaType.get("application/octet-stream"));// 返回当前构建器实例,以支持链式调用return this;}/*** 执行同步请求并返回原始响应对象。* <p>* 适用于需要手动处理响应状态码和响应体的场景,需调用者手动关闭响应体。** @return OkHttp 的 {@link Response} 对象* @throws IOException 网络异常、请求超时或服务器错误*/public Response execute() throws IOException {// 构建最终URLHttpUrl httpUrl = urlBuilder.build();// POST请求设置请求体if (requestBody != null) {// 若请求体不为空,则设置请求方法为 POST 并设置请求体requestBuilder.method("POST", requestBody);}// 设置URL并构建请求Request request = requestBuilder.url(httpUrl).build();// 执行请求并返回响应return client.newCall(request).execute();}/*** 执行同步请求并返回处理后的响应字符串(自动处理非成功状态码)。* <p>* 功能包括:* <ul>*     <li>自动关闭响应体(通过 try-with-resources)</li>*     <li>检查响应状态码,非 2xx 状态码抛出 {@link OkHttp_Util.HttpException}</li>*     <li>将响应体转换为 UTF-8 编码的字符串</li>* </ul>* 自动关闭响应体,处理非成功状态码({@code response.isSuccessful()})* </p>** @return 响应正文(UTF-8 字符串)* @throws IOException               网络异常、响应体解析失败或 I/O 错误* @throws OkHttp_Util.HttpException 当响应状态码非 2xx 时抛出,包含状态码和错误消息*/public String execute_Pro() throws IOException {// 构建最终URLHttpUrl httpUrl = urlBuilder.build();// POST请求设置请求体if (requestBody != null) {// 若请求体不为空,则设置请求方法为 POST 并设置请求体requestBuilder.method("POST", requestBody);}// 设置URL并构建请求Request request = requestBuilder.url(httpUrl).build();// 执行请求并自动关闭响应体try (Response response = client.newCall(request).execute()) {// 解析响应并返回响应正文return OkHttp_Util.parseResponse(response);}}/*** 执行异步请求,通过回调处理响应结果。* <p>* 支持处理成功响应({@link Callback#onResponse(Call, Response)})和失败情况({@link Callback#onFailure(Call, IOException)})。* <p>* **注意**:异步请求不会自动关闭响应体,需在 {@link Callback#onResponse(Call, Response)} 中手动关闭。** @param callback 异步回调接口,不可为 null* @throws NullPointerException 当 callback 为 null 时抛出*/public void enqueue(Callback callback) {try {// 检查 OkHttpClient 实例是否为 nullif (client == null) {// 若为 null,则调用回调的 onFailure 方法并传入异常信息callback.onFailure(null, new IOException("OkHttpClient 实例为 null"));return;}// 构建请求Request request = requestBuilder.url(urlBuilder.build()).build();// 检查请求是否为 nullif (request == null) {// 若为 null,则调用回调的 onFailure 方法并传入异常信息callback.onFailure(null, new IOException("请求构建失败,Request 为 null"));return;}// 执行异步请求client.newCall(request).enqueue(callback);} catch (IllegalStateException e) {// 记录 URL 构建失败的日志// log.error("URL构建失败", e);System.err.println("URL构建失败: " + e.getMessage());// 调用回调的 onFailure 方法并传入异常信息callback.onFailure(null, new IOException("URL构建失败"));} catch (Exception e) {// 记录异步请求失败的日志// log.error("异步请求失败", e);System.err.println("异步请求失败: " + e.getMessage());// 调用回调的 onFailure 方法并传入异常信息callback.onFailure(null, new IOException("异步请求失败"));}}}/*** 重载工厂方法:创建一个 GET 请求的链式构建器** @param url 请求的 URL* @return 链式构建器实例*/public static RequestChainBuilder get(String url) {// 创建一个 RequestChainBuilder 实例并设置请求方法为 GETreturn new RequestChainBuilder(url, OkHttp_Util.getDefaultInstance()).get();}/*** 重载工厂方法:创建一个 POST 请求的链式构建器** @param url 请求的 URL* @return 链式构建器实例*/public static RequestChainBuilder post(String url) {// 创建一个 RequestChainBuilder 实例并设置请求方法为 POSTreturn new RequestChainBuilder(url, OkHttp_Util.getDefaultInstance()).post();}/*** 重载工厂方法:支持传入自定义 OkHttpClient 实例,创建一个使用自定义 OkHttpClient 实例的 GET 请求的链式构建器** @param url    请求的 URL* @param client 自定义的 OkHttpClient 实例* @return 链式构建器实例*/public static RequestChainBuilder get(String url, OkHttpClient client) {// 创建一个 RequestChainBuilder 实例并设置请求方法为 GET,使用自定义的 OkHttpClient 实例return new RequestChainBuilder(url, client).get();}/*** 重载工厂方法:支持传入自定义 OkHttpClient 实例,创建一个使用自定义 OkHttpClient 实例的 POST 请求的链式构建器** @param url    请求的 URL* @param client 自定义的 OkHttpClient 实例* @return 链式构建器实例*/public static RequestChainBuilder post(String url, OkHttpClient client) {// 创建一个 RequestChainBuilder 实例并设置请求方法为 POST,使用自定义的 OkHttpClient 实例return new RequestChainBuilder(url, client).post();}// endregionpublic static void main(String[] args) throws IOException {// 使用默认配置OkHttpClient defaultClient = OkHttp_Util.getDefaultInstance();// -------------------------------------------------------------------------------String responseDefault = OkHttp_Util.get("https://api.example.com").addUrlParam("key", "value").execute_Pro();// -------------------------------------------------------------------------------// 创建自定义配置OkHttpClient.Builder customBuilder = OkHttp_Util.customBuilder().addInterceptor(new LoggingInterceptor()).connectTimeout(30, TimeUnit.SECONDS);// 提交并实例化自定义配置(单例)OkHttp_Util.buildCustomInstance(customBuilder);// 获取自定义配置实例OkHttpClient customClient = OkHttp_Util.getCustomInstance();String responseCustom = OkHttp_Util.get("https://api.example.com", customClient).addUrlParam("key", "value").execute_Pro();}
}

六、总结

本工具类通过封装OkHttp的复杂配置,提供以下优势:

  • 开发效率提升:链式API简化网络请求编写
  • 可维护性强:统一配置入口,修改全局参数方便
  • 安全性增强:标准化HTTPS证书管理
  • 健壮性保障:内置重试机制和异常处理

适合中大型项目作为基础网络组件使用,建议根据实际业务需求调整超时时间和重试策略。

相关文章:

OkHttp3.X 工具类封装:链式调用,支持HTTPS、重试、文件上传【内含常用设计模式设计示例】

OkHttp3.X 工具类封装&#xff1a;链式调用&#xff0c;支持HTTPS、重试、文件上传 基于OkHttp3.X封装&#xff0c;提供链式调用API&#xff0c;简化GET/POST请求&#xff0c;支持HTTPS、自动重试、文件上传等功能&#xff0c;提升开发效率。 在 Android 和 Java 开发中&#x…...

Unity SpriteEditor(精灵图片编辑器)

&#x1f3c6; 个人愚见&#xff0c;没事写写笔记 &#x1f3c6;《博客内容》&#xff1a;Unity3D开发内容 &#x1f3c6;&#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f50e;SpriteEditor&#xff1a; 精灵图片编辑器 &#x1f4cc;用于编辑2D游戏开发中使用的Sp…...

雅思写作--70个高频表达

文章目录 1. learn new skills学生通过户外活动学到很多新技2. take immediate action to do各国采取有效行动以保护环境政府采取了必要行动以减少失业。你应该立即采取行动来解3. communication skills4. grow significantly5. have many advantages1. learn new skills “lea…...

Anaconda中配置Pyspark的Spark开发环境

Anaconda中配置Pyspark的Spark开发环境 目录 1.在控制台中测试ipython是否启动正常2.安装好Java3.安装Spark并配置环境变量4.PySpark配置5.修改spark\conf下的spark-env文件6.测试Pyspark是否安装成功 1.在控制台中测试ipython是否启动正常 anaconda正常安装 这里先检查ipyt…...

Spring 提供了多种依赖注入的方式

构造器注入&#xff08;Constructor Injection&#xff09; 构造器注入是通过类的构造函数来注入依赖项。这是 Spring 推荐的方式&#xff0c;因为它提供了不可变性和更好的可测试性。 import org.springframework.stereotype.Component;Component public class ServiceA {pub…...

面经-计算机网络——OSI七层模型与TCP/IP四层模型的对比详解

OSI七层模型与TCP/IP四层模型的对比详解 一、图示解析&#xff1a;分层封装结构 你提供的图清晰展示了网络通信中从应用层到物理层的封装过程&#xff0c;每一层都会对上层的数据加上自己的头部信息&#xff08;Header&#xff09;&#xff1a; 应用层&#xff1a; 应用…...

网络安全知识问答微信小程序的设计与实现

网络安全知识问答微信小程序的设计与实现&#xff0c;说白了&#xff0c;就是搭建一款网络安全知识问答微信小程序&#xff0c;类似网络安全百科直通车。三步走。 需求沟通 进行需求沟通&#xff0c;此处省略1000字。 画草图 根据沟通的需求&#xff0c;进行整理&#xff0c…...

Canvas特效实例:黑客帝国-字母矩阵(字母雨)

黑客帝国-字幕矩阵&#xff08;字母雨&#xff09; 效果预览代码实现思路解析遗留问题 效果预览 话不多说&#xff0c;我们直接上效果&#xff1a;当页面加载完成&#xff0c;屏幕上会落下如瀑布般的绿色字母流&#xff0c;不断向下滑动&#xff0c;仿佛进入了黑客帝国的数字世…...

「Mac畅玩AIGC与多模态11」开发篇07 - 使用自定义名言插件开发智能体应用

一、概述 本篇介绍如何在 macOS 环境下,通过编写自定义 OpenAPI Schema,将无需认证的名言服务接入 Dify 平台,并开发基于外部公共数据的智能体应用。本案例继续实践 GET 请求型 API 的实际调用技巧。 二、环境准备 1. 确认本地开发环境 macOS 系统Dify 平台已部署并可访问…...

快速上手非关系型数据库-MongoDB

简介 MongoDB 是一个基于文档的 NoSQL 数据库&#xff0c;由 MongoDB Inc. 开发。 NoSQL&#xff0c;指的是非关系型的数据库。NoSQL有时也称作Not Only SQL的缩写&#xff0c;是对不同于传统的关系型数据库的数据库管理系统的统称。 MongoDB 的设计理念是为了应对大数据量、…...

响应式布局,在飞帆平台中如此简单

这些控件都是可以自己动手去实现的。也可以将这些控件复制到自己名下进行修改。 响应式布局https://fvi.cn/782...

UN R79 关于车辆转向装置形式认证的统一规定(正文部分1)

UN R79法规是针对转向装置的型式认证法规&#xff0c;涉及A/B1/C类的横向控制辅助驾驶功能&#xff0c;对各功能的功能边界、性能要求、状态提示、故障警示以及型式认证要提交的信息做了规范&#xff0c;本文结合百度文心一言对法规进行翻译&#xff0c;并结合个人理解对部分内…...

深度学习系统学习系列【1】之基本知识

文章目录 说明基础知识人工智能、机器学习、深度学习的关系机器学习传统机器学习的缺陷选择深度学习的原因深度学习的关键问题深度学习的应用深度学习的加速硬件GPU环境搭建主流深度学习框架对比 说明 文章属于个人学习笔记内容&#xff0c;仅供学习和交流。内容参考深度学习原…...

python3GUI--视频监控管理平台 By:PyQt5(详细讲解)

文章目录 一&#xff0e;前言二&#xff0e;相关知识1.PyQt52.RTSP协议&#x1f4cc; 简介&#xff1a;&#x1f9e9; 特点&#xff1a;&#x1f4e1; 工作方式&#xff1a; 2. **RTMP&#xff08;Real-Time Messaging Protocol&#xff09;**&#x1f4cc; 简介&#xff1a;&a…...

第十一届蓝桥杯 2020 C/C++组 既约分数

目录 题目&#xff1a; 题目描述&#xff1a; 题目链接&#xff1a; 思路&#xff1a; 核心思路&#xff1a; 思路详解&#xff1a; 代码&#xff1a; 代码详解&#xff1a; 题目&#xff1a; 题目描述&#xff1a; 题目链接&#xff1a; 既约分数 - 蓝桥云课 思路&a…...

如何让Steam下载速度解除封印?!

平时一直没注意到家里的路由器在偷懒。最近成功榨干家里的带宽&#xff0c;把平时一直20mb/s左右下载速度的路由器一番改造后成功steam下载速度稳定85Mb/s。平时一直都只发挥了他的1/3不到&#xff0c;真是太可惜了。 硬件 首先检查硬件&#xff0c;就千兆路由器而言&#xf…...

HOOK上瘾思维模型——AI与思维模型【88】

一、定义 HOOK上瘾思维模型是一种通过设计一系列的触发&#xff08;Trigger&#xff09;、行动&#xff08;Action&#xff09;、奖励&#xff08;Reward&#xff09;和投入&#xff08;Investment&#xff09;环节&#xff0c;来促使用户形成习惯并持续使用产品或服务的思维框…...

基于开源AI智能名片链动2+1模式S2B2C商城小程序的IP开发泡沫破局与价值重构研究

摘要&#xff1a;当前IP开发领域普遍存在"冒进式泡沫"现象&#xff0c;企业将初级IP包装为超级IP运营&#xff0c;导致资源错配与价值虚化。本文通过实证分析开源AI智能名片链动21模式S2B2C商城小程序的技术架构与商业逻辑&#xff0c;揭示其通过智能内容引擎、合规化…...

深⼊理解指针(8)

1.对上一篇的补充内容 typedef int* ptr_t #define PTR_T int* 这两种写法都是可以的 ptr_t p1, p2; //p1, p2 都是指针变量 PTR_T p3, p4; //p3 是指针变量, p4是整型变量 为什么p3 是指针变量, p4是整型变量呢&#xff1f; 因为PTR_T 真的被改为了 int* 在编译器中…...

【iview】icon样式

A. 工程中引入样式文件 iview源码工程中的example工程中如何引入iview样式 image.png 自定义工程中如何引入iview样式 一般在src/main.js中引入&#xff08;在index.html中也可以&#xff0c;当然app.vue中也可以&#xff09; import "iview/dist/styles/iview.css"B…...

【计算机视觉】三维视觉:Nerfstudio:模块化神经辐射场框架的技术突破与实战指南

深度解析Nerfstudio&#xff1a;模块化神经辐射场框架的技术突破与实战指南 技术架构与核心创新系统架构设计关键技术特性 环境配置与安装指南硬件要求全平台安装流程 实战全流程解析1. 数据采集与预处理2. 模型训练与优化3. 可视化与导出 核心技术深度解析1. 混合表示网络2. 渐…...

第二章 OpenCV篇-图像阈值的综合操作-Python

目录 一.图像阈值 二.图像平滑 1.均值滤波 2.方框滤波 3.高斯滤波 4.中值滤波 5.双边滤波 此章节主要讲解&#xff1a;图像阈值、图像平滑处理、均值滤波、方框滤波、高斯滤波、中值滤波、双边滤波。 这里先讲作者使用matplotlib模块出现错误的解决方法。 首先作者在这…...

WPF处理大规模激光数据计算与安全传输处理

WPF大规模激光数据处理与安全传输系统设计方案 一、系统架构设计 1. 整体架构 ┌─────────────────────────────────────────────┐ │ WPF客户端应用 │ ├───────────────┬…...

vue 常见ui库对比(element、ant、antV等)

Element UI 1. 简介 Element UI 是一个基于 Vue 2 和 Vue 3 的企业级 UI 组件库&#xff0c;提供了丰富的组件和主题定制功能。官方网站&#xff1a;Element UI 2. 主要特点 丰富的组件&#xff1a;包括表单、表格、布局、导航、弹窗等多种组件。主题定制&#xff1a;支持主…...

【c++】【STL】stack详解

目录 stack类的作用什么是容器适配器stack的接口构造函数emptysizetoppushpopswap关系运算符重载 stack类的实现 stack类的作用 stack是stl库提供的一种容器适配器&#xff0c;也就是我们数据结构中学到的栈&#xff0c;是非常常用的数据结构&#xff0c;特点是遵循LIFO&#…...

单片机-89C51部分:12 pwm 呼吸灯 直流电机

飞书文档https://x509p6c8to.feishu.cn/wiki/JkzfwSoFBiUKc4kh8IoccTfyndg 一、什么是PWM&#xff1f; PWM是脉冲宽度调制的缩写&#xff0c;它是一种通过调整脉冲信号的高电平和低电平时间比例来控制电路输出的技术。简单来说&#xff0c;PWM是一种控制电子设备输出电压或电…...

WPF实现数据库操作与日志记录

1. 数据库操作实现 1.1 数据库连接基类 public abstract class DatabaseBase : IDisposable {protected string ConnectionString { get; }protected IDbConnection Connection { get; private set; }protected DatabaseBase(string connectionString){ConnectionString = co…...

用spring-boot-maven-plugin打包成单个jar有哪些缺点优化方案

Spring Boot 的 Fat JAR&#xff08;通过 spring-boot-maven-plugin 打包&#xff09;虽然简化了部署&#xff0c;但也存在一些潜在缺点&#xff0c;需根据场景权衡&#xff1a; 1. 启动速度较慢 原因&#xff1a; Fat JAR 需要在启动时解压并加载所有依赖的 JAR 文件到类路径…...

Spring Boot 使用 WebMagic 爬虫框架入门

1. 创建 Spring Boot 项目 使用 Spring Initializr 创建一个 Spring Boot 项目&#xff0c;选择需要的依赖&#xff0c;如 Spring Web 等。 2. 添加 WebMagic 依赖 在项目的 pom.xml 文件中添加 WebMagic 的核心和扩展依赖&#xff1a; <dependency><groupId>u…...

【软件设计师:复习】上午题核心知识点总结(二)

一、计算机网络(常考) 1.网络模型与协议(必考) 1.OSI七层模型 vs. TCP/IP四层模型 OSI七层TCP/IP四层核心协议/设备功能应用层(Application)应用层HTTP、FTP、DNS、SMTP提供用户接口和服务表示层(Presentation)SSL/TLS、JPEG、ASCII数据格式转换、加密/解密会话层(S…...

TensorRt10学习第一章

建立TensorRt时必须要有Public ILogger,因为createInferBuiler和createruntime要用&#xff0c;是一个接口 出错打印 和...

【LeetCode Hot100】回溯篇

前言 本文用于整理LeetCode Hot100中题目解答&#xff0c;因题目比较简单且更多是为了面试快速写出正确思路&#xff0c;只做简单题意解读和一句话题解方便记忆。但代码会全部给出&#xff0c;方便大家整理代码思路。 46. 全排列 一句话题意 给定一个无重复数字的序列&#xf…...

Go 语言中一个功能强大且广泛使用的数据验证库github.com/go-playground/validator/v10

github.com/go-playground/validator/v10 是 Go 语言中一个功能强大且广泛使用的数据验证库&#xff0c;主要用于对结构体字段进行数据校验&#xff0c;确保数据的合法性和完整性。以下是其核心作用、使用场景及代码案例的详细说明&#xff1a; 核心作用 数据校验 支持对结构体…...

Java 多线程进阶:线程安全、synchronized、死锁、wait/notify 全解析(含代码示例)

在 Java 并发编程中&#xff0c;“线程安全” 是核心议题之一。本文将深入讲解线程安全的实现手段、synchronized 的使用方式、可重入锁、死锁的成因与避免、wait/notify 通信机制等&#xff0c;并配合实际代码案例&#xff0c;帮助你彻底搞懂 Java 线程协作机制。 一、线程安全…...

windows电脑端SSH连接开termux的安卓端

&#xff08;确保你此前已经安装好了ssh&#xff09;在手机termux当中输入&#xff1a; 查看状态&#xff1a;ssh 启动服务&#xff1a;sshd 查看IP&#xff1a;ifconfig 然后在电脑端&#xff1a;...

Java 期中考试练习题

一、引言 Java 作为一门广泛应用的编程语言&#xff0c;在计算机相关专业的课程体系中占据重要地位。期中考试是检验同学们对 Java 知识掌握程度的重要环节。本文将呈现一些典型的 Java 期中考试试题&#xff0c;并进行详细讲解&#xff0c;希望能帮助大家更好地理解和掌握 Ja…...

【Unity】 组件库分类详解

1️⃣ Audio&#xff08;音频组件&#xff09; 用于处理游戏中的声音。 Audio Source 读音[ˈɔːdiəʊ ˈsɔːs]&#xff0c;音频源组件&#xff0c;用于播放音频文件&#xff0c;可设置音量、Pitch、循环播放等属性&#xff0c;是音频播放的核心组件。 Audio Listener 读音…...

Java 中使用正则表达式

1. 引入包 在使用正则表达式之前&#xff0c;需要引入包&#xff1a; import java.util.regex.Matcher; import java.util.regex.Pattern; 2. 常用模式规则 元字符 &#xff1a;这些是正则表达式中的特殊字符&#xff0c;用于匹配特定的模式。 . &#xff1a;匹配任意单个字…...

如何降低LabVIEW开发费用

在 LabVIEW 开发过程中&#xff0c;开发费用是用户和开发者共同关注的重点。过高的开发成本可能会压缩项目利润空间&#xff0c;甚至影响项目的可行性。下面将介绍降低 LabVIEW 开发费用的有效方法。 ​ 合理规划项目需求&#xff0c;避免后期增加​ 在项目启动阶段&#xff…...

WPF使用SQLSugar和Nlog

WPF应用中使用SQLSugar和NLog实现数据库操作与日志记录 1. 准备工作 首先,通过NuGet安装必要的包: Install-Package SQLSugarCore Install-Package NLog Install-Package NLog.Config Install-Package NLog.Targets.File 2. 配置NLog 在项目中添加nlog.config文件: <…...

Python10天冲刺-设计模型之策略模式

策略模式是一种行为设计模式&#xff0c;它允许你在运行时动态地改变对象的行为。这种模式的核心思想是将一组相关的算法封装在一起&#xff0c;并让它们相互替换。 下面是使用 Python 实现策略模式的一个示例&#xff1a; 示例代码 假设我们有一个简单的购物车系统&#xf…...

Js扩展DOM、BOM、AJAX、事件、定时器

BOM 操作 BOM指的是浏览器对象模型&#xff1a;Browser Object Mode&#xff0c;通过操作 window 对象的属性和方法来实现与浏览器的交互。 BOM的构成如下图所示&#xff1a; 其中&#xff0c;window对象是顶级对象&#xff0c;在 window 对象下面有一些重要的属性&#xff1…...

奥地利学派方法论的三个基础

主观价值论&#xff1a; 一切估价行为皆来自于个人&#xff0c;价格现象只能从主观估价中得到解释。 个人只在边际上做决策&#xff0c;边际价值是递减的。 罗斯巴德的等式&#xff1a;三个单位的某个东西的总效用 > 两个单位的总效用 > 一个单位的总效用&#xff0c;但…...

WPF之Image控件详解

文章目录 1. 概述2. Image控件的基本属性2.1 Source属性2.2 Stretch属性2.3 StretchDirection属性 3. 在XAML中使用Image控件3.1 基本用法3.2 设置拉伸模式3.3 设置图像对齐方式 4. 在代码中操作Image控件4.1 加载本地图像4.2 异步加载图像4.3 从流中加载图像4.4 控制图像的解码…...

如何将 VS Code 与 Linux 系统高效连接:从入门到进阶

引言 无论是开发服务器应用、管理远程主机&#xff0c;还是在本地 Linux 环境中提升开发效率&#xff0c;Visual Studio Code&#xff08;VS Code&#xff09; 凭借其强大的扩展能力&#xff0c;成为连接 Linux 系统的利器。本文将详细介绍 三种主流方法&#xff0c;助你无缝对…...

Matlab/Simulink - BLDC直流无刷电机仿真基础教程(五) - animateRotorPosition脚本讲解与使用

Matlab/Simulink - BLDC直流无刷电机仿真基础教程&#xff08;五&#xff09; - animateRotorPosition脚本讲解与使用 前言一、animateRotorPosition脚本内容二、脚本功能讲解三、脚本修改与模型配置四、可视化效果展示五、修改后脚本内容文章相关模型文件下载链接参考链接 前言…...

安川机器人常见故障报警及解决办法

机器人权限设置 操作权限设置(如果密码不对,就证明密码被人修改) 编辑模式密码:无(一把钥匙,默认) 管理模式密码:999999999(9个9,二把钥匙) 安全模式密码:555555555(9个5,三把钥匙,权限最高,有的型号机器人,没有此模式,但最高密码为安全模式密码) 示教器…...

【Quest开发】极简版!透视环境下抠出身体并能遮挡身体上的服装

前两天发了一个很复杂的版本&#xff0c;又鼓捣了一下发现完全没有必要。我之前的理解有点偏&#xff08;不是错误的但用法错了&#xff09;&#xff0c;但是有一些小伙伴收藏了&#xff0c;害怕里面的某些东西对谁有用&#xff0c;所以写了一篇新的&#xff0c;前两步配置环境…...

【Github仓库】Learn-Vim随笔

一、前言 学习vim的过程中发现了很多很好的资源&#xff0c;其中不乏bilibili上up主的精品教程。也在YouTube上看过很多教程。但Learn-Vim这个Github仓库实在让我受益良多。 本笔记便是出于此仓库&#xff1a; 仓库地址 附上个人.vimrc配置文件: syntax on " 开启语法高…...

【2025五一数学建模竞赛C题】社交媒体平台用户分析问题|建模过程+完整代码论文全解全析

你是否在寻找数学建模比赛的突破点&#xff1f;数学建模进阶思路&#xff01; 作为经验丰富的美赛O奖、国赛国一的数学建模团队&#xff0c;我们将为你带来本次数学建模竞赛的全面解析。这个解决方案包不仅包括完整的代码实现&#xff0c;还有详尽的建模过程和解析&#xff0c…...