Java开源工具库使用之httpclient

news2024/11/30 11:47:45

文章目录

  • 前言
  • 一、简单使用
    • 1.1 get 请求
    • 1.2 post 简单表单请求
    • 1.3 表单上传文件
    • 1.4 上传 json 数据
  • 二、高级用法
    • 2.1 超时和重试
    • 2.2 Cookie
    • 2.3 拦截器
    • 2.4 fluent API
  • 三、3.1旧版本使用
    • 3.1 Get 请求
    • 3.2 Post 请求
  • 四、异步版本使用
    • 4.1 基本请求
    • 4.2 请求流水线执行
  • 参考

前言

HttpClient 成立于2001年,是 Apache Jakarta Commons 项目下的子项目,2004 年离开 Commons,提升成为一个单独的 Jakarta 项目。2005 年,Jakarta 创建了 HttpComponents 项目,目标是开发 HttpClient 3.x 的继任者。2007 年,Commons 项目,也就是 HttpClient 项目的发源地,离开了 Jakarta, 成为了1个新的顶级项目。不久之后,HttpComponents 也离开了 Jakarta, 成为一个独立的顶级项目,负责维护 HttpClient 的工作。

  • HttpClient 提供了高效、最新、功能丰富的支持 HTTP 协议的客户端编程工具包,支持最新版本的 HTTP 协议。

  • HttpComponents 项目,包含 HttpClientHttpCore, AsyncClient 三大模块,提供了更好的性能和更大的灵活性。

  • HttpClient 是依赖于 HttpCore 的,最新的 HttpClient 版本为 5.2

  • HttpClient 是以 3.1 版本为分隔,大版本之间用法有很多不同

  • 最新文档地址:https://hc.apache.org/httpcomponents-client-5.2.x/index.html

  • 旧版文档地址:https://hc.apache.org/httpclient-legacy/userguide.html

  • github 地址:https://github.com/apache/httpcomponents-client

  • pom 依赖

    <!-- 最新版本5 -->
    <dependency>
        <groupId>org.apache.httpcomponents.client5</groupId>
        <artifactId>httpclient5</artifactId>
        <version>5.2.1</version>
    </dependency>
    
    <!-- 版本4 -->
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.13</version>
    </dependency>
    
    <!-- 旧版本3,07年后没更新 -->
    <dependency>
        <groupId>commons-httpclient</groupId>
        <artifactId>commons-httpclient</artifactId>
        <version>3.1</version>
    </dependency>
    

一、简单使用

1.1 get 请求

String url = "http://httpbin.org/get";
try (final CloseableHttpClient httpclient = HttpClients.createDefault()) {
    final HttpGet httpget = new HttpGet(url);

    // Create a custom response handler
    final HttpClientResponseHandler<String> responseHandler = response -> {
        final int status = response.getCode();
        if (status >= HttpStatus.SC_SUCCESS && status < HttpStatus.SC_REDIRECTION) {
            final HttpEntity entity = response.getEntity();
            try {
                return entity != null ? EntityUtils.toString(entity) : null;
            } catch (final ParseException ex) {
                throw new ClientProtocolException(ex);
            }
        } else {
            throw new ClientProtocolException("Unexpected response status: " + status);
        }
    };
    final String responseBody = httpclient.execute(httpget, responseHandler);
    System.out.println(responseBody);
}

1.2 post 简单表单请求

String url = "http://httpbin.org/post";
String username = "root";
String loginPw = "";
try (final CloseableHttpClient httpclient = HttpClients.createDefault()) {
    final HttpPost httppost = new HttpPost(url);
    final List<NameValuePair> params = new ArrayList<>();
    params.add(new BasicNameValuePair("username", username));
    params.add(new BasicNameValuePair("password", loginPw));
    httppost.setEntity(new UrlEncodedFormEntity(params));

    // Create a custom response handler
    final HttpClientResponseHandler<String> responseHandler = response -> {
        final int status = response.getCode();
        if (status >= HttpStatus.SC_SUCCESS && status < HttpStatus.SC_REDIRECTION) {
            final HttpEntity entity = response.getEntity();
            try {
                return entity != null ? EntityUtils.toString(entity) : null;
            } catch (final ParseException ex) {
                throw new ClientProtocolException(ex);
            }
        } else {
            throw new ClientProtocolException("Unexpected response status: " + status);
        }
    };
    final String responseBody = httpclient.execute(httppost, responseHandler);
    System.out.println(responseBody);
}

