欢迎访问我的GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos

本篇概览

  • 本文是《java与es8实战》系列的第六篇,经过前面的实战,咱们初步掌握了一些Java对ES的基本操作,通过发送请求对象(例如CreateIndexResponse)到ES服务端,达到操作ES的目的,但是细心的您可能发现了:请求对象可能很复杂,例如多层对象嵌套,那么用代码来创建这些请求对象也必然不会容易
  • 今天的文章,咱们先来体验用代码创建请求对象的不便之处,再尝试ES官方给我们提供的解决之道:用JSON创建请求对象
  • 接下来,咱们从一个假设的任务开始

任务安排

  • 现在咱们要创建一个索引,此索引记录的是商品信息
  1. 有一个副本(属于setting部分)
  2. 共三个分片(属于setting部分)
  3. 共三个字段:商品名称name(keyword),商品描述description(text),价格price(integer)(属于mapping部分)
  4. name字段值长为256,超出此长度的字段将不会被索引,但是会存储
  • 接下来,咱们在kibana上用JSON创建索引,再写代码创建相同索引,然后对比两种方式的复杂程度

kibana上创建索引

  • 如果在kibana上用json来创建,请求内容如下,索引名是product001
PUT product001
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1
},
"mappings": {
"properties": {
"name": {
"type": "keyword",
"ignore_above": 256
},
"description": {
"type": "text"
},
"price": {
"type": "integer"
}
}
}
}
  • 效果如下,符合预期

  • 通过eshead观察,也是符合预期

  • 可见基于JSON的操作简单明了,接下来看看创建相通索引的代码是什么样子

基于代码创建

  • 关于如何连接ES的代码并非本篇重点,而且前面的文章已有详细说明,就不多赘述了
  • 首先创建一个API,可以接受外部传来的Setting和Mapping设定,然后用这些设定来创建索引
    @Autowired
private ElasticsearchClient elasticsearchClient; @Override
public void create(String name,
Function<IndexSettings.Builder, ObjectBuilder<IndexSettings>> settingFn,
Function<TypeMapping.Builder, ObjectBuilder<TypeMapping>> mappingFn) throws IOException {
elasticsearchClient
.indices()
.create(c -> c
.index(name)
.settings(settingFn)
.mappings(mappingFn)
);
}
  • 然后就是如何准备Setting和Mapping参数,再调用create方法完成创建,为了让代码顺利执行,我将调用create方法的代码写在单元测试类中,这样后面只需要执行单元测试即可调用create方法
@SpringBootTest
class EsServiceImplTest { @Autowired
EsService esService; @Test
void create() throws Exception {
// 索引名
String indexName = "product002"; // 构建setting时,builder用到的lambda
Function<IndexSettings.Builder, ObjectBuilder<IndexSettings>> settingFn = sBuilder -> sBuilder
.index(iBuilder -> iBuilder
// 三个分片
.numberOfShards("3")
// 一个副本
.numberOfReplicas("1")
); // 新的索引有三个字段,每个字段都有自己的property,这里依次创建
Property keywordProperty = Property.of(pBuilder -> pBuilder.keyword(kBuilder -> kBuilder.ignoreAbove(256)));
Property textProperty = Property.of(pBuilder -> pBuilder.text(tBuilder -> tBuilder));
Property integerProperty = Property.of(pBuilder -> pBuilder.integer(iBuilder -> iBuilder)); // // 构建mapping时,builder用到的lambda
Function<TypeMapping.Builder, ObjectBuilder<TypeMapping>> mappingFn = mBuilder -> mBuilder
.properties("name", keywordProperty)
.properties("description", textProperty)
.properties("price", integerProperty); // 创建索引,并且指定了setting和mapping
esService.create(indexName, settingFn, mappingFn); }
}
  • 由于Java API Client中所有对象都统一使用builder pattern的方式创建,这导致代码量略多,例如setting部分,除了setting自身要用Lambda表达式,设置分片和副本的代码也要用Lambda的形式传入,这种嵌套效果在编码中看起来还是有点绕的,阅读起来可能会有点不适应
  • 执行单元测试,如下图,未发生异常

  • 用kibana查看新建的索引

  • 最后,将product001和product002的mapping放在一起对比,可见一模一样

  • 再用eshead对比分片和副本的效果,也是一模一样

