HttpComponents: 领域对象的设计
1. HTTP协议
1.1 HTTP请求
HTTP请求由请求头、请求体两部分组成,请求头又分为请求行(request line)和普通的请求头组成。通过浏览器的开发者工具,我们能查看请求和响应的详情。 下面是一个HTTP请求发送的完整内容。
POST https://track.abc.com/v4/track HTTP/1.1
Host: track.abc.com
Connection: keep-alive
Content-Length: 2048
Pragma: no-cache
Cache-Control: no-cache
sec-ch-ua: "Google Chrome";v="87", " Not;A Brand";v="99", "Chromium";v="87"
Accept: application/json, text/javascript, */*;
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
Origin: https://class.abc.com
Sec-Fetch-Site: same-site
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://class.abc.com/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: HJ_UID=1fafb8b2-2a34-9cbe-e6ba-b8b4aabab4a1; _SREF_45=d=2020&t=1609310840140
按照上面的理论,我们可以将这一个完整的请求拆分为3部分,请求行、请求头、请求体。
1. 请求行
POST https://track.abc.com/v4/track HTTP/1.1
POST
用于指定请求的方法,此外还可以有OPTOINS GET HEAD PUT DELETE TRACE CONNECT
等,更多详细解释可以参见RFC 2616。后面跟的https://track.abc.com/v4/track
是我们要访问的资源URI。最后的HTTP/1.1
指定了HTTP协议的版本,HTTP/1.1
是目最常见的版本。
2. 请求头
Host: track.abc.com
Connection: keep-alive
Content-Length: 2048
Pragma: no-cache
Cache-Control: no-cache
Accept: application/json, text/javascript, */*;
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
Referer: https://class.abc.com/
Accept-Encoding: gzip, deflate, br
Cookie: HJ_UID=1fafb8b2-2a34-9cbe-e6ba-b8b4aabab4a1; _SREF_45=
Header | 说明 |
---|---|
Host | 指定要访问的域名。请求行的域名会在客户端访问时转换为具体的IP。 Nginx是通过请求头的Host 来将请求转发到不同的域名配置的。 |
Connection | 用于指定连接保持的策略,这里的keep-alive 是期望服务器保持连接,在后续的请求中直接复用当前连接。 |
Pragma | 设置代理服务器(varnish)是否允许缓存,设置为no-cache 时代理即使发现有缓存也会回源上层服务器。 |
Cache-Control | 类是Pragma,不同的是这个请求体是HTTP 1.0时代的规范,请这个头同时支持做为响应头,但Pragma不能。 |
Accept | 指定支持的MIME-TYPE |
Content-Type | 指定请求内容类型以及编码 |
Referer | 上一页地址 |
Accept-Encoding | 支持的压缩方式 |
Cookie | 符合当前请求的Cookie值 |
HTTP请求是无状态的,Java服务端的Session都是通过Cookie保存会话标识来实现的。 Chrome新版本加了Cookie跨域的逻辑,SameSite设置会影响Cookie上报,对应逻辑查看SameSite对应的笔记。
3. 请求体
d=2020&t=1609310840140
请求体的格式可以通过Content-Type
指定,日常我们常用的有两种格式:
- Form表单提交,上面我们给定的就是Form表单提交的数据格式,通过
&
符合切割字段,通过=
连接字段名和字段值。 - JSON请求体,一般我们在SpringBoot后端通过@ResponseBody接收
1.2 HTTP响应
类似于HTTP请求,HTTP响应同样由响应头、响应内容两部分组成。 响应头有分为两类: 状态行、 响应头。 下面是一个HTTP响应的完整内容:
HTTP/1.1 200 OK
Date: Wed, 30 Dec 2020 06:47:20 GMT
Content-Length: 0
Connection: keep-alive
Server: nginx/1.14.0
Access-Control-Allow-Origin: https://class.abc.com
Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE
Access-Control-Max-Age: 86400
Access-Control-Allow-Headers: x-requested-with,Authorization,Cookie
Access-Control-Allow-Credentials: true
Set-Cookie: HJ_SSID_45=hsrein-fe2d-455c-a765-ce1b76647d4c; Domain=.abc.com; Expires=Wed, 30-Dec-2020 07:17:20 GMT; Path=/
Set-Cookie: _SREF_45=""; Domain=.abc.com; Expires=Thu, 01-Jul-2021 06:47:20 GMT; Path=/
Set-Cookie: HJ_CSST_45=0; Domain=.abc.com; Expires=Wed, 30-Dec-2020 07:17:20 GMT; Path=/
X-Via: 1.1 PS-000-01AdS239:3 (Cdn Cache Server V2.0)
X-Ws-Request-Id: 5fec2278_PS-000-01yOO242_18720-46076{"hj_vt": 1
}
1. 状态行
HTTP/1.1 200 OK
状态行有3部分组成,HTTP/1.1
标识HTTP协议的版本号,200
是我们的HTTP响应的状态码,OK
是HTTP响应的描述。
目前的状态码分为5类:
状态码 | 描述 |
---|---|
1xx | 请求已经接收,后台内部处理中 |
2xx | 请求成功 |
3xx | 重定向,需要客户端(浏览器)发起后续操作 |
4xx | 客户端错误 |
5xx | 服务端错误 |
2. 响应头
Date: Wed, 30 Dec 2020 06:47:20 GMT
Connection: keep-alive
Server: nginx/1.14.0
Access-Control-Allow-Origin: https://class.aaa.com
Set-Cookie: HJ_SSID_45=hsrein-fe2d-455c-a765-ce1b76647d4c; Domain=.bbb.com; Expires=Wed, 30-Dec-2020 07:17:20 GMT; Path=/
X-Via: 1.1 PS-000-01AdS239:3 (Cdn Cache Server V2.0)
X-Ws-Request-Id: 5fec2278_PS-000-01yOO242_18720-46076
Header | 说明 |
---|---|
Date | 响应内容生成的时间 |
Connection | 连接复用策略 |
Access-Control-Allow-Origin | 允许跨域,https://class.aaa.com 页面发起到当前接口跨域请求 |
Set-Cookie | 向客户端写入Cookie |
2. 领域对象设计
设计良好的系统有清晰划分和边界,层层递进,领域对象设计很考验架构师的全局观。随意的继承、组合,很快就会变的不可维护,导致项目失败。
所谓的架构就是定义划分和边界,让系统的增长不受限于当初的定义的能力,具体的技术只是帮助实现这个定义的手段。
2.1 HttpMessage
HTTP请求和HTTP响应都继承了HttpMessage
,HttpMessage
提供HTTP头各种操作(读取、写入、遍历等)。
以下的代码是对HttpMessage
的基本操作:
HttpMessage ht = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
ht.addHeader("Set-Cookie", "c1=a; path=/; domain=localhost");
ht.addHeader("Set-Cookie", "c2=b; path=\"/\", c3=c; domain=\"localhost\"");
Header h1 = ht.getFirstHeader("Set-Cookie");
System.out.println(h1);
Header h2 = ht.getLastHeader("Set-Cookie");
System.out.println(h2);
Header[] hs = ht.getHeaders("Set-Cookie");
System.out.println(hs.length);
遍历所有HTTP头:
HeaderIterator it = ht.headerIterator("Set-Cookie");
while (it.hasNext()) {System.out.println(it.next());
}
通过BasicHeaderElementIterator
解析HTTP头:
HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
response.addHeader("Set-Cookie", "c1=a; path=/; domain=localhost");
response.addHeader("Set-Cookie", "c2=b; path=\"/\", c3=c; domain=\"localhost\"");HeaderElementIterator it = new BasicHeaderElementIterator(response.headerIterator("Set-Cookie"));while (it.hasNext()) {HeaderElement elem = it.nextElement();System.out.println(elem.getName() + " = " + elem.getValue());NameValuePair[] params = elem.getParameters();for (int i = 0; i < params.length; i++) {System.out.println(" " + params[i]);}
}
2.2 HTTP请求
HttpCore使用HttpRequest
表示HTTP请求,我们可以通过下面这段代码创建一个最简单的HTTP请求:
HttpRequest request = new BasicHttpRequest("GET", "/index.html", HttpVersion.HTTP_1_1);
System.out.println(request.getRequestLine().getMethod()); // 输出 GET
System.out.println(request.getRequestLine().getUri()); // 输出 /index.html
System.out.println(request.getProtocolVersion()); // 输出 HTTP/1.1
System.out.println(request.getRequestLine().toString()); // 输出 GET /index.html HTTP/1.1
1. HttpRequest
HttpCore提供了大量实现类,下面的图片是httpcore:4.4.13
版本下的类继承结构
HttpMessage
提供了HTTP头和HTTP协议版本号相关的操作。HttpRequest
在HttpMessage
的基础上额外提供了请求行。AbstractExecutionAwareRequest
实现HttpMessage
、HttpRequest
,额外实现HttpExecutionAware
查看是否取消、接收Cancellable对象取消请求。HttpUriRequest
继承自HttpRequest
,额外提供了获取HTTP方法、URI,运行取消执行(abort方法),以及查询是否已经取消(isAborted方法)HttpEntityEnclosingRequest
继承自HttpRequest
,额外提供携带请求体的能力(setEntity(HttpEntity entity)
)BasicHttpRequest
提供了HttpRequest
最基本的实现,对于只需要请求行、HTTP头的请求,可以直接使用。
2. HttpGet、HttpPost、HttpPut、HttpDelete等
HttpRequest
的4个主要实现类中AbstractExecutionAwareRequest
、HttpUriRequest
共同做为HttpRequestBase
的基类,提供不包含请求体的HTTP请求实现,我们常用的有HttpGet
、HttpDelete
、HttpOptions
、HttpHead
、HttpTrace
。
HttpRequestBase
组合HttpEntityEnclosingRequest
提供实现类HttpEntityEnclosingRequestBase
,它是所有包含请求体的HTTP请求实现,包括HttpPut
、HttpPost
、HttpDelete
、HttpPatch
。
2.3 HTTP响应
HttpCore使用HttpResponse
表示HTTP响应,同样继承自HttpMessage
,额外提供了状态行、响应体(HttpEntity)。通过下面的代码可以创建一个最简单的HTTP响应:
HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
System.out.println(response.getProtocolVersion()); // 输出 HTTP/1.1
System.out.println(response.getStatusLine().getStatusCode()); // 输出 200
System.out.println(response.getStatusLine().getReasonPhrase()); // 输出 OK
System.out.println(response.getStatusLine().toString()); // 输出 HTTP/1.1 200 OK
1. HttpResponse
HttpResponse
提供了获取状态行、状态码、状态描述,以及响应内容的方法。
2. BasicHttpResponse
HttpResponse
只提供了两个实现类,常用的BasicHttpResponse
封装普通HTTP响应,HttpResponseProxy
供代理服务器使用。
2.4 HttpEntity
HttpCore抽象了HttpEntity表示请求体/响应体,回想一下,前面我们学习的HttpRequest
有部分是实现了HttpEntityEnclosingRequest
的可以携带HttpEntity向服务器提交数据。 HttpResponse
都包含一个setEntity
和getEntity
方法,当然RFC文档定义,部分响应如302跳转不应该包含HttpEntity
。
HttpCore官方将HttpEntity分为3类:
类型 | 说明 |
---|---|
streamed | 请求体内容来自于InputStream或者程序生成,因为流无法重复读取,导致HttpEntity内容只能被消费一次 |
self-contained | 请求体内容存储在内存中,可以反复读取 |
wrapping | 装饰器模式,请求体内容来自其他HttpEntity,额外包装处理后对外提供 |
1. HttpEntity定义
HttpEntity的核心作用就是表示请求体,请求体会被用在输入和输出,基本上这也就确定了HttpEntity的接口定义。
- 我们要从请求体读取数据,于是定义了
InputStream HttpEntity#getContent()
- 我们要将请求体发送到服务端(写到输出流),于是定义了
void HttpEntity#writeTo(OutputStream)
- 服务端需要知道我们发送的是图片还是文本,于是定义了
Header HttpEntity#getContentType()
- 服务端需要知道我们发送的文本用什么编码,于是定义了
Header HttpEntity#getContentEncoding()
创建HttpEntity要提供ContentType对象,用于定于HttpEntity
包含的内容及编码,后面的HTTP协议拦截器会协助我们处理HTTP头和HttpEntity
的关系。
- 发送
HttpEntity
的时候HTTP协议拦截器会自动从HttpEntity
读取ContentType,并在HttpRequest
下添加HTTP头Content-Type
。 - 接收
HttpResponse
初始化HttpEntity
时,通过HTTP协议拦截器自动从Content-Type
头读取并设置HttpEntity
的ContentType
。
HttpEntity
有大量的实现类,我们来看一个最简单的HttpEntity
初始化:
StringEntity myEntity = new StringEntity("important message", Consts.UTF_8); // 默认ContentType是text/plainSystem.out.println(myEntity.getContentType()); // 输出 Content-Type: text/plain; charset=UTF-8
System.out.println(myEntity.getContentLength()); // 将字符串转为字节数组后的长度
System.out.println(EntityUtils.toString(myEntity)); // 构造函数传入的字符串
System.out.println(EntityUtils.toByteArray(myEntity).length); // 将字符串转为字节数组后的长度
HttpEntity
有4组实现类:
-
RequestEntityProy
,用于实现代理服务器 -
StreamingHttpEntity
,提供Body对象,将Body.writeTo方法写OutputStream,适用于生成InputStream开销大的场景 -
HttpEntityWrapper
,装饰器模式,主要用于实现压缩、解压
-
AbstractHttpEntity
,最实用的实现,它是我们常用的StringEntity、InputStreamEntity、BasicHttpEntity、FileEntity、ByteArrayEntity等的父类
1. BasicHttpEntity
BasicHttpEntity
提供无参构造函数,默认表示空的HttpEntity。 通过BasicHttpEntity#setContent
传入InputStream,BaiscHttpEntity#setContentLength
设置HttpEntity长度,能构造出有实际能容的HttpEntity
。
我们看一个简单的示例:
BasicHttpEntity e = new BasicHttpEntity();
e.setContent(new ByteArrayInputStream("helloworld".getBytes()));
e.setContentLength(-1);
2. ByteArrayEntity
ByteArrayEntity
属于self-contained
的HttpEntity
,只需要提供byte数组即可构建。
我们看一个简单的示例:
ByteArrayEntity myEntity = new ByteArrayEntity(new byte[] {1,2,3}, ContentType.APPLICATION_OCTET_STREAM);
3. StringEntity
StringEntity
也是self-contained
的HttpEntity
, 有3种构造方式:
HttpEntity myEntity1 = new StringEntity(sb.toString()); // 默认MIME-TYPE为text/plain,默认编码 ISO-8859-1
HttpEntity myEntity2 = new StringEntity(sb.toString(), Consts.UTF_8); // 默认MIME-TYPE为text/plain,自己指定编码
HttpEntity myEntity3 = new StringEntity(sb.toString(), ContentType.create("text/plain", Consts.UTF_8)); // 自己字段MIME-TYPE和编码
4. InputStreamEntity
通过InputStream
构建,允许传入要读取的字节数(-1表示不限)。比较使用的场景是前端提交一个文件后我们拿到一个输入流,通过这个流我们再上传到文件到分布式文件系统。
我们看一个简单的示例:
InputStream instream = getSomeInputStream();
InputStreamEntity myEntity = new InputStreamEntity(instream, 16);
5. FileEntity
通过提供一个File
对象构建,是self-contained
类型的HttpEntity
。
我们看一个简单的示例:
HttpEntity entity = new FileEntity(staticFile,ContentType.create("application/java-archive"));
6. BufferedHttpEntity
BufferedHttpEntity
继承自HttpEntityWrapper
,使用装饰器模式,将其他类型的HttpEntity
转为self-contained
类型,内部实现是将其他类型的HttpEntity
内容读取并缓存在内存中。
我们看一个简单的示例:
myNonRepeatableEntity.setContent(someInputStream);
BufferedHttpEntity myBufferedEntity = new BufferedHttpEntity(myNonRepeatableEntity);
2. EntityUtils
通过InputStream HttpEntity#getContent()
太过底层,使用麻烦。 HttpCore提供了EntityUtils
帮助我们消费HttpEntity
。 EntityUtils
主要提供3类方法:
consume
、consumerQuietly
用于关闭HttpEntity
的输入流,以便是否资源,在我们不需要HttpEntity
的内容的时候使用。toByteArray
将HttpEntity
内容转换为字节数字,适用于传输非文本内容的场景,比如图片。toString
系列,用于将HttpEntity
的内容转换为字符串,可以使用HttpEntity
字段的编码信息,或者自己指定编码
2.5 HTTP协议处理器
通常复杂而多变的逻辑都会采用责任链模式或者拦截器模式分而治之,HttpCore中的HTTP协议就是通过拦截器链完成的。
HttpCore中将拦截器划分为两类:
HttpRequestInterceptor
,请求拦截器HttpResponseInterceptor
,响应拦截器
HttpCore定义了大量的拦截器来出来HTTP协议的细节,下面的表格我们列出一些常见的拦截器:
拦截器 | 说明 |
---|---|
RequestContent | 计算请求体长度,添加Content-Length、Transfer-Content头,添加HTTP版本号 |
RequestConnControl | 负责在请求中添加Connection头 |
RequestDate | 负责在请求添加Date头 |
RequestExpectContinue | 负责添加请求的Expect头 |
RequestTargetHost | 负责添加请求的Host头 |
RequestUserAgent | 负责添加请求的User-Agent头 |
ResponseContent | 计算响应体长度,添加Content-Length、Transfer-Content头,添加HTTP版本号 |
ResponseConnControl | 负责在响应中添加Connection头 |
ResponseDate | 负责在响应添加Date头 |
ResponseServer | 负责添加响应的Server头 |
HTTP拦截器需要配合HttpProcessorBudiler
使用,这个Builder会创建一个ImmutableHttpProcessor
,ImmutableHttpProcessor
会在process
方法内循环调用其他HttpProcessor
。
HttpProcessor httpproc = HttpProcessorBuilder.create().add(new RequestContent()).add(new RequestTargetHost()).add(new RequestConnControl()).add(new RequestUserAgent("MyAgent-HTTP/1.1")).add(new RequestExpectContinue(true)).build();HttpCoreContext context = HttpCoreContext.create();
context.setTargetHost(HttpHost.create("www.a.com"));HttpRequest request = new BasicHttpRequest("GET", "/index.html");
request.addHeader("Host","www.a.com");httpproc.process(request, context);HeaderIterator it = request.headerIterator();
while (it.hasNext()) {Header h = it.nextHeader();System.out.println(h.getName() + ":" + h.getValue());
}System.out.println(request);
服务端处理逻辑
HttpResponse = <...>
httpproc.process(response, context);
2.6 HttpCoreContext
HTTP请求本身是无状态的,很多场景下我们希望保留状态,比如Java服务端会话需要的JSESSIONID。 HttpCoreContext
的目的就是为了解决这个问题。
下面是一个最简单的使用示例:
HttpProcessor httpproc = HttpProcessorBuilder.create().add(new HttpRequestInterceptor() {public void process(HttpRequest request,HttpContext context) throws HttpException, IOException {String id = (String) context.getAttribute("session-id");if (id != null) {request.addHeader("Session-ID", id);}}}).build();HttpCoreContext context = HttpCoreContext.create();
HttpRequest request = new BasicHttpRequest("GET", "/");
httpproc.process(request, context);
3. 总结
4. 参考资料
- HTTP协议文档 RFC2616 https://tools.ietf.org/html/rfc2616
- HttpComponents文档 https://hc.apache.org/httpcomponents-core-ga/tutorial/html/fundamentals.html
相关文章:
HttpComponents: 领域对象的设计
1. HTTP协议 1.1 HTTP请求 HTTP请求由请求头、请求体两部分组成,请求头又分为请求行(request line)和普通的请求头组成。通过浏览器的开发者工具,我们能查看请求和响应的详情。 下面是一个HTTP请求发送的完整内容。 POST https://track.abc.com/v4/tr…...
使用wire重构商品微服务
一.wire简介 Wire 是一个轻巧的Golang依赖注入工具。它由Go Cloud团队开发,通过自动生成代码的方式在编译期完成依赖注入。 依赖注入是保持软件 “低耦合、易维护” 的重要设计准则之一。 此准则被广泛应用在各种开发平台之中,有很多与之相关的优秀工…...
大三上实训内容
项目一:爬取天气预报数据 【内容】 在中国天气网(http://www.weather.com.cn)中输入城市的名称,例如输入信阳,进入http://www.weather.com.cn/weather1d/101180601.shtml#input 的网页显示信阳的天气预报,其中101180601是信阳的…...
IOT安全学习路标
1. 物联网基础知识 首先,你需要建立坚实的物联网基础知识,包括IoT的架构和组件,传感器和设备的连接和通信技术,云端和边缘计算等。 2. 通信和网络安全 学习关于物联网通信和网络安全的基础知识,包括加密和认证技术、…...
java中线程的状态是如何转换的?
在 Java 中,线程有几种状态,主要包括 NEW(新建)、RUNNABLE(可运行)、BLOCKED(阻塞)、WAITING(等待)、TIMED_WAITING(计时等待)、和 TE…...
处理合并目录下的Excel文件数据并指定列去重
处理合并目录下的Excel文件数据并指定列去重 需求:读取指定目录下的Excel文件并给数据做合并与去重处理 Python代码实现 import os import pandas as pd import warnings import time from tqdm import tqdm #进度条展示def read_excel(path):dfs []for file in…...
Numpy数组的去重 np.unique()(第15讲)
Numpy数组的去重 np.unique()(第15讲) 🍹博主 侯小啾 感谢您的支持与信赖。☀️ 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ�…...
ROS-log功能区别
ROS使用rosout包来记录各个节点的log信息,通常这些log信息是一些可以读懂的字符串信息,这些信息一般用来记录节点的运行状态。 ROS有五种不同类型的log信息,分别为:logdebug、loginfo、logwarn、logerr、logfatal。 等级由低到高&…...
学习git后,真正在项目中如何使用?
文章目录 前言下载和安装Git克隆远程仓库PyCharm链接本地Git创建分支修改项目工程并提交到本地仓库推送到远程仓库小结 前言 网上学习git的教程,甚至还有很多可视化很好的git教程,入门git也不是什么难事。但我发现,当我真的要从网上克隆一个…...
Qt国际化翻译Linguist使用
QT的国际化是非常方便的,简单的说就是QT有自带的翻译工具把我们源代码中的字符串翻译成任何语言文件,再把这个语言文件加载到项目中就可以显示不同的语言。下面直接上手: 步骤一:打开pro文件,添加:TRANSLA…...
ShardingSphere数据分片之分表操作
1、概述 Apache ShardingSphere 是一款分布式的数据库生态系统, 可以将任意数据库转换为分布式数据库,并通过数据分片、弹性伸缩、加密等能力对原有数据库进行增强。 Apache ShardingSphere 设计哲学为 Database Plus,旨在构建异构数据库上…...
基于ssm鲸落文化线上体验馆论文
摘 要 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本鲸落文化线上体验馆就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信…...
LeetCode Hot100 131.分割回文串
题目: 给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。 回文串 是正着读和反着读都一样的字符串。 方法:灵神-子集型回溯 假设每对相邻字符之间有个逗号,那么就看…...
SAP UI5 walkthrough step9 Component Configuration
在之前的章节中,我们已经介绍完了MVC的架构和实现,现在我们来讲一下,SAPUI5的结构 这一步,我们将所有的UI资产从index.html里面独立封装在一个组件里面 这样组件就变得独立,可复用了。这样,无所什么时候我…...
【数据结构和算法】--- 栈
目录 栈的概念及结构栈的实现初始化栈入栈出栈其他一些栈函数 小结栈相关的题目 栈的概念及结构 栈是一种特殊的线性表。相比于链表和顺序表,栈只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的…...
CentOS7.0 下rpm安装MySQL5.5.60
下载 下载路径: MySQL :: Download MySQL Community Server -->looking for the latest GA version-->5.5.60 此压缩包中有多个rpm包 有四个不是必须的,只需安装这三个 MySQL-server-5.5.60-1.el6.x86_64 MySQL-devel-5.5.60-1.el6.x86_64 MySQL-client-5.5.60-1.el6.x8…...
智慧能源:数字孪生压缩空气储能管控平台
压缩空气储能在解决可再生能源不稳定性和提供可靠能源供应方面具有重要的优势。压缩空气储能,是指在电网负荷低谷期将电能用于压缩空气,在电网负荷高峰期释放压缩空气推动汽轮机发电的储能方式。通过提高能量转换效率、增加储能密度、快速启动和调节能力…...
【链表OJ—反转链表】
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 1、反转链表题目: 2、方法讲解: 解法一: 解法二: 总结 前言 世上有两种耀眼的光芒,一种是正在升起的太…...
TCP一对一聊天
客户端 import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedReader; import java.io.IOException; import java.io…...
基于Java的招聘系统的设计与实现
末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SSM 前端:Vue 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软件:IDEA / Eclipse 是否Maven项目:是 目录…...
spring boot整合mybatis进行部门管理管理的增删改查
部门列表查询: 功能实现: 需求:查询数据库表中的所有部门数据,展示在页面上。 准备工作: 准备数据库表dept(部门表),实体类Dept。在项目中引入mybatis的起步依赖,mysql的…...
微软 Power Platform 零基础 Power Pages 网页搭建高阶实际案例实践(四)
微软 Power Platform 零基础 Power Pages 网页搭建教程之高阶案例实践学习(四) Power Pages 实际案例学习进阶 微软 Power Platform 零基础 Power Pages 网页搭建教程之高阶案例实践学习(四)1、新增视图,添加List页面2…...
如何在任何STM32上面安装micro_ros
就我知道的:micro-ros只能在特定的昂贵的开发板上面运行,但是偶然发现了这个文章,似乎提供了一个全新的方式来在ros2和单片机之间通讯,如果能够这样肯定也能够提高效率,但即使不行,使用串口库也应该比较简单…...
肖sir__ 项目讲解__项目数据
项目时间: 情况一:项目时间开始到上线的时间,这个时间一般比较长(一年,二年,三年) 情况二:项目的版本的时间或则是周期(1个月,2个月,3个月&…...
微服务实战系列之J2Cache
前言 经过近几天陆续发布Cache系列博文,博主已对业界主流的缓存工具进行了基本介绍,当然也提到了一些基本技巧。相信各位盆友看见这么多Cache工具后,在选型上一定存在某些偏爱: A同学说:不管业务千变万化,…...
12.ROS导航模块:gmapping、AMCL、map_server、move_base案例
目录 1 导航概述 2 导航简介 2.1 导航模块简介 1.全局地图 2.自身定位 3.路径规划 4.运动控制 5.环境感知 2.2 导航坐标系odom、map 1.简介 2.特点 3.坐标系变换 2.3 导航条件说明 1.硬件 2.软件 3 导航实现 3.1 创建本篇博客的功能包 3.2 建图--gmapping 3.…...
C++中string类的使用
一.string类 1.1为什么学习string类? C 语言中,字符串是以 \0 结尾的一些字符的集合,为了操作方便, C 标准库中提供了一些 str 系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP 的思想&#x…...
LeeCode每日刷题12.8
搜索插入位置 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 示例 1: 输入: nums [1,3,5,6], target 5 输出: …...
硕士毕业论文格式修改要点_word
目录 0、最开始要做的事情1、更改样式(先善器)2、多级标题(解决自动更新问题必要的基础设置)2、插入图片(1)设置一个图片样式——“无间隔”(2)插入题注(3)修…...
远红外温和护理,一贴缓解痛风不适
在冬天,很多人都会因为痛风等原因引起的关节炎症而感到不适,因为关节疼痛、肢体麻木等问题会对生活质量造成很大的影响。市场上缓解关节酸痛的护理品很多,常见的应该还是关节贴,我现在用的就是何浩明关节痛风贴。 相比于同类产品&…...
优化 SQL 日志记录的方法
为什么 SQL 日志记录是必不可少的 SQL 日志记录在数据库安全和审计中起着至关重要的作用,它涉及跟踪在数据库上执行的所有 SQL 语句,从而实现审计、故障排除和取证分析。SQL 日志记录可以提供有关数据库如何访问和使用的宝贵见解,使其成为确…...
Java设计模式-工厂模式
目录 一、简单工厂模式 (一)需求 (二)使用传统的方法来完成 (三)传统方法的优缺点 (四)基本介绍 (五)使用简单工厂模式 二、工厂方法模式 ࿰…...
每天五分钟计算机视觉:稠密连接网络(DenseNet)
本文重点 在前面的课程中我们学习了残差网络ResNet,而DenseNet可以看成是ResNet的后续,我们看一下图就可以看出二者的主要区别了。 特点 DenseNet是一种卷积神经网络,它的特点是每一层都直接连接到所有后续层。这意味着,每一层都接收来自前一层的输出,并将其作为输入传递…...
mysql支持的整数类型、各类型整数能够表示的数值范围
MySQL :: MySQL 8.2 Reference Manual :: 11.1.2 Integer Types (Exact Value) - INTEGER, INT, SMALLINT, TINYINT, MEDIUMINT, BIGINT mysql支持的整数有:TINYINT、SMALLINT、MEDIUMINT、INT(INT和INTEGER是同义词)、BIGINT,各…...
我不是DBA之慢SQL诊断方式
最近经常遇到技术开发跑来问我慢SQL优化相关工作,所以干脆出几篇SQL相关优化技术月报,我这里就以公司mysql一致的5.7版本来说明下。 在企业中慢SQL问题进场会遇到,尤其像我们这种ERP行业。 成熟的公司企业都会有晚上的慢SQL监控和预警机制。…...
JavaScript基础知识整理(最全知识点, 精简版,0基础版)
文章目录 一、输入和输出内容 1.1 输出 1.1.1 在浏览器的控制台输出打印 1.1.2 直接在浏览器的页面上输出内容 1.1.3 页面弹出警告对话框 1.2 输入 二、变量 2.1 变量是什么 2.2 变量的声明和赋值 2.3 变量的命名规范和规范 三、变量扩展(数组) 3.1 数组…...
人工智能和网络安全:坏与好
人工智能似乎可以并且已经被用来帮助网络犯罪和网络攻击的各个方面。 人工智能可以用来令人信服地模仿真人的声音。人工智能工具可以帮助诈骗者制作更好、语法正确的网络钓鱼消息(而糟糕的语法往往会暴露出漏洞),并将其翻译成多种语言&…...
基于SSH的java记账管理系统
基于SSH的java记账管理系统 一、系统介绍二、功能展示四、其他系统实现五、获取源码 一、系统介绍 项目类型:Java EE项目 项目名称:基于SSH的记账管理系统 项目架构:B/S架构 开发语言:Java语言 前端技术:HTML、CS…...
github可访问但无法clone问题
github可访问但无法clone问题 重置 http.proxy 重置 http.proxy git config --global http.proxy http://127.0.0.1:1080 git config --global https.proxy https://127.0.0.1:1080 git config --global --unset http.proxy git config --global --unset https.proxy...
WebGL笔记:图形缩放的原理和实现
缩放 1 )原理 缩放可以理解为对向量长度的改变,或者对向量坐标分量的同步缩放 如下图,比如让向量OA 收缩到点B的位置,也就是从OA变成OB,缩放了一半 2 )公式 已知 点A的位置是(ax,ay,az)点A基于原点內缩了…...
前端学习--React(5)
一、useReducer 管理相对复杂的状态数据 定义一个reducer函数,根据action值的不同返回不同的状态 在组件中调用useReducer并传入reducer函数和状态的初始值 事件发生时,通过dispatch函数分派一个对象,即通知reducer具体返回哪个状态对应的操…...
【数据结构】平衡树引入
数据结构-平衡树 前置知识 二叉树二叉树的中序遍历 问题 维护一个数据结构,支持插入元素、删除元素、查询元素的排名、查询排名对应的元素、查询元素的前驱、查询元素的后继等。 BST(二叉搜索树) 作为一个基本无效(很容易卡掉…...
机器视觉相机镜头光源选型
镜头选型工具 - HiTools - 海康威视 Hikvisionhttps://www.hikvision.com/cn/support/tools/hitools/cl8a9de13648c56d7f/ 海康机器人-机器视觉产品页杭州海康机器人股份有限公司海康机器人HIKROBOT是面向全球的机器视觉和移动机器人产品及解决方案提供商,业务聚焦于…...
Appium:iOS测试比Android测试更难?
iOS测试与Android测试: Appium 是一个开源的自动化测试框架,用于iOS、Android和Web应用程序。它允许开发者使用自己的语言来编写测试脚本,并且可以运行在多种平台上。 就Appium本身而言,它为iOS和Android提供了相似的测试能力和…...
使用c#罗列、监视、控制进程
个人简介:本人多年从事研发和测试领域工作,有一定的经验; 口号:懒人推动科技进步,学习编程啊脚本啊目的就是要将人从做相同的工作脱离出来,手懒可以但是脑子不能懒,让重复的事情自动完成,能动一下就完成任务就不能动两下,懒到极致才是目标! 方向:本人不怎么将理论的…...
Vue:绘制图例
本文记录使用Vue框架绘制图例的代码片段。 可以嵌入到cesium视图中,也可以直接绘制到自己的原生系统中。 一、绘制图例Vue组件 <div v-for="(color, index) in colors" :key="index" class="legend-item"><div class="color-…...
Web(8)SQL注入
Web网站(对外门户) 原理:not>and>or(优先级) 一.低级注入 order by的作用是对字段进行排序,如order by 5,根据第五个字段 进行排序,如果一共有4个字段,输入order by 5系统就会报错不 …...
kafka入门(三):kafka多线程消费
kafka消费积压 如果生产者发送消息的速度过快,或者是消费者处理消息的速度太慢,那么就会有越来越多的消息无法及时消费,也就是消费积压。 消费积压时, (1) 可以增加Topic的分区数,并且增加消费组的消费者数量&#…...
android通过广播打印RAM信息
通过广播打印ram相关log 参数说明: 广播:com.android.settings.action.RAM_INFO int型参数index:0 - 3h, 1 - 6h, 2 - 12h, 3 - 24h 代表过去时间app使用ram情况(平均/最大占用) Index: frameworks/base/services/cor…...
C++新经典模板与泛型编程:策略类模板
策略类模板 在前面的博文中,策略类SumPolicy和MinPolicy都是普通的类,其中包含的是一个静态成员函数模板algorithm(),该函数模板包含两个类型模板参数。其实,也可以把SumPolicy和MinPolicy类写成类模板—直接把algorithm()中的两…...