1.3 表单上传文件

final HttpPost httppost = new HttpPost(url);
            
final MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.addTextBody("username", username);
builder.addTextBody("password", password);
builder.addBinaryBody("file", new File("src/test/resources/test.txt"), ContentType.APPLICATION_OCTET_STREAM, "test.txt");

final HttpEntity multipart = builder.build();

httppost.setEntity(multipart);

1.4 上传 json 数据

final HttpPost httppost = new HttpPost(url);

httppost.setHeader("Accept", "application/json");
httppost.setHeader("Content-type", "application/json");

final String json = "{\"id\":1,\"name\":\"John\"}";
final StringEntity stringEntity = new StringEntity(json);
httppost.setEntity(stringEntity);

二、高级用法

2.1 超时和重试

超时控制可以通过 RequestConfig 这个类控制

String url = "http://httpbin.org/get";

RequestConfig requestConfig = RequestConfig.custom()
    .setConnectionRequestTimeout(Timeout.ofSeconds(100L))//连接请求超时, 0为无限。默认值:3分钟。
    .setResponseTimeout(Timeout.ofSeconds(600L)) // 响应超时时间,0为无限。带有消息复用的HTTP传输可能不支持响应超时
    .build();

try (final CloseableHttpClient httpclient = HttpClients.createDefault()) {
    final HttpGet httpGet = new HttpGet(url);
    httpGet.setConfig(requestConfig);
    final HttpClientResponseHandler<String> responseHandler = response -> {
        final int status = response.getCode();

        if (status >= HttpStatus.SC_SUCCESS && status < HttpStatus.SC_REDIRECTION) {
            final HttpEntity entity = response.getEntity();
            try {
                return entity != null ? EntityUtils.toString(entity) : null;
            } catch (final ParseException ex) {
                throw new ClientProtocolException(ex);
            }
        } else {
            throw new ClientProtocolException("Unexpected response status: " + status);
        }
    };
    httpclient.execute(httpGet, responseHandler);
}

重试,默认重试策略为最大次数1次,重试间隔为1秒。

String url = "http://httpbin.org/get";

try (final CloseableHttpClient httpclient = HttpClients.custom()
     .setRetryStrategy(new DefaultHttpRequestRetryStrategy(3, TimeValue.ofSeconds(20L)))
     .build()) {
    final HttpGet httpGet = new HttpGet(url);

    final HttpClientResponseHandler<String> responseHandler = response -> {
        final int status = response.getCode();

        if (status >= HttpStatus.SC_SUCCESS && status < HttpStatus.SC_REDIRECTION) {
            final HttpEntity entity = response.getEntity();
            try {
                return entity != null ? EntityUtils.toString(entity) : null;
            } catch (final ParseException ex) {
                throw new ClientProtocolException(ex);
            }
        } else {
            throw new ClientProtocolException("Unexpected response status: " + status);
        }
    };
    httpclient.execute(httpGet, responseHandler);
}

2.2 Cookie

HttpClients.createDefault 已经内置默认 Cookie 管理器可以用来携带 Cookie 访问

String url = "http://httpbin.org/cookies/set/foo/bar";
String url2 = "http://httpbin.org/cookies";