小结和感慨

  • 至此,可以得出结论:
  1. Java API Client的对ES的操作,能得到kibana+JSON相同的效果
  2. 然而,用java代码来实现JSON的嵌套对象的内容,代码的复杂程度上升,可读性下降(纯属个人感觉)
  • 另外,在开发期间,我们也常常先用kibana+JSON先做基本的测试和验证,然后再去编码
  • 因此,如果能在代码中直接使用kibana的JSON,以此取代复杂的builder pattern代码去创建各种增删改查的请求对象,那该多好啊
  • ES官方预判了我的预判,在Java API Client中支持使用JSON来构建请求对象

能用JSON的根本原因

  • 动手实践之前,有个问题先思考一下

  • 刚才咱们写了那么多代码,才能创建出CreateIndexResponse对象(注意代码:elasticsearchClient.indices().create),怎么就能用JSON轻易的创建出来呢?有什么直接证据或者关键代码吗?

  • 来看看CreateIndexResponse的builder的源码,集成了父类,也实现了接口,

public static class Builder extends WithJsonObjectBuilderBase<Builder>
implements
ObjectBuilder<CreateIndexRequest> {
  • 用IDEA查看类图的功能,Builder的继承和实现关系一目了然,注意红色箭头指向的WithJson接口,它是Builder父类实现的接口,也是让CreateIndexResponse可以通过JSON来创建的关键

  • 强大的IDEA,可以在上图直接展开WithJson接口的所有方法签名,如下图,一目了然,三个方法三种入参,证明了使用者可以用三种方式将JSON内容传给Builder,再由Builer根据传入的内容生成CreateIndexResponse实例

创建工程

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<!-- 请改为自己项目的parent坐标 -->
<parent>
<artifactId>elasticsearch-tutorials</artifactId>
<groupId>com.bolingcavalry</groupId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<!-- 请改为自己项目的artifactId -->
<artifactId>object-from-json</artifactId>
<packaging>jar</packaging>
<!-- 请改为自己项目的name -->
<name>object-from-json</name>
<url>https://github.com/zq2599</url> <!--不用spring-boot-starter-parent作为parent时的配置-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId> <version>${springboot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency> <!-- 不加这个,configuration类中,IDEA总会添加一些提示 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency> <dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <!-- exclude junit 4 -->
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions> </dependency> <!-- junit 5 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency> <dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency> <!-- elasticsearch引入依赖 start -->
<dependency>
<groupId>co.elastic.clients</groupId>
<artifactId>elasticsearch-java</artifactId>
</dependency> <dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency> <!-- 使用spring boot Maven插件时需要添加该依赖 -->
<dependency>
<groupId>jakarta.json</groupId>
<artifactId>jakarta.json-api</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies> <build>
<plugins>
<!-- 需要此插件,在执行mvn test命令时才会执行单元测试 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M4</version>
<configuration>
<skipTests>false</skipTests>
</configuration>
</plugin> <plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins> <resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
</build>
</project>
  • 是个普通的SpringBoot应用,入口类FromJsonApplication.java如下,非常简单
package com.bolingcavalry.fromjson;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication
public class FromJsonApplication {
public static void main(String[] args) {
SpringApplication.run(FromJsonApplication.class, args);
}
}
  • 然后是连接ES的配置类ClientConfig.java,关于如何连接ES,在《java与es8实战之四》一文已经详细说明,不再赘述,直接使用配置类的elasticsearchClient方法创建的ElasticsearchClient对象即可操作ES
@ConfigurationProperties(prefix = "elasticsearch") //配置的前缀
@Configuration
public class ClientConfig { @Setter
private String hosts; /**
* 解析配置的字符串,转为HttpHost对象数组
* @return
*/
private HttpHost[] toHttpHost() {
if (!StringUtils.hasLength(hosts)) {
throw new RuntimeException("invalid elasticsearch configuration");
} String[] hostArray = hosts.split(",");
HttpHost[] httpHosts = new HttpHost[hostArray.length];
HttpHost httpHost;
for (int i = 0; i < hostArray.length; i++) {
String[] strings = hostArray[i].split(":");
httpHost = new HttpHost(strings[0], Integer.parseInt(strings[1]), "http");
httpHosts[i] = httpHost;
} return httpHosts;
} @Bean
public ElasticsearchClient elasticsearchClient() {
HttpHost[] httpHosts = toHttpHost();
RestClient restClient = RestClient.builder(httpHosts).build();
RestClientTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
// And create the API client
return new ElasticsearchClient(transport);
}
}
  • 最后是配置文件application.yml
elasticsearch:
# 多个IP逗号隔开
hosts: 127.0.0.1:9200
  • 现在工程已经建好,接下来开始实践如何通过JSON得到请求对象,通过刚才对WithJson接口的分析,JSON转请求对象共有三种方式
  1. ImputStream
  2. JSON字符串
  3. Parse
  • 接下来逐个实践

第一种:InputStream作为入参

  • 最简单的方式莫过通过InputStream转换,InputStream是大家常用到的IO类,相信您已经胸有成竹了,流程如下图

  • 开始编码,首先创建一个接口EsService.java,里面有名为create的方法,这是创建索引用的,入参是索引名和包含有JSON内容的InputStream
public interface EsService {
/**
* 以InputStream为入参创建索引
* @param name 索引名称
* @param inputStream 包含JSON内容的文件流对象
*/
void create(String name, InputStream inputStream) throws IOException;
}
  • 接下来是重点:EsService接口的实现类EsServiceImpl.java,可见非常简单,只要调用builder的withJson方法,将InputStream作为入参传入即可
@Service
public class EsServiceImpl implements EsService { @Autowired
private ElasticsearchClient elasticsearchClient; @Override
public void create(String name, InputStream inputStream) throws IOException {
// 根据InputStrea创建请求对象
CreateIndexRequest request = CreateIndexRequest.of(builder -> builder
.index(name)
.withJson(inputStream)); elasticsearchClient.indices().create(request);
}
}
  • 为了验证EsServiceImpl的create方法,先准备好json文件,文件名为product003.json,完整路径是:/Users/will/temp/202206/25/product003.json
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1
},
"mappings": {
"properties": {
"name": {
"type": "keyword",
"ignore_above": 256
},
"description": {
"type": "text"
},
"price": {
"type": "integer"
}
}
}
}
  • 最后写一个单元测试类,调用EsServiceImpl的create方法,将product003.json转成InputStream对象作为其入参,验证create方法的功能是否符合预期,如下所示,代码非常简单
    @Test
