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

SpringData ElasticSearch - 简化开发,完美适配 Spring 生态

目录

一、SpringData ElasticSearch

1.1、环境配置

1.2、创建实体类

1.3、ElasticsearchRestTemplate 的使用

1.3.1、创建索引 设置映射

1.3.2、创建索引映射注意事项(必看)

1.3.3、简单的增删改查

1.3.4、搜索

1.4、ElasticsearchRepository

1.4.1、使用方式

1.4.2、简单的增删改查

1.4.3、分页排序查询


一、SpringData ElasticSearch


1.1、环境配置

a)依赖如下:

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId></dependency>

b)配置文件如下:

spring:elasticsearch:uris: env-base:9200

1.2、创建实体类

a)简单结构如下(后续实例,围绕此结构展开):

import org.springframework.data.annotation.Id
import org.springframework.data.elasticsearch.annotations.Document
import org.springframework.data.elasticsearch.annotations.Field
import org.springframework.data.elasticsearch.annotations.FieldType/***  @shards: 主分片数量*  @replicas: 副本分片数量*/
@Document(indexName = "album_info", shards = 1, replicas = 0)
data class AlbumInfoDo(/*** @Id: 表示文档中的主键,并且会在保存在 ElasticSearch 数据结构中 {"id": "", "userId": "", "title": ""}*/@Id@Field(type = FieldType.Keyword)val id: Long? = null,/*** @Field: 描述 Java 类型中的属性映射*      - name: 对应 ES 索引中的字段名. 默认和属性同名*      - type: 对应字段类型,默认是 FieldType.Auto (会根据我们数据类型自动进行定义),但是建议主动定义,避免导致错误映射*      - index: 是否创建索引. text 类型创建倒排索引,其他类型创建正排索引.  默认是 true*      - analyzer: 分词器名称.  中文我们一般都使用 ik 分词器(ik分词器有 ik_smart 和 ik_max_word)*/@Field(name = "user_id", type = FieldType.Long)val userId: Long,@Field(type = FieldType.Text, analyzer = "ik_max_word")val title: String,@Field(type = FieldType.Text, analyzer = "ik_smart")val content: String,
)

b)复杂嵌套结构如下:

import org.springframework.data.annotation.Id
import org.springframework.data.elasticsearch.annotations.Document
import org.springframework.data.elasticsearch.annotations.Field
import org.springframework.data.elasticsearch.annotations.FieldType@Document(indexName = "album_list")
data class AlbumListDo(@Id@Field(type = FieldType.Keyword)var id: Long,@Field(type = FieldType.Nested) // 表示一个嵌套结构var userinfo: UserInfoSimp,@Field(type = FieldType.Text, analyzer = "ik_max_word")var title: String,@Field(type = FieldType.Text, analyzer = "ik_smart")var content: String,@Field(type = FieldType.Nested) // 表示一个嵌套结构var photos: List<AlbumPhotoSimp>,
)data class UserInfoSimp(@Field(type = FieldType.Long)val userId: Long,@Field(type = FieldType.Text, analyzer = "ik_max_word")val username: String,@Field(type = FieldType.Keyword, index = false)val avatar: String,
)data class AlbumPhotoSimp(@Field(type = FieldType.Integer, index = false)val sort: Int,@Field(type = FieldType.Keyword, index = false)val photo: String,
)

对于一个小型系统来说,一般也不会创建这种复杂程度的文档,因为会涉及到很多一致性问题, 需要通过大量的 mq 进行同步,给系统带来一定的开销. 

因此,一般会将需要进行模糊查询的字段存 Document 中(es 就擅长这个),而其他数据则可以在 Document 中以 id 的形式进行存储.   这样就既可以借助 es 高效的模糊查询能力,也能减少为保证一致性而带来的系统开销.  从 es 中查到数据后,再通过其他表的 id 从数据库中拿数据即可(这点开销,相对于从大量数据的数据库中进行 like 查询,几乎可以忽略).

1.3、ElasticsearchRestTemplate 的使用

1.3.1、创建索引 设置映射

@SpringBootTest(classes = [DataEsApplication::class])
class DataEsApplicationTests {@Resource private lateinit var elasticsearchTemplate: ElasticsearchRestTemplate@Testfun test1() {//创建索引elasticsearchTemplate.indexOps(AlbumInfoDo::class.java).create()//设置映射elasticsearchTemplate.indexOps(AlbumInfoDo::class.java).putMapping(elasticsearchTemplate.indexOps(AlbumInfoDo::class.java).createMapping())}}

效果如下:

1.3.2、创建索引映射注意事项(必看)

a)在没有创建索引库和映射的情况下,也可以直接向 es 库中插入数据,如下代码:

    @Testfun test1() {val o = AlbumListDo(id = 1,userinfo = UserInfoSimp(userId = 1,username = "cyk",avatar = "http:photo1.com"),title = "天气很好的一天",content = "早上起来,我要好好学习,然去公园散步~",photos = listOf(AlbumPhotoSimp(1, "www.photo1"),AlbumPhotoSimp(2, "www.photo2")))val result = esTemplate.save(o)println(result)}

b)即使上述代码中 AlbumListDo 中有各种注解标记,但是不会生效!!! es 会根据插入的数据,自动转化数据结构(无视你的注解).

c)因此,一定要先创建索引库和映射,再进行数据插入!

1.3.3、简单的增删改查

    /*** 更新和添加都是这样* 更新的时候会根据 id 进行覆盖*/@Testfun testSave() {//保存单条数据val a1 = AlbumInfoDo(id = 1,userId = 10000,title = "今天天气真好",content = "学习完之后,我要出去好好玩")val result = elasticsearchTemplate.save(a1)println(result)//保存多条数据val list = listOf(AlbumInfoDo(2, 10000, "西安六号线避雷", "前俯后仰。他就一直在那前后动。他背后是我朋友,我让他不要挤了,他直接就急了,开始故意很大力的挤来挤去。"),AlbumInfoDo(3, 10000, "字节跳动快上车~", "#内推 #字节跳动内推 #互联网"),AlbumInfoDo(4, 10000, "连王思聪也变得低调老实了", "如今的王思聪,不仅交女友的质量下降,在网上也不再像以前那样随意喷这喷那。显然,资金的紧张让他低调了许多"))val resultList = elasticsearchTemplate.save(list)resultList.forEach(::println)}@Testfun testDelete() {//根据主键删除elasticsearchTemplate.delete("1", AlbumInfoDo::class.java)}@Testfun testGet() {val result = elasticsearchTemplate.get("1", AlbumInfoDo::class.java)println(result)}

补充一个修改:

    override fun update(msg: UpdateAlbumInfoMsg): Int {val query = UpdateQuery.builder(msg.albumId.toString()) //指定修改的文档 id.withDocument(org.springframework.data.elasticsearch.core.document.Document.create() //指定修改字段.append("title", msg.title) .append("content", msg.content).append("ut_time", msg.utTime)).build()val result = restTemplate.update(query, IndexCoordinates.of("album_doc")).resultreturn result.ordinal}

1.3.4、搜索

a)一般搜索

import org.cyk.dataes.model.AlbumInfoDo
import org.elasticsearch.index.query.QueryBuilders
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder
import org.junit.jupiter.api.Test
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.data.domain.PageRequest
import org.springframework.data.domain.Sort
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder
import javax.annotation.Resource@SpringBootTest(classes = [DataEsApplication::class])
class TemplateTests {@Resource private lateinit var elasticsearchTemplate: ElasticsearchRestTemplate/*** 全文检索查询(match_all)*/@Testfun testMatchAllQuery() {val query = NativeSearchQueryBuilder().withQuery(QueryBuilders.matchAllQuery()).build()val hits = elasticsearchTemplate.search(query, AlbumInfoDo::class.java)println("总数为: ${hits.totalHits}")hits.forEach { println(it.content) }}/*** 全文检索查询(match)*/@Testfun testMatchQuery() {val query = NativeSearchQueryBuilder().withQuery(QueryBuilders.matchQuery("title", "天气")).build()val hits = elasticsearchTemplate.search(query, AlbumInfoDo::class.java)hits.forEach { println(it.content) }}/*** 精确查询(term)*/@Testfun testTerm() {val query = NativeSearchQueryBuilder().withQuery(QueryBuilders.termQuery("user_id", 10001)).build()val hits = elasticsearchTemplate.search(query, AlbumInfoDo::class.java)hits.forEach { println(it.content) }}/*** 范围查询*/@Testfun testRangeQuery() {val query = NativeSearchQueryBuilder().withQuery(QueryBuilders.rangeQuery("id").gte(1).lt(4)).build()val hits = elasticsearchTemplate.search(query, AlbumInfoDo::class.java)hits.forEach { println(it.content) }}/*** 复合查询(bool)*/@Testfun testBoolQuery() {val boolQuery = QueryBuilders.boolQuery()//必要条件: query.must 得到一个集合val mustList = boolQuery.must()mustList.add(QueryBuilders.rangeQuery("user_id").gte(10000).lt(10003))//其他的搜索条件集合的获取方式类似val mustNotList = boolQuery.mustNot()val should = boolQuery.should()//当然,还有一种简化的写法,如下,下述代码相当于 query.should().add(QueryBuilders.matchAllQuery())boolQuery.should(QueryBuilders.matchAllQuery())val query =  NativeSearchQueryBuilder().withQuery(boolQuery).build()val hits = elasticsearchTemplate.search(query, AlbumInfoDo::class.java)hits.forEach { println(it.content) }}/*** 排序和分页*/@Testfun testSortAndPage() {val query = NativeSearchQueryBuilder().withQuery(QueryBuilders.matchAllQuery()).withPageable(PageRequest.of(0, 3) //参数一: 页码(从 0 开始),size 每页查询多少条数据.withSort(Sort.by(Sort.Order.desc("id"))) //根据 id 降序排序(这里也可以根据多个字段进行升序降序)).build()val hits = elasticsearchTemplate.search(query, AlbumInfoDo::class.java)hits.forEach{ println(it.content) }}/*** 高亮搜索*/@Testfun testHighLight() {//定义高亮字段val field = HighlightBuilder.Field("title")//a) 前缀标签field.preTags("<span style='color:red'>")//b) 后缀标签field.postTags("</span>")//c) 高亮的片段长度(多少个几个字需要高亮,一般会设置的大一些,让匹配到的字段尽量都高亮)field.fragmentSize(10)//d) 高亮片段的数量field.numOfFragments(1)// withHighlightFields(Field... 高亮字段数组)val query = NativeSearchQueryBuilder().withQuery(QueryBuilders.matchQuery("title", "天气")).withHighlightFields(field).build()val hits = elasticsearchTemplate.search(query, AlbumInfoDo::class.java)//注意,hit.content 中本身是没有高亮数据的,因此这里需要手工处理hits.forEach {val result = it.content//根据高亮字段名称,获取高亮数据集合,结果是 List<String>val hList = it.getHighlightField("title")if(hList.size > 0) {//有高亮数据result.title = hList.get(0)}println(result)}}}

b)基于 completionSuggestion 实现自动补全

data 如下:

@Document(indexName = "album_doc")
data class AlbumDocDo (@Id@Field(type = FieldType.Keyword)val id: Long,@Field(name = "user_id", type = FieldType.Long)val userId: Long,@Field(type = FieldType.Text, analyzer = "ik_max_word", copyTo = ["suggestion"])val title: String,@Field(type = FieldType.Text, analyzer = "ik_smart")val content: String,@Field(name = "ct_time", type = FieldType.Long)val ctTime: Long,@Field(name = "ut_time", type = FieldType.Long)val utTime: Long,@CompletionField(maxInputLength = 100, analyzer = "ik_max_word", searchAnalyzer = "ik_max_word")val suggestion: Completion? = null,
)

自动补全的字段必须是 completion 类型.  自动补全字段为 title,将他 copy 到了 suggestion 字段,实现自动补全. 

    override fun suggestTexts(o: AlbumSuggestDto): List<String> {val suggest = SuggestBuilder().addSuggestion("title_suggest",     //自定义补全名SuggestBuilders.completionSuggestion("suggestion") //自动补全时需要查询的字段.prefix(o.text)        //要进行补全的值(用户搜索框中输入的).skipDuplicates(true)  //如果查询时有重复的词条,是否自动跳过(true 为跳过).size(o.limit)         //获取多少个结果)val query = NativeSearchQueryBuilder().withSuggestBuilder(suggest).build()val hits = restTemplate.search(query, AlbumDocDo::class.java)val suggests = hits.suggest?.getSuggestion("title_suggest") //根据自定义补全名获取对应的补全结果集?.entries?.get(0)      //结果集(记录了根据什么前缀(prefix)进行自动补全,补全的结果对象...)?.options?.map(::map) ?: emptyList()  //补全的结果对象(其中 text 就是自动补全的结果)return suggests}private fun map(hit: Suggest.Suggestion.Entry.Option): String {return hit.text}

例如需要自动补全 "c",result 结构如下

1.4、ElasticsearchRepository

1.4.1、使用方式

这个东西就跟 JPA 的使用方式一样,只不过高版本的 SpringData Elasticsearch 没有给 ElasticsearchRepository 接口提供复杂搜索查询,建议还是使用 ElasticsearchTemplate

自定义一个接口, 继承  ElasticsearchRepository 接口,如下:

import org.cyk.dataes.model.AlbumInfoDo
import org.springframework.data.elasticsearch.repository.ElasticsearchRepositoryinterface AlbumInfoRepo: ElasticsearchRepository<AlbumInfoDo, Long> //<实体类,主键类型>

1.4.2、简单的增删改查

import org.cyk.dataes.model.AlbumInfoDo
import org.cyk.dataes.service.AlbumInfoESRepo
import org.junit.jupiter.api.Test
import org.springframework.boot.test.context.SpringBootTest
import javax.annotation.Resource@SpringBootTest(classes = [DataEsApplication::class])
class RepoTests {@Resource private lateinit var albumInfoESRepo: AlbumInfoESRepo@Testfun testSave() {//增加单个val a = AlbumInfoDo(1, 10000, "今天天气真好", "学习完之后,我要出去好好玩")val result = albumInfoESRepo.save(a)println(result)//批量新增val list = listOf(AlbumInfoDo(2, 10000, "西安六号线避雷", "前俯后仰。他就一直在那前后动。他背后是我朋友,我让他不要挤了,他直接就急了,开始故意很大力的挤来挤去。"),AlbumInfoDo(3, 10000, "字节跳动快上车~", "#内推 #字节跳动内推 #互联网"),AlbumInfoDo(4, 10000, "连王思聪也变得低调老实了", "如今的王思聪,不仅交女友的质量下降,在网上也不再像以前那样随意喷这喷那。显然,资金的紧张让他低调了许多"))val resultList = albumInfoESRepo.saveAll(list)resultList.forEach(::println)}@Testfun testDel() {//根据 id 删除albumInfoESRepo.deleteById(1)//删除所有albumInfoESRepo.deleteAll()}@Testfun testFind() {//查询所有val resultList = albumInfoESRepo.findAll()resultList.forEach(::println)//根据 id 查询val result = albumInfoESRepo.findById(1)println(result.get())}}

1.4.3、分页排序查询

import org.cyk.dataes.service.AlbumInfoESRepo
import org.junit.jupiter.api.Test
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.data.domain.PageRequest
import org.springframework.data.domain.Sort
import javax.annotation.Resource@SpringBootTest(classes = [DataEsApplication::class])
class RepoTests2 {@Resourceprivate lateinit var albumInfoESRepo: AlbumInfoESRepo@Testfun testFindPageAndSort() {//从 0 下标开始向后获取 3 个,并根据 id 降序排序val result = albumInfoESRepo.findAll(PageRequest.of(0, 3,Sort.by(Sort.Direction.DESC, "id")))result.content.forEach(::println)}}

相关文章:

SpringData ElasticSearch - 简化开发,完美适配 Spring 生态

目录 一、SpringData ElasticSearch 1.1、环境配置 1.2、创建实体类 1.3、ElasticsearchRestTemplate 的使用 1.3.1、创建索引 设置映射 1.3.2、创建索引映射注意事项&#xff08;必看&#xff09; 1.3.3、简单的增删改查 1.3.4、搜索 1.4、ElasticsearchRepository …...

突破!AI机器人拥有嗅觉!仿生嗅觉芯片研究登上Nature子刊

我们一直梦想着让AI与人类能够更加相似&#xff0c;赋予它们视觉与听觉。而让机器人拥有嗅觉一直以来面临着巨大的困难。 香港科技大学范志勇教授领导的研究团队凭借最新研发的仿生嗅觉芯片&#xff08;BOC&#xff09;在这一领域取得了重大突破。该研究成果目前已被发表到IF …...

前端接口防止重复请求实现方案

前言 前段时间老板心血来潮&#xff0c;要我们前端组对整个的项目都做一下接口防止重复请求的处理&#xff08;似乎是有用户通过一些快速点击薅到了一些优惠券啥的&#xff09;。。。听到这个需求&#xff0c;第一反应就是&#xff0c;防止薅羊毛最保险的方案不还是在服务端加…...

【leetcode面试经典150题】13.除自身以外数组的乘积(C++)

【leetcode面试经典150题】专栏系列将为准备暑期实习生以及秋招的同学们提高在面试时的经典面试算法题的思路和想法。本专栏将以一题多解和精简算法思路为主&#xff0c;题解使用C语言。&#xff08;若有使用其他语言的同学也可了解题解思路&#xff0c;本质上语法内容一致&…...

网络编程核心概念解析:IP地址、端口号与网络字节序深度探讨

⭐小白苦学IT的博客主页 ⭐初学者必看&#xff1a;Linux操作系统入门 ⭐代码仓库&#xff1a;Linux代码仓库 ❤关注我一起讨论和学习Linux系统 本节重点 认识IP地址, 端口号, 网络字节序等网络编程中的基本概念; 1.前言 网络编程&#xff0c;作为现代信息社会中的一项核心技术&…...

突破编程_C++_网络编程(TCPIP 四层模型(网络层(1))

1 网络层概述 TCP/IP 四层模型中的网络层是模型中的核心组成部分&#xff0c;它主要负责处理数据包的路由和转发&#xff0c;确保数据能够在源主机和目标主机之间准确地传输。 一、主要功能 网络层的主要功能是实现数据包的选路和转发。当数据从应用层传输到传输层后&#x…...

Java | Leetcode Java题解之第9题回文数

题目&#xff1a; 题解&#xff1a; class Solution {public boolean isPalindrome(int x) {// 特殊情况&#xff1a;// 如上所述&#xff0c;当 x < 0 时&#xff0c;x 不是回文数。// 同样地&#xff0c;如果数字的最后一位是 0&#xff0c;为了使该数字为回文&#xff0…...

极简云验证 download.php 文件读取漏洞复现

0x01 产品简介 极简云验证是一款开源的网络验证系统&#xff0c;支持多应用卡密生成&#xff1a;卡密生成 单码卡密 次数卡密 会员卡密 积分卡密、卡密管理 卡密长度 卡密封禁 批量生成 批量导出 自定义卡密前缀等&#xff1b;支持多应用多用户管理&#xff1a;应用备注 应用版…...

红黑树路径长度分析:证明与实现

红黑树路径长度分析&#xff1a;证明与实现 一、红黑树的基本性质二、证明&#xff1a;最长路径至多是最短路径的2倍2.1 证明思路2.2 证明过程 三、伪代码实现四、 C语言代码实现5、 结论 红黑树作为一种高效的自平衡二叉搜索树&#xff0c;在计算机科学领域中被广泛应用于各种…...

esp32 gpio初识(一)

目录 功能介绍 实操 功能介绍 引脚又叫管脚&#xff0c;英文叫 Pin, 就是从集成电路&#xff08;芯片以及一些电子元件&#xff09;内部电路引出与外围电路的接线的接口。 在我们的 ESP32 开发板上, 我们可以把这些称为引脚, 这些引脚其实是从 ESP32 芯片内部引出来的, 我们…...

python 自制黄金矿工游戏(设计思路+源码)

1.视频效果演示 python自制黄金矿工&#xff0c;细节拉满沉浸式体验&#xff0c;看了你也会 2.开发准备的工具 python3.8, pygame库(python3.5以上的版本应该都可以) 图片处理工具&#xff0c;美图秀秀 截图工具&#xff0c;电脑自带的 自动抠图网页&#xff1a;https://ko…...

Splunk Attack Range:一款针对Splunk安全的模拟测试环境创建工具

关于Splunk Attack Range Splunk Attack Range是一款针对Splunk安全的模拟测试环境创建工具&#xff0c;该工具完全开源&#xff0c;目前由Splunk威胁研究团队负责维护。 该工具能够帮助广大研究人员构建模拟攻击测试所用的本地或云端环境&#xff0c;并将数据转发至Splunk实例…...

OpenCV入门例程:裁剪图片、模糊检测、黑屏检测

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 本例程运行环境为CentOS7&…...

opencv-python库 cv2边界填充resize图片

文章目录 边界填充改变图片大小 边界填充 在OpenCV中&#xff0c;边界填充&#xff08;Border Padding&#xff09;是指在图像周围添加额外的像素&#xff0c;以扩展图像的尺寸或满足某些算法&#xff08;如卷积&#xff09;的要求。OpenCV提供了cv2.copyMakeBorder()函数来进…...

Java代码基础算法练习-负数个数统计-2024.04.04

任务描述&#xff1a; 从键盘输入任意10个整型数&#xff08;数值范围-100000~100000&#xff09;&#xff0c;统计其中的负数个数 任务要求&#xff1a; 代码示例&#xff1a; package April_2024;import java.util.Scanner;// 从键盘输入任意10个整型数&#xff08;数值范围…...

【算法刷题day17】Leetcode:110.平衡二叉树 257. 二叉树的所有路径 404.左叶子之和

110.平衡二叉树 文档链接&#xff1a;[代码随想录] 题目链接&#xff1a;:110.平衡二叉树 题目&#xff1a; 给定一个二叉树&#xff0c;判断它是否是 平衡二叉树 注意&#xff1a; 判断两棵子树高度差是否大于1 class Solution { public:int result;bool isBalanced(TreeNode…...

C++ | Leetcode C++题解之第10题正则表达式匹配

题目&#xff1a; 题解&#xff1a; class Solution { public:bool isMatch(string s, string p) {int m s.size();int n p.size();auto matches [&](int i, int j) {if (i 0) {return false;}if (p[j - 1] .) {return true;}return s[i - 1] p[j - 1];};vector<…...

职场迷航?MBTI测试为你指明方向,找到最匹配的职业!

MBTI简介 MBTI的全名是Myers-Briggs Type Indicator。它是一种迫选型、自我报告式的性格评估工具&#xff0c;用以衡量和描述人们在获取信息、作出决策、对待生活等方面的心理活动规律和性格类型。 类型指标 美国的凯恩琳布里格斯和她的女儿伊莎贝尔布里格斯迈尔斯研制了迈尔…...

hive 慢sql 查询

hive 慢sql 查询 查找 hive 执行日志存储路径&#xff08;一般是 hive-audit.log &#xff09; 比如&#xff1a;/var/log/Bigdata/audit/hive/hiveserver/hive-audit.log 解析日志 获取 执行时间 执行 OperationId 执行人 UserNameroot 执行sql 数据分隔符为 \001 并写入 hiv…...

Vue - 2( 10000 字 Vue 入门级教程)

一&#xff1a;Vue 1.1 绑定样式 1.1.1 绑定 class 样式 <!DOCTYPE html> <html><head><meta charset"UTF-8" /><title>绑定样式</title><style>......</style><script type"text/javascript" src&…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文&#xff5c;魏琳华 编&#xff5c;王一粟 一场大会&#xff0c;聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中&#xff0c;汇集了学界、创业公司和大厂等三方的热门选手&#xff0c;关于多模态的集中讨论达到了前所未有的热度。其中&#xff0c;…...

C++实现分布式网络通信框架RPC(3)--rpc调用端

目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中&#xff0c;我们已经大致实现了rpc服务端的各项功能代…...

HBuilderX安装(uni-app和小程序开发)

下载HBuilderX 访问官方网站&#xff1a;https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本&#xff1a; Windows版&#xff08;推荐下载标准版&#xff09; Windows系统安装步骤 运行安装程序&#xff1a; 双击下载的.exe安装文件 如果出现安全提示&…...

Robots.txt 文件

什么是robots.txt&#xff1f; robots.txt 是一个位于网站根目录下的文本文件&#xff08;如&#xff1a;https://example.com/robots.txt&#xff09;&#xff0c;它用于指导网络爬虫&#xff08;如搜索引擎的蜘蛛程序&#xff09;如何抓取该网站的内容。这个文件遵循 Robots…...

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

2023赣州旅游投资集团

单选题 1.“不登高山&#xff0c;不知天之高也&#xff1b;不临深溪&#xff0c;不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?

Redis 的发布订阅&#xff08;Pub/Sub&#xff09;模式与专业的 MQ&#xff08;Message Queue&#xff09;如 Kafka、RabbitMQ 进行比较&#xff0c;核心的权衡点在于&#xff1a;简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...

七、数据库的完整性

七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

CppCon 2015 学习:Time Programming Fundamentals

Civil Time 公历时间 特点&#xff1a; 共 6 个字段&#xff1a; Year&#xff08;年&#xff09;Month&#xff08;月&#xff09;Day&#xff08;日&#xff09;Hour&#xff08;小时&#xff09;Minute&#xff08;分钟&#xff09;Second&#xff08;秒&#xff09; 表示…...