try (final CloseableHttpClient httpclient = HttpClients.createDefault()) {
    final HttpGet httpGet = new HttpGet(url);

    final HttpClientResponseHandler<String> responseHandler = response -> {
        final int status = response.getCode();

        if (status >= HttpStatus.SC_SUCCESS && status < HttpStatus.SC_REDIRECTION) {
            final HttpEntity entity = response.getEntity();
            try {
                return entity != null ? EntityUtils.toString(entity) : null;
            } catch (final ParseException ex) {
                throw new ClientProtocolException(ex);
            }
        } else {
            throw new ClientProtocolException("Unexpected response status: " + status);
        }
    };
    final HttpGet httpGet2 = new HttpGet(url2);

    String responseBody2 = httpclient.execute(httpGet2, responseHandler);
    System.out.println(responseBody2);

    final String responseBody = httpclient.execute(httpGet, responseHandler);
    System.out.println(responseBody);

    responseBody2 = httpclient.execute(httpGet2, responseHandler);
    System.out.println(responseBody2);
}

还可以访问通过本地上下文绑定 cookie,从而获取cookie 信息

String url = "http://httpbin.org/cookies/set/foo/bar";

try (final CloseableHttpClient httpclient = HttpClients.createDefault()) {
    // 创建一个本地的 Cookie 存储
    final CookieStore cookieStore = new BasicCookieStore();

    final HttpClientContext localContext = HttpClientContext.create();
    // 绑定 cookieStore 到 localContext
    localContext.setCookieStore(cookieStore);

    final HttpGet httpget = new HttpGet(url);

    final HttpClientResponseHandler<String> responseHandler = response -> {
        final int status = response.getCode();

        if (status >= HttpStatus.SC_SUCCESS && status < HttpStatus.SC_REDIRECTION) {
            final HttpEntity entity = response.getEntity();
            try {
                final List<Cookie> cookies = cookieStore.getCookies();
                for (Cookie cookie : cookies) {
                    System.out.println("Local cookie: " + cookie);
                }
                return entity != null ? EntityUtils.toString(entity) : null;
            } catch (final ParseException ex) {
                throw new ClientProtocolException(ex);
            }
        } else {
            throw new ClientProtocolException("Unexpected response status: " + status);
        }
    };

    String response = httpclient.execute(httpget, localContext, responseHandler);
    System.out.println(response);
}

2.3 拦截器

httpclient 支持通过拦截器对请求进行一定的处理,有如下几个方法添加拦截器

  • addRequestInterceptorFirst
  • addRequestInterceptorLast
  • addResponseInterceptorFirst
  • addResponseInterceptorLast
  • addExecInterceptorFirst
  • addExecInterceptorLast
  • addExecInterceptorBefore
  • addExecInterceptorAfter

添加的拦截器可分为3种类型: request, response和 exec,对应请求,响应和执行。其中Exec执行的名字在枚举ChainElement 中,在 HttpClientBuilder 类源码中,可以发现除了 CACHING 其它都可以通过配置使用,并且枚举中的顺序也是Exec执行的顺序,其中 MAIN_TRANSPORT 执行包含 request 和 response 拦截器执行

ChainElement 定义了一组可用于构建HTTP请求处理管道的元素,每个元素都可以实现特定的功能,如添加自定义HTTP头、添加身份验证信息等。

public enum ChainElement {
    REDIRECT, COMPRESS, BACK_OFF, RETRY, CACHING, PROTOCOL, CONNECT, MAIN_TRANSPORT
}

下面是一个对官方拦截器例子修改的代码

AtomicLong count = new AtomicLong();