void createByInputStream() throws Exception {
// 文件名
String filePath = "/Users/will/temp/202206/25/product003.json";
// 索引名
String indexName = "product003";
// 通过InputStream创建索引
esService.create(indexName, new FileInputStream(filePath));
}
  • 运行单元测试代码,一切正常

  • 用kibana查看product003索引,如下所示,符合预期

  • 再用eshead查看副本和分片,和之前的两个索引一致

分析Reader类

  • 接下来尝试WithJson接口的第二个方法
default T withJson(Reader input) {
JsonpMapper mapper = SimpleJsonpMapper.INSTANCE_REJECT_UNKNOWN_FIELDS;
return withJson(mapper.jsonProvider().createParser(input), mapper);
}
  • 先来看看这个Reader的继承关系,本篇不会详细分析Reader代码,咱们重点关注它的两个比较重要的子类:StringReader和FileReader

  • 接下来先用FileReader作为withJson方法的入参,验证用文件来创建请求对象,再用StringReader作为withJson方法的入参,验证用字符串来创建请求对象

第二种:FileReader作为入参

  • 首先,给EsService接口新增一个方法
    /**
* 以Reader为入参创建索引
* @param name 索引名称
* @param reader 包含JSON内容的文件流对象
*/
void create(String name, Reader reader) throws IOException;
  • 接下来是重点:EsService接口的实现类EsServiceImpl.java,可见非常简单,只要调用builder的withJson方法,将Reader作为入参传入即可
    @Override
public void create(String name, Reader reader) throws IOException {
// 根据Reader创建请求对象
CreateIndexRequest request = CreateIndexRequest.of(builder -> builder
.index(name)
.withJson(reader)); elasticsearchClient.indices().create(request);
}
  • json文件继续使用刚才创建的product003.json文件

  • 单元测试代码中也增加一个方法,用于验证刚才写的create方法

    @Test
void createByReader() throws Exception {
// 文件名
String filePath = "/Users/will/temp/202206/25/product003.json";
// 索引名
String indexName = "product004"; // 通过InputStream创建索引
esService.create(indexName, new FileReader(filePath));
}
  • 接下来是执行单元测试方法,在kibana和eshead上验证product004索引和之前新建的几个索引是否一致,这里就不多占用篇幅了,结论是一模一样
  • 其实吧,用InputStream或者Reader作为参数,内部实现是一回事,来看看FileReader构造方法的源码吧,里面是InputStream
public class FileReader extends InputStreamReader {

    public FileReader(String fileName) throws FileNotFoundException {
super(new FileInputStream(fileName));
}

第三种:字符串作为入参

  • 接下来要验证的是用字符串来创建请求对象,这个比较实用,用字符串创建请求对象,给我们的应用开发提供了很大的自由度,废话少说,开始写代码

  • 首先还是给EsService接口新增一个方法,入参是索引名称和JSON字符串

    /**
* 以字符串为入参创建索引
* @param name 索引名称
* @param jsonContent 包含JSON内容的字符串
*/
void create(String name, String jsonContent) throws IOException;
  • 接下来是重点:EsService接口的实现类EsServiceImpl.java,可见非常简单,用字符串创建StringReader对象,然后只要调用builder的withJson方法,将StringReader对象作为入参传入即可
    @Override
public void create(String name, String jsonContent) throws IOException {
// 根据Reader创建请求对象
CreateIndexRequest request = CreateIndexRequest.of(builder -> builder
.index(name)
.withJson(new StringReader(jsonContent))); elasticsearchClient.indices().create(request);
}
  • 为了验证上面的create方法,在单元测试类中新增一个方法来验证
    @Test
void createByString() throws Exception {
// 文件名
String jsonContent = "{\n" +
" \"settings\": {\n" +
" \"number_of_shards\": 3,\n" +
" \"number_of_replicas\": 1\n" +
" },\n" +
" \"mappings\": {\n" +
" \"properties\": {\n" +
" \"name\": {\n" +
" \"type\": \"keyword\",\n" +
" \"ignore_above\": 256\n" +
" },\n" +
" \"description\": {\n" +
" \"type\": \"text\"\n" +
" },\n" +
" \"price\": {\n" +
" \"type\": \"integer\"\n" +
" }\n" +
" }\n" +
" }\n" +
"}\n"; // 索引名
String indexName = "product005"; // 通过InputStream创建索引
esService.create(indexName, jsonContent);
}
  • 接下来是执行单元测试方法,在kibana和eshead上验证product004索引和之前新建的几个索引是否一致,这里就不多占用篇幅了,结论是一模一样

第四种:JsonParser和JsonpMapper作为入参

  • 基于JSON创建ES请求对象的最后一种方法如下,入参是JsonParser和JsonpMapper
T withJson(JsonParser parser, JsonpMapper mapper)
  • 前面三种方法,咱们都写了代码去验证,不过最后这种就不写代码验证了,原因很简单:没必要,咱们先来看看WithJson接口的源码
public interface WithJson<T> {

    default T withJson(InputStream input) {
JsonpMapper mapper = SimpleJsonpMapper.INSTANCE_REJECT_UNKNOWN_FIELDS;
return withJson(mapper.jsonProvider().createParser(input), mapper);
} default T withJson(Reader input) {
JsonpMapper mapper = SimpleJsonpMapper.INSTANCE_REJECT_UNKNOWN_FIELDS;
return withJson(mapper.jsonProvider().createParser(input), mapper);
} T withJson(JsonParser parser, JsonpMapper mapper);
}
  • 可见,前面使用过的withJson(InputStream input)和withJson(Reader input),其实都是在调用withJson(JsonParser parser, JsonpMapper mapper),所以,在实际使用中,掌握withJson(InputStream input)和withJson(Reader input)就已经够用了,如果一定要使用withJson(JsonParser parser, JsonpMapper mapper),就参考上面的代码去构造JsonParser即可

代码和JSON内容混用