try (final CloseableHttpClient httpclient = HttpClients.custom()
     .addExecInterceptorAfter(ChainElement.PROTOCOL.name(), "custom", (request, scope, chain) -> {
         request.setHeader("request-id", Long.toString(count.incrementAndGet()));
         return chain.proceed(request, scope);
     })
     .addExecInterceptorAfter("custom", "quit3rd", ((request, scope, chain) -> {
         final Header idHeader = request.getFirstHeader("request-id");
         if (idHeader != null && "3".equalsIgnoreCase(idHeader.getValue())) {
             final ClassicHttpResponse response = new BasicClassicHttpResponse(HttpStatus.SC_NOT_FOUND, "Oppsie");
             response.setEntity(new StringEntity("bad luck", ContentType.TEXT_PLAIN));
             return response;
         } else {
             return chain.proceed(request, scope);
         }
     }))

     .addExecInterceptorBefore(ChainElement.CONNECT.name(), "AAA", (request, scope, chain) -> {
         System.out.println("AAA");
         return chain.proceed(request, scope);
     })
     .addExecInterceptorBefore("AAA", "BBB", (request, scope, chain) -> {
         System.out.println("BBB");
         return chain.proceed(request, scope);
     })
     .addExecInterceptorAfter("AAA", "CCC", (request, scope, chain) -> {
         System.out.println("CCC");
         return chain.proceed(request, scope);
     })

     .addRequestInterceptorFirst((request, entity, context) -> {
         System.out.println("第一个request first现在获取:" + context.getAttribute("foo"));
     })
     .addRequestInterceptorFirst((request, entity, context) -> {
         System.out.println("第二个request first, 现在设置name");
         context.setAttribute("foo", "bar");
     })
     .addRequestInterceptorLast((request, entity, context) -> {
         System.out.println("第一个request last现在获取:" + context.getAttribute("foo"));
     })

     .build()) {


    for (int i = 0; i < 5; i++) {
        final HttpGet httpget = new HttpGet("http://httpbin.org/get");

        System.out.println("Executing request " + httpget.getMethod() + " " + httpget.getUri());

        httpclient.execute(httpget, response -> {
            System.out.println("----------------------------------------");
            System.out.println(httpget + "->" + new StatusLine(response));
            EntityUtils.consume(response.getEntity());
            return null;
        });
    }
}

下面动图显示的是调试过程中 execChain 执行链的顺序

内置拦截器

下面是 调试过程中的request和response 拦截器,从名字就可以看出除了Main类是自定义的拦截器,其余都是自带的,其中cookie处理也是通过拦截器实现的。

请求响应拦截器

2.4 fluent API

HttpClienet 4.5 版本以上支持fluent API, 优点是代码更简洁,同时为线程安全的。

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>fluent-hc</artifactId>
    <version>4.5.13</version>
</dependency>
String urlGet = "http://httpbin.org/get";
String urlPost = "http://httpbin.org/post";

String response = Request.Get(urlGet)
    .addHeader("Authorization", "Bear:dw")
    .execute()
    .handleResponse(httpResponse -> {
        int code = httpResponse.getStatusLine().getStatusCode();
        if (code == HttpStatus.SC_SUCCESS) {
            return org.apache.http.util.EntityUtils.toString(httpResponse.getEntity());
        }
        return null;
    });

System.out.println(response);

String result = Request.Post(urlPost)
    .bodyForm(Form.form().add("foo", "bar").build())
    .execute()
    .returnContent()
    .asString();

System.out.println(result);

三、3.1旧版本使用

3.1 Get 请求

String url = "http://httpbin.com";
HttpClient client = new HttpClient();
GetMethod method = new GetMethod(url);
method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
                                new DefaultHttpMethodRetryHandler(3, false));
try {
    // Execute the method.
    int statusCode = client.executeMethod(method);

    if (statusCode != HttpStatus.SC_OK) {
        System.err.println("Method failed: " + method.getStatusLine());
    }

    // Read the response body.
    byte[] responseBody = method.getResponseBody();

    // Deal with the response.
    // Use caution: ensure correct character encoding and is not binary data
    System.out.println(new String(responseBody));

} catch (HttpException e) {
    System.err.println("Fatal protocol violation: " + e.getMessage());
    e.printStackTrace();
} catch (IOException e) {
    System.err.println("Fatal transport error: " + e.getMessage());
    e.printStackTrace();
} finally {
    // Release the connection.
    method.releaseConnection();
}

3.2 Post 请求

String url = "http://httpbin.org/post";
HttpClient client = new HttpClient();
PostMethod method = new PostMethod(url);
NameValuePair[] data = {
    new NameValuePair("user", "joe"),
    new NameValuePair("password", "bloggs")
};
method.setRequestBody(data);

try {
    int statusCode = client.executeMethod(method);
    if (statusCode != HttpStatus.SC_OK) {
        System.err.println("Method failed: " + method.getStatusLine());
    }
    byte[] responseBody = method.getResponseBody();
    System.out.println(new String(responseBody));
} catch (HttpException e) {
    System.err.println("Fatal protocol violation: " + e.getMessage());
    e.printStackTrace();
} catch (IOException e) {
    System.err.println("Fatal transport error: " + e.getMessage());
    e.printStackTrace();
} finally {
    method.releaseConnection();
}

四、异步版本使用

4.1 基本请求

final IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
                .setSoTimeout(Timeout.ofSeconds(5))
                .build();

final CloseableHttpAsyncClient client = HttpAsyncClients.custom()
    .setIOReactorConfig(ioReactorConfig)
    .build();

client.start();

final HttpHost target = new HttpHost("httpbin.org");
final String[] requestUris = new String[] {"/", "/ip", "/user-agent", "/headers"};

for (final String requestUri: requestUris) {
    final SimpleHttpRequest request = SimpleRequestBuilder.get()
        .setHttpHost(target)
        .setPath(requestUri)
        .build();

    System.out.println("请求url:" + requestUri);
    final Future<SimpleHttpResponse> future = client.execute(
        SimpleRequestProducer.create(request),
        SimpleResponseConsumer.create(),
        new FutureCallback<SimpleHttpResponse>() {

            @Override
            public void completed(final SimpleHttpResponse response) {
                System.out.println(requestUri + " 返回状态码:" + response.getCode() + ",返回内容:" + response.getBodyText());
            }

            @Override
            public void failed(final Exception ex) {
                System.out.println(request + "->" + ex);
            }

            @Override
            public void cancelled() {
                System.out.println(request + " cancelled");
            }

        });
    future.get();
}

System.out.println("Shutting down");
client.close(CloseMode.GRACEFUL);

4.2 请求流水线执行

final MinimalHttpAsyncClient client = HttpAsyncClients.createMinimal(
    H2Config.DEFAULT,
    Http1Config.DEFAULT,
    IOReactorConfig.DEFAULT,
    PoolingAsyncClientConnectionManagerBuilder.create()
    .setDefaultTlsConfig(TlsConfig.custom()
                         .setVersionPolicy(HttpVersionPolicy.FORCE_HTTP_1)
                         .build())
    .build());

client.start();

final HttpHost target = new HttpHost("httpbin.org");
final Future<AsyncClientEndpoint> leaseFuture = client.lease(target, null);
final AsyncClientEndpoint endpoint = leaseFuture.get(30, TimeUnit.SECONDS);
try {
    final String[] requestUris = new String[] {"/", "/ip", "/user-agent", "/headers"};

    final CountDownLatch latch = new CountDownLatch(requestUris.length);
    for (final String requestUri: requestUris) {
        final SimpleHttpRequest request = SimpleRequestBuilder.get()
            .setHttpHost(target)
            .setPath(requestUri)
            .build();

        System.out.println("Executing request " + request);
        endpoint.execute(
            SimpleRequestProducer.create(request),
            SimpleResponseConsumer.create(),
            new FutureCallback<SimpleHttpResponse>() {

                @Override
                public void completed(final SimpleHttpResponse response) {
                    latch.countDown();
                    System.out.println(request + "->" + new StatusLine(response));
                    System.out.println(response.getBody());
                }

                @Override
                public void failed(final Exception ex) {
                    latch.countDown();
                    System.out.println(request + "->" + ex);
                }

                @Override
                public void cancelled() {
                    latch.countDown();
                    System.out.println(request + " cancelled");
                }

            });
    }
    latch.await();
} finally {
    endpoint.releaseAndReuse();
}

System.out.println("Shutting down");
client.close(CloseMode.GRACEFUL);

参考

  1. https://hc.apache.org/httpclient-legacy/index.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/363564.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SSM SpringBoot vue 健康医疗预约系统

SSM SpringBoot vue 健康医疗预约系统 SSM 健康医疗预约系统 功能介绍 首页 图片轮播展示 出诊信息推荐 医院公告 科室信息 科室详情 出诊信息 医生详情 挂号预约 登录注册 留言反馈 个人中心 我的收藏 后台管理 登录 注册医生 个人中心 用户管理 科室信息管理 医生管理 出诊…