  • 有时候用代码和JSON混合使用来创建请求对象,既能用JSON省去大量代码工作,又能用代码保持该有的灵活性,如下所示,查询用JSON字符串,聚合参数用builder的API生成
Reader queryJson = new StringReader(
"{" +
" \"query\": {" +
" \"range\": {" +
" \"@timestamp\": {" +
" \"gt\": \"now-1w\"" +
" }" +
" }" +
" }" +
"}"); SearchRequest aggRequest = SearchRequest.of(b -> b
.withJson(queryJson)
.aggregations("max-cpu", a1 -> a1
.dateHistogram(h -> h
.field("@timestamp")
.calendarInterval(CalendarInterval.Hour)
)
.aggregations("max", a2 -> a2
.max(m -> m.field("host.cpu.usage"))
)
)
.size(0)
); Map<String, Aggregate> aggs = client
.search(aggRequest, Void.class)
.aggregations();
  • 另外,不光是请求对象,与请求对象有关的实例也能用JSON生成,回顾本文最开始的那段代码中,构造CreateIndexResponse对象时还要创建Property对象,实际上这个Property是可以通过JSON生成的,参考代码如下
String json = "{ " +
" \"type\": \"text\"," +
" \"fields\": {" +
" \"some_field\": { " +
" \"type\": \"keyword\"," +
" \"normalizer\": \"lowercase\"" +
" }" +
" }" +
" }"; Property p = Property.of(b -> b
.withJson(new StringReader(json))
);
  • 至此,基于JSON构造ES请求对象的实战就完成了,今后在kibana上验证通过的JSON请求体,可以直接放在代码中用于使用,这将有效的降低代码量,也提升了整体可读性

源码下载

名称 链接 备注
项目主页 https://github.com/zq2599/blog_demos 该项目在GitHub上的主页
git仓库地址(https) https://github.com/zq2599/blog_demos.git 该项目源码的仓库地址,https协议
git仓库地址(ssh) git@github.com:zq2599/blog_demos.git 该项目源码的仓库地址,ssh协议
  • 这个git项目中有多个文件夹,本次实战的源码在elasticsearch-tutorials文件夹下,如下图红框

  • elasticsearch-tutorials是个父工程,里面有多个module,本篇实战的module是object-from-json,如下图红框

欢迎关注博客园:程序员欣宸

学习路上,你不孤单,欣宸原创一路相伴...

java与es8实战之六:用JSON创建请求对象(比builder pattern更加直观简洁)的更多相关文章

  1. java版gRPC实战之六:客户端动态获取服务端地址

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  2. Java Spring Cloud 实战之路 - 1 创建项目

    0. 前言 该项目使用Maven进行管理和构建,所以需要预先配置好Maven.嗯,在这个系列里就不做过多的介绍了. 1. 创建项目 先创建一个pom.xml 文件,添加以下内容: <?xml v ...

  3. Java 用HTTP的方式发送JSON报文请求

    前言: 项目调用第三方接口时,通常是用socket或者http的通讯方式发送请求:http 为短连接,客户端发送请求都需要服务器端回送响应,请求结束后,主动释放链接.Socket为长连接:通常情况下S ...

  4. 使用JSON语法创建JS对象(重要)

    JS对象的键值可以加单引号或者不加或者加双引号 JSON语法提供了一种更简单的方式来创建对象,可以避免书写函数,也可避免用new关键字,可以直接创建一个JS对象,使用一个花括号,然后将每个属性写成&q ...

  5. Effective Java 第三版——2. 当构造方法参数过多时使用builder模式

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  6. Java秒杀系统实战系列~商品秒杀代码实战

    摘要: 本篇博文是“Java秒杀系统实战系列文章”的第六篇,本篇博文我们将进入整个秒杀系统核心功能模块的代码开发,即“商品秒杀”功能模块的代码实战. 内容: “商品秒杀”功能模块是建立在“商品详情”功 ...