二、Java虚拟机的基本结构

Java虚拟机的架构1.内存结果概述2.类加载器子系统的作用3. 类加载器ClassLoader角色4.类的加载过程5.类加载器的分类1.引导类加载器(虚拟机自带的加载器)Bootstrap ClassLoader2.扩展类加载器(虚拟机自带的加载器) Extenssion ClassLoader3.应用程序类加载器(虚拟机自带的加载器…

CAN TP层函数介绍

如果想使用CAN TP层函数,首先需要在网络节点或测试节点配置页面的Componets组件一栏添加osek_tp.dll文件。路径为:C:\Program Files\Vector CANoe 15\Exec32 至于节点的CAPL程序内需不需要引用这个dll文件,无所谓,可写可不写。但是如果是其他dll,必须在CAPL程序中引用。为…

多服务器节点访问解决一人一单问题+redis设置锁方案

项目地址及项目具体介绍-码云仓库&#xff1a;https://gitee.com/flowers-bloom-is-the-sea/distributeNodeSolvePessimisticLockByRedis 测试1&#xff1a; 这里使用jmeter同时启动2各线程&#xff1a; 原来的数据库表的数据&#xff1a; goods的数据是&#xff1a; id …

金蝶云星空物料批量禁用反禁用程序

【需求描述】&#xff1a;需要通过批量禁用反禁用操作物料。 【操作方法】&#xff1a; 下载附件批量禁用程序。 首先双击安装&#xff0c;一直下一步。 双击打开 会提示需要配置账套信息 点击菜单栏配置 输入相关配置信息 填写完毕后 然后点击下载模板导入要下载的数据 选…

Linux进程学习【三】

✨个人主页&#xff1a; Yohifo &#x1f389;所属专栏&#xff1a; Linux学习之旅 &#x1f38a;每篇一句&#xff1a; 图片来源 &#x1f383;操作环境&#xff1a; CentOS 7.6 阿里云远程服务器 Perseverance is not a long race; it is many short races one after another…

Word控件Spire.Doc 【Table】教程(18):如何在 C# 中的 Word 中创建嵌套表格

Spire.Doc for .NET是一款专门对 Word 文档进行操作的 .NET 类库。在于帮助开发人员无需安装 Microsoft Word情况下&#xff0c;轻松快捷高效地创建、编辑、转换和打印 Microsoft Word 文档。拥有近10年专业开发经验Spire系列办公文档开发工具&#xff0c;专注于创建、编辑、转…

「JVM 编译优化」即时编译器

前端编译器&#xff08;javac&#xff09;将 Java 代码转为字节码&#xff08;抽象语法树&#xff09;&#xff0c;优化手段主要用于提升程序的编码效率&#xff1b; 后端编译器&#xff08;内置于 JVM 的 JIT/AOT Compiler&#xff0c;C1&#xff0c;C2&#xff09;将字节码转…

2022年休闲游戏市场总结

在预测 2023 年之前&#xff0c;我们先回顾一下 2022 年。从上一年发生的事件中往往能看到未来趋势的影子&#xff0c;所以 2022 年的总结至关重要。一、2022年总结回顾1、流行游戏类型回顾 2022 年&#xff0c;三种超休闲游戏表现最为突出&#xff1a;跑酷游戏&#xff1a;跑酷…

spring之声明式事务开发

文章目录一、声明式事务之全注解式开发1、新建springConfig类2、测试程序3、测试结果二、声明式事务之XML实现方式1、配置步骤2、测试程序3、运行结果附一、声明式事务之全注解式开发 基于之前的银行转账系统&#xff0c;将spring.xml配置文件嘎掉&#xff0c;变成全注解式开发…

【极海APM32替代笔记】低功耗模式下的RTC唤醒(非闹钟唤醒,而是采用RTC_WAKEUPTIMER)

【极海APM32替代笔记】低功耗模式下的RTC唤醒&#xff08;非闹钟唤醒&#xff0c;而是采用RTC_WAKEUPTIMER&#xff09; 【STM32笔记】低功耗模式配置及避坑汇总 前文&#xff1a; blog.csdn.net/weixin_53403301/article/details/128216064 【STM32笔记】HAL库低功耗模式配置…

Spring Boot整合RabbitMQ教程

1.首页我们了解一下消息中间件的应用场景异步处理场景说明&#xff1a;用户注册后&#xff0c;需要发注册邮件和注册短信,传统的做法有两种1.串行的方式;2.并行的方式 (1)串行方式:将注册信息写入数据库后,发送注册邮件,再发送注册短信,以上三个任务全部完成后才返回给客户端。…

js实现轮播图

实现的效果图 原理:一次性加载所有图片&#xff0c;使用定位将图片重合在一起&#xff0c;根据opacity&#xff0c;z-index 属性显示当前图片 一、基本的HTML布局 创建一个外部容器来存放图片&#xff0c;prev-next是添加的左右切换按钮&#xff0c;dot存放图片下方的小白点…

《爆肝整理》保姆级系列教程python接口自动化(二十一)--unittest简介(详解)

简介 前边的随笔主要介绍的requests模块的有关知识个内容&#xff0c;接下来看一下python的单元测试框架unittest。熟悉 或者了解java 的小伙伴应该都清楚常见的单元测试框架 Junit 和 TestNG&#xff0c;这个招聘的需求上也是经常见到的。python 里面也有单元 测试框架-unitt…

小熊电器:精品与创意,走上“顶流之路”的两把“宝剑”

回顾2022年&#xff0c;小家电市场降温趋势明显&#xff0c;业绩表现整体低迷&#xff0c;如主打高端路线的北鼎&#xff0c;去年8亿元的营收出现个位数下滑&#xff0c;归母净利润同比下降超56%&#xff1b;苏泊尔营收也出现微降&#xff0c;归母净利润预计同比增长不到10%。而…

教你如何搭建培训机构-招生管理系统,demo可分享

1、简介1.1、案例简介本文将介绍&#xff0c;如何搭建培训机构-招生管理。1.2、应用场景根据意向信息站的收录信息&#xff0c;可批量导入意向信息&#xff0c;在意向信息站转为意向学员&#xff0c;转为意向学员后可进行报名收费成为正式学员。2、设置方法2.1、表单搭建1&…

从零实现深度学习框架:Seq2Seq从理论到实战【实战篇】

来源&#xff1a;投稿 作者&#xff1a;175 编辑&#xff1a;学姐 往期内容&#xff1a; 从零实现深度学习框架1&#xff1a;RNN从理论到实战&#xff08;理论篇&#xff09; 从零实现深度学习框架2&#xff1a;RNN从理论到实战&#xff08;实战篇&#xff09; 从零实现深度…

JUC-day01

JUC-day01 什么是JUC线程的状态: wait sleep关键字:同步锁 原理(重点)Lock接口: ReentrantLock(可重入锁)—>AQS CAS线程之间的通讯 1 什么是JUC 1.1 JUC简介 在Java中&#xff0c;线程部分是一个重点&#xff0c;本篇文章说的JUC也是关于线程的。JUC就是java.util .con…

活动预告 | GAIDC 全球人工智能开发者先锋大会

大会主题——“向光而行的 AI 开发者” 2023 全球人工智能开发者先锋大会&#xff08;GAIDC&#xff09; 由世界人工智能大会组委会、上海市经济和信息化委员会、上海市人才工作领导小组办公室及中国&#xff08;上海&#xff09;自由贸易试验区临港新片区管理委员会指导&…

【Java集合类】HashMap(二)- 设计要点

本章将开始探讨JDK中的HashMap&#xff0c;包括HashMap如何避免和解决上一章所说的散列冲突问题&#xff0c;以及Java 8对HashMap的改进 避免散列冲突- 散列函数设计 String.hashcode() Object.hashCode()方法用于返回当前对象的散列值。Object类中也约定了&#xff0c;重写…