  7. 重学 Java 设计模式:实战适配器模式

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 擦屁屁纸80%的面积都是保护手的! 工作到3年左右很大一部分程序员都想提升自己的技术 ...

  8. 重学 Java 设计模式:实战责任链模式「模拟618电商大促期间,项目上线流程多级负责人审批场景」

    作者:小傅哥 博客:https://bugstack.cn - 原创系列专题文章 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 场地和场景的重要性 射击

  9. 重学 Java 设计模式:实战备忘录模式「模拟互联网系统上线过程中,配置文件回滚场景」

    作者:小傅哥 博客:https://bugstack.cn - 原创系列专题文章 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 实现不了是研发的借口? 实现不了,有时候是功能复杂度较高难以实 ...

  10. 重学 Java 设计模式:实战状态模式「模拟系统营销活动,状态流程审核发布上线场景」

    作者:小傅哥 博客:https://bugstack.cn - 原创系列专题文章 沉淀.分享.成长,让自己和他人都能有所收获! @ 目录 一.前言 二.开发环境 三.状态模式介绍 四.案例场景模拟 1 ...

随机推荐

  1. LC19. 删除链表的倒数第 N 个结点

    删除链表的倒数第N个结点(中等) Q:给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点. 示例: 示例一:输入:head = [1,2,3,4,5], n = 2 输出:[1,2,3, ...

  2. 带你彻底掌握Bean的生命周期

    摘要:我们将深入研究Spring Framework的核心部分--Spring Bean的生命周期. 本文分享自华为云社区<Spring高手之路5--彻底掌握Bean的生命周期>,作者: ...

  3. 每日一题 力扣 1377 https://leetcode.cn/problems/frog-position-after-t-seconds/

    力扣 1377 https://leetcode.cn/problems/frog-position-after-t-seconds/ 这道题目用dp去做,构建邻接矩阵,做的时候需要注意题目条件,如果 ...

  4. ENVI实现QUAC、简化黑暗像元、FLAASH方法的遥感影像大气校正

    本文介绍基于ENVI软件,实现对Landsat 7遥感影像加以预处理与多种不同大气校正方法的操作. 目录 1 数据导入与辐射定标 2 波段合成 3 编辑头文件 4 转换文件格式 5 QUAC快速大气校 ...

  5. SQL Server中获取不同格式的日期

    select * from 表名 where Convert(varchar(100),日期字段,23)='2008-12-15' Convert函数的应用: Select CONVERT(varch ...

  6. 【IDEA】 远程调试

    远程调试 使用特定JVM参数运行服务端代码 要让远程服务器运行的代码支持远程调试,则启动的时候必须加上特定的JVM参数,这些参数是: -Xdebug -Xrunjdwp:transport=dt_so ...

  7. 基于SM4和LSB算法实现图片数字水印加密软件(密码赛)

    一.前言 密码赛和星火杯时做的小项目,密码赛的时候是个半成品,没有过初赛,星火杯之前完善了 设计思路 最开始是想做一个图片水印用作对图片来源的不可否认性做保护,又考虑保护数据完整性,因此选中了易损水印 ...

  8. CMOS信噪比与感光面积的关系

    前言 一般情况下,相同分辨率的sensor,如果感光面积越大,则其单位像素的感光面积也越大,成像质量也会越好.即相同分辨率品质相当的sensor,2/3"的传感器成像质量一般情况就要优于1/ ...

  9. 【Python】从同步到异步多核:测试桩性能优化,加速应用的开发和验证

    测试工作中常用到的测试桩mock能力 在我们的测试工作过程中,可能会遇到多个项目并行开发的时候,后端服务还没有开发完成,或者我们需要压测某个服务,这个服务测在试环境的依赖组件(如 MQ) 无法支撑我们 ...

  10. JPA自动生成POJO

    原文地址 JPA自动生成POJO 通过表生成POJO类 这篇文章不涉及idea配置数据源教程,该文章使用前提是用户已配置好idea数据源 修改自带的生成类 import com.intellij.da ...