Mall脚手架总结(二) —— SpringData操作Elasticsearch

前言

        万字长文带你弄清楚SpringData中的Elasticsearch操作以及在脚手架里接口的结构关系!经过前面鉴证授权的整合,荔枝开始熟悉项目的学习的方法了,虽然脚手架中的内容比较简单,但是把边角的知识点全部扫到还是比较花时间的尤其是对于基础不是特别牢固的小伙伴来说~荔枝也希望这篇文章能对正在学习的小伙伴有帮助~~~


文章目录

前言

一、整合ES实现搜索

1.1 SpringData框架

1.2 ElasticsearchRepository

1.3 分页工具:Pageable、Page 

1.3.1 Page接口

1.3.2 Pageable接口

1.4 函数式接口 

1.5 常用注解

1.6 Elasticsearch实现搜索的流程

 总结


一、整合ES实现搜索

        Elasticsearch实现搜索的功能比较简单,我们需要自定义一个Dao层的接口来自定义Mybatis操作数据库并将需要搜索的数据导入到ES中,同时对于相关的操作ES的操作我们通过一个继承ElasticsearchRepository接口的功能接口比如EsProductRepository来实现,其中有关ElasticsearchRepository的知识需要我们着重去理解。同时我们需要清楚的是在SpringBoot中我们操作Elasticsearch是通过Spring Data框架来实现的。

1.1 SpringData框架

        Spring Data是Spring中的一个子项目,通过官网的介绍我们可以了解到Spring Data是为各种数据访问技术提供一种一致的基于Spring编程的模型,同时也保证数据存储的特殊特性。其中包含了比如JDBC、JPA、MongoDB、Redis、 Elasticsearch等技术在Spring项目中的数据操作。在SpringBoot项目中来操作ES使用SpringData无疑是最好的哈哈哈。

Repository 

        Repository是Spring Data框架中定义的一个泛型接口(标记接口),该接口并不会定义任何方法,我们可以通过定义功能接口继承Repository,则该接口会被IOC容器识别为一个Repository Bean纳入到IOC容器中,进而可以在该接口中定义满足一定规范的方法。 

package org.springframework.data.repository;import org.springframework.stereotype.Indexed;@Indexed
public interface Repository<T, ID> {
}

需要注意的是,Spring Data中给出了该接口的基本的继承接口CrudRepository,该接口定义了基本的操作数据库的CRUD方法,比如save开头的保存数据方法、find用来查询数据的方法等

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.springframework.data.repository;import java.util.Optional;@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {<S extends T> S save(S entity);  //保存单个实体<S extends T> Iterable<S> saveAll(Iterable<S> entities); //保存集合Optional<T> findById(ID id);boolean existsById(ID id);Iterable<T> findAll();Iterable<T> findAllById(Iterable<ID> ids);long count();void deleteById(ID id);void delete(T entity);void deleteAllById(Iterable<? extends ID> ids);void deleteAll(Iterable<? extends T> entities);void deleteAll();
}

继承的子接口:

  • CrudRepository:继承Repository,实现一组CURD相关的方法
  • PagingAndSortingRespository:继承CrudRepository,实现了一组分页排序相关的方法
  • JpaRepository:继承PagingAndSortingRespository,实现了一组JPA规范相关的方法
  • JpaSpecificationExecutor:不属于Repository体系,实现一组 JPA Criteria 查询相关的方法

1.2 ElasticsearchRepository

        ElasticsearchRepository是Repository的一个曾孙子辈的接口,继承关系自PagingAndSortingRepository接口。在前面我们知道该接口在CrudRepository接口基础上添加了一些分页的操作。回到前面Spring Data定义的要整合数据访问技术的初衷,有关ES的操作也就必须会有一个相应的特殊的接口实现了:ElasticsearchRepository。

下面先看看这张图理清楚不同了接口之间的继承关系:

再来看看源码:

@NoRepositoryBean
public interface ElasticsearchRepository<T, ID> extends PagingAndSortingRepository<T, ID> {Page<T> searchSimilar(T entity, @Nullable String[] fields, Pageable pageable);
}

说一下@NoRepositoryBean,该注解是为了防止Spring Data为其创建实例,官网规定我们在定义Repository的子接口的时候加入该注解,具体深入的原因这里就不赘述,可以看看这篇文章:

https://www.cnblogs.com/logoman/p/11707659.html

searchSimilar是一个一个只能使用ID字段进行模糊查询的方法,具体的细节大家可以看看这篇博文

Elasticsearch中ElasticsearchRepository的searchSimilar使用的坑-CSDN博客

        看了这么多的补充知识,相信大家对大体的SpringData提供的ElasticsearchRepository接口也有了相应的了解,回到脚手架的实现上,这里定义了一个根据名称、标题和关键词来模糊搜索的方法,需要注意的是这里的方法命名语法是有特定的要求的,因为我们需要通过衍生查询来实现ES中的数据操作。

package com.crj.crj_mall_learning.elasticsearch.repository;import com.crj.crj_mall_learning.elasticsearch.document.EsProduct;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;/*** @auther lzddl* @description 商品ES操作类*/
public interface EsProductRepository extends ElasticsearchRepository<EsProduct, Long> {/*** 搜索查询** @param name              商品名称* @param subTitle          商品标题* @param keywords          商品关键字* @param page              分页信息* @return*///该接口交给RS自动生成相应的实现类Page<EsProduct> findByNameOrSubTitleOrKeywords(String name, String subTitle, String keywords, Pageable page);//再随便写一个根据名字和标题搜索的方法试试Page<EsProduct> findByNameOrSubTitle(String name,String subTitle,Pageable page);
}

IDEA中默认会提示相应的衍生查询的关键字!

衍生查询的关键字

Keyword

Sample

Elasticsearch Query String

And

findByNameAndPrice

{ "query" : { "bool" : { "must" : [ { "query_string" : { "query" : "?", "fields" : [ "name" ] } }, { "query_string" : { "query" : "?", "fields" : [ "price" ] } } ] } }}

Or

findByNameOrPrice

{ "query" : { "bool" : { "should" : [ { "query_string" : { "query" : "?", "fields" : [ "name" ] } }, { "query_string" : { "query" : "?", "fields" : [ "price" ] } } ] } }}

Is

findByName

{ "query" : { "bool" : { "must" : [ { "query_string" : { "query" : "?", "fields" : [ "name" ] } } ] } }}

Not

findByNameNot

{ "query" : { "bool" : { "must_not" : [ { "query_string" : { "query" : "?", "fields" : [ "name" ] } } ] } }}

Between

findByPriceBetween

{ "query" : { "bool" : { "must" : [ {"range" : {"price" : {"from" : ?, "to" : ?, "include_lower" : true, "include_upper" : true } } } ] } }}

LessThan

findByPriceLessThan

{ "query" : { "bool" : { "must" : [ {"range" : {"price" : {"from" : null, "to" : ?, "include_lower" : true, "include_upper" : false } } } ] } }}

LessThanEqual

findByPriceLessThanEqual

{ "query" : { "bool" : { "must" : [ {"range" : {"price" : {"from" : null, "to" : ?, "include_lower" : true, "include_upper" : true } } } ] } }}

GreaterThan

findByPriceGreaterThan

{ "query" : { "bool" : { "must" : [ {"range" : {"price" : {"from" : ?, "to" : null, "include_lower" : false, "include_upper" : true } } } ] } }}

GreaterThanEqual

findByPriceGreaterThan

{ "query" : { "bool" : { "must" : [ {"range" : {"price" : {"from" : ?, "to" : null, "include_lower" : true, "include_upper" : true } } } ] } }}

Before

findByPriceBefore

{ "query" : { "bool" : { "must" : [ {"range" : {"price" : {"from" : null, "to" : ?, "include_lower" : true, "include_upper" : true } } } ] } }}

After

findByPriceAfter

{ "query" : { "bool" : { "must" : [ {"range" : {"price" : {"from" : ?, "to" : null, "include_lower" : true, "include_upper" : true } } } ] } }}

Like

findByNameLike

{ "query" : { "bool" : { "must" : [ { "query_string" : { "query" : "?*", "fields" : [ "name" ] }, "analyze_wildcard": true } ] } }}

StartingWith

findByNameStartingWith

{ "query" : { "bool" : { "must" : [ { "query_string" : { "query" : "?*", "fields" : [ "name" ] }, "analyze_wildcard": true } ] } }}

EndingWith

findByNameEndingWith

{ "query" : { "bool" : { "must" : [ { "query_string" : { "query" : "*?", "fields" : [ "name" ] }, "analyze_wildcard": true } ] } }}

Contains/Containing

findByNameContaining

{ "query" : { "bool" : { "must" : [ { "query_string" : { "query" : "?", "fields" : [ "name" ] }, "analyze_wildcard": true } ] } }}

In (when annotated as FieldType.Keyword)

findByNameIn(Collectionnames)

{ "query" : { "bool" : { "must" : [ {"bool" : {"must" : [ {"terms" : {"name" : ["?","?"]}} ] } } ] } }}

In

findByNameIn(Collectionnames)

{ "query": {"bool": {"must": [{"query_string":{"query": ""?" "?"", "fields": ["name"]}}]}}}

NotIn (when annotated as FieldType.Keyword)

findByNameNotIn(Collectionnames)

{ "query" : { "bool" : { "must" : [ {"bool" : {"must_not" : [ {"terms" : {"name" : ["?","?"]}} ] } } ] } }}

NotIn

findByNameNotIn(Collectionnames)

{"query": {"bool": {"must": [{"query_string": {"query": "NOT("?" "?")", "fields": ["name"]}}]}}}

True

findByAvailableTrue

{ "query" : { "bool" : { "must" : [ { "query_string" : { "query" : "true", "fields" : [ "available" ] } } ] } }}

False

findByAvailableFalse

{ "query" : { "bool" : { "must" : [ { "query_string" : { "query" : "false", "fields" : [ "available" ] } } ] } }}

OrderBy

findByAvailableTrueOrderByNameDesc

{ "query" : { "bool" : { "must" : [ { "query_string" : { "query" : "true", "fields" : [ "available" ] } } ] } }, "sort":[{"name":{"order":"desc"}}] }

Exists

findByNameExists

{"query":{"bool":{"must":[{"exists":{"field":"name"}}]}}}

IsNull

findByNameIsNull

{"query":{"bool":{"must_not":[{"exists":{"field":"name"}}]}}}

IsNotNull

findByNameIsNotNull

{"query":{"bool":{"must":[{"exists":{"field":"name"}}]}}}

IsEmpty

findByNameIsEmpty

{"query":{"bool":{"must":[{"bool":{"must":[{"exists":{"field":"name"}}],"must_not":[{"wildcard":{"name":{"wildcard":"*"}}}]}}]}}}

IsNotEmpty

findByNameIsNotEmpty

{"query":{"bool":{"must":[{"wildcard":{"name":{"wildcard":"*"}}}]}}}

除了这种方式,我们还可以通过@Query注解的方式来使用Elasticsearch原生的查询DSL语句:

public interface EsProductRepository extends ElasticsearchRepository<EsProduct, Long> {@Query("{"bool" : {"must" : {"field" : {"name" : " ? 0"}}}}")Page<EsProduct> findByName(String name, Pageable pageable);
}

1.3 分页工具:Pageable、Page 

1.3.1 Page接口

Page接口表示一个分页查询的结果集,它包含了查询结果的分页信息和数据。Page接口继承自Slice接口,因此也有相应的的分页信息方法。下面我们来看看相应的类图:

1.3.2 Pageable接口

Pageable接口用于表示分页查询的请求信息,它包含了分页查询的相关参数,例如页数、每页记录数、排序方式等。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.springframework.data.domain;import java.util.Optional;
import org.springframework.util.Assert;public interface Pageable {static Pageable unpaged() {return Unpaged.INSTANCE;}static Pageable ofSize(int pageSize) {return PageRequest.of(0, pageSize);}default boolean isPaged() {return true;}default boolean isUnpaged() {return !this.isPaged();}//返回请求的页数int getPageNumber();//放回每页包含的记录数int getPageSize();//根据底层页面和页面大小返回偏移量long getOffset();//返回排序信息Sort getSort();default Sort getSortOr(Sort sort) {Assert.notNull(sort, "Fallback Sort must not be null");return this.getSort().isSorted() ? this.getSort() : sort;}Pageable next();//返回前一页的 Pageable 对象,如果当前页已经是第一页则返回第一页。Pageable previousOrFirst();//返回第一页的 Pageable 对象Pageable first();//返回一个新的 Pageable 对象,指定请求的页数。Pageable withPage(int pageNumber);//判断是否有前一页。boolean hasPrevious();default Optional<Pageable> toOptional() {return this.isUnpaged() ? Optional.empty() : Optional.of(this);}
}

这里我们再回顾一下函数式接口的知识哈~

1.4 函数式接口 

在Java8之后为了兼容加进来的lambda表达式,引入了一个函数式接口的概念,函数式接口指的是在接口中只有一个抽象方法。同时需要注意的是,从Java8之后定义接口中是可以存在方法体的,但必须是default默认方法和static静态方法。

二者区别

  • 默认方法允许在接口中提供方法的默认实现,而不需要实现该接口的所有类都去覆盖这个方法,默认方法使得接口的修改更加灵活,因为可以在接口中添加新的方法,而不需要改变现有的实现类;
  • 静态方法可以通过接口的名称直接调用,无需实例化接口的实现类,通常用于提供一些与接口相关的工具方法或辅助方法;

我们可以通过@FunctionalInterface注解来告诉编译器函数式接口的声明,一旦加上该注解,接口中就最多只会有一个抽象方法! 

1.5 常用注解

Spring Data中常用的操作Elasticsearch的注解主要有四个:@Document、@Setting、@Id和@Field。

注解名称作用参数说明

@Document

用于标识映射到Elasticsearch文档上的领域对象

indexName:索引库的名字,MySQL中数据库的概念

@Setting

ES的配置注解

shards:默认分片数
replicas:默认副本数量

@Id

用于标识文档的ID,文档可以认为是MySQL中表行的概念

无参数

@Field

用于标识文档中的字段,可以认为是MySQL中列的概念

type:文档中字段的类型
index:是否建立倒排索引
store:是否进行存储
analyzer:分词器的名称

Field中常用的Type类型

public enum FieldType {Auto("auto"), //自动判断字段类型Text("text"), //会进行分词并建了索引的字符类型Keyword("keyword"), //不会进行分词建立索引的类型Long("long"), //Integer("integer"), //Short("short"), //Byte("byte"), //Double("double"), //Float("float"), //Date("date"), //Boolean("boolean"), //Object("object"), //Nested("nested"), //嵌套对象类型Ip("ip"), //
}

1.6 Elasticsearch实现搜索的流程

在最开始我们其实比较清晰的弄清楚了ES的整合流程,这里荔枝梳理一下一些重要的部分和自己踩的坑。

dao层

dao层其实是比较重要的一环,我们需要将数据库中的数据查询出来,由于商品的信息比较负载,还涉及到嵌套的对象,所以这部分的需求需要自己写一个mapper文件来实现mybatis操作。 

/*** @auther lzddl* @description 搜索系统中的商品管理自定义Dao,根据id来将数据库中的对应商品数据加载到EsProduct对象中*/
public interface EsProductDao {List<EsProduct> getAllEsProductList(@Param("id") Long id);
}

server层的实现类

        这个部分其实是比较重要的,我们可以来看看关系的类图,有关ES的操作其实就在EsProductRepository接口中,有关数据库数据导入的操作就在EsProductDao中,而EsProductService其实就作为control下面直接操作的ES搜索方法。

EsProductServiceImpl 

/*** @auther lzddl* @description 搜索商品管理Service实现类*/
@Service
public class EsProductServiceImpl implements EsProductService {private static final Logger LOGGER = LoggerFactory.getLogger(EsProductServiceImpl.class);@Autowiredprivate EsProductDao productDao;@Autowiredprivate EsProductRepository productRepository;@Overridepublic int importAll() {List<EsProduct> esProductList = productDao.getAllEsProductList(null);Iterable<EsProduct> esProductIterable = productRepository.saveAll(esProductList);Iterator<EsProduct> iterator = esProductIterable.iterator();int result = 0;while (iterator.hasNext()) {result++;iterator.next();}return result;}@Overridepublic void delete(Long id) {productRepository.deleteById(id);}@Overridepublic EsProduct create(Long id) {EsProduct result = null;List<EsProduct> esProductList = productDao.getAllEsProductList(id);if (esProductList.size() > 0) {EsProduct esProduct = esProductList.get(0);result = productRepository.save(esProduct);}return result;}@Overridepublic void delete(List<Long> ids) {if (!CollectionUtils.isEmpty(ids)) {List<EsProduct> esProductList = new ArrayList<>();for (Long id : ids) {EsProduct esProduct = new EsProduct();esProduct.setId(id);esProductList.add(esProduct);}productRepository.deleteAll(esProductList);}}@Overridepublic Page<EsProduct> search(String keyword, Integer pageNum, Integer pageSize) {Pageable pageable = PageRequest.of(pageNum, pageSize);return productRepository.findByNameOrSubTitleOrKeywords(keyword, keyword, keyword, pageable);}}

安装ES踩的坑1:路径不要有空格!  

不然你就会看到这样的报错呜呜呜~~~ 

安装ES踩的坑2:中文分词器的解压路径一定要在plugin/analysis-ik下!


 总结

        看懂脚手架的源码+弄清楚边角知识+梳理文章真的很耗时,学的好慢不过确实有效果哈哈哈,最后也要感谢宏哥和各位大佬博客的帮助!希望荔枝能继续加快脚步给大家输出更有质量的博文,最后一起加油吧~~~

今朝已然成为过去,明日依然向往未来!我是荔枝,在技术成长之路上与您相伴~~~

如果博文对您有帮助的话,可以给荔枝一键三连嘿,您的支持和鼓励是荔枝最大的动力!

如果博文内容有误,也欢迎各位大佬在下方评论区批评指正!!!

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【轻松玩转MacOS】故障排除篇

引言 在使用 MacOS 时&#xff0c;遇到故障是在所难免的。不要担心&#xff0c;这篇文章将为您提供一些常见的故障排除步骤&#xff0c;并介绍如何联系苹果的支持团队寻求帮助。让我们一起来看看吧&#xff01; 一、常见的故障排除步骤 1.1 网络连接问题 如果你发现你的Mac…

Redis(三)

文章目录 一、单节点Redis的问题&#xff08;一&#xff09;数据丢失&#xff08;二&#xff09;并发能力问题&#xff08;三&#xff09;存储能力问题&#xff08;四&#xff09;故障恢复问题 二、Redis持久化&#xff08;一&#xff09;RDB1、RDB是什么2、rdb配置3、手动触发…

面试题:MySQL 中 InnoDB 的索引结构以及使用 B+ 树实现索引的原因

文章目录 概述表空间索引结构为什么使用 B 树实现索引&#xff1f;总结 概述 在 MySQL 的众多存储引擎中&#xff0c;InnoDB 是最常用的存储引擎&#xff0c;也是 MySQL 现阶段唯一免费支持事务机制的存储引擎。在本文中&#xff0c;我们以 InnoDB 为例&#xff0c;介绍 MySQL…

计算机丢失msvcr120.dll解决办法,快速解决的力量文件丢失

关于计算机丢失msvcr120.dll应该很多朋友都遇到过&#xff0c;本篇文章将和大家探讨一下关于计算机丢失msvcr120.dll解决办法。同时想和大叫一起了解一下msvcr120.dll文件到底有什么作用&#xff0c;是不是必须将其恢复。 一.msvcr120.dll的作用 msvcr120.dll文件时电脑中的一…

工业读写器如何选型?

随着工业自动化的迅速发展&#xff0c;库存管理、生产流程、质量管理等传统工作人工工作也逐渐由各种智能设备来替代管理。RFID技术作为非接触式数据传输的通信方式&#xff0c;也常常应用在工业场合之中。具体工业RFID读写器如何选型&#xff0c;有哪些选择要点呢?ANDEAWELL国…

尚品甄选2023全新SpringBoot+SpringCloud企业级微服务项目

最适合新手入门的SpringBootSpringCloud企业级微服务项目来啦&#xff01;如果你已经学习了Java基础、SSM框架、SpringBoot、SpringCloud&#xff0c;想找一个项目来实战练习&#xff1b;或者你刚刚入行&#xff0c;需要可以写到简历中的微服务架构项目&#xff01; 项目采用前…

基于小波神经网络的网络流量预测算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022A 3.部分核心程序 ........................................................... %% 总流量数据 input(:,1)dat…

Go:关于 Channel

文章目录 写在前面内容模型图与代码发送流程接收流程 写在前面 本篇主要是通过 Channel 的模型图&#xff0c;对 Channel 的原理做一个基本的概述 内容 模型图与代码 我们先来看下 Channel 的模型图&#xff1a; 以上的图是一个简要的模型图&#xff0c;意味着丢失一些细节…

腾讯云2核4G轻量服务器5M带宽支持多少人同时在线?

腾讯云轻量2核4G5M带宽服务器支持多少人在线访问&#xff1f;5M带宽下载速度峰值可达640KB/秒&#xff0c;阿腾云以搭建网站为例&#xff0c;假设优化后平均大小为60KB&#xff0c;则5M带宽可支撑10个用户同时在1秒内打开网站&#xff0c;从CPU内存的角度&#xff0c;网站程序效…

从零开始学习:如何使用Selenium和Python进行自动化测试?

安装selenium 打开命令控制符输入&#xff1a;pip install -U selenium 火狐浏览器安装firebug&#xff1a;www.firebug.com&#xff0c;调试所有网站语言&#xff0c;调试功能 Selenium IDE 是嵌入到Firefox 浏览器中的一个插件&#xff0c;实现简单的浏览器操 作的录制与回…

AI:10-基于TensorFlow的玉米病害识别

玉米是世界上最重要的粮食作物之一,然而,玉米病害对其产量和质量造成了严重威胁。传统的病害识别方法通常依赖于人工观察和经验判断,效率低下且易受主观因素影响。近年来,基于深度学习的图像识别技术在农业领域取得了显著进展,为玉米病害的快速、准确识别提供了新的解决方…

干货!SRC漏洞挖掘项目实战经验分享

目录 一、hunter上搜索web.title”nacos”&#xff0c;查找中国境内的资产&#xff0c;定位到两个地址。 二、访问一下8086端口&#xff0c;界面很明显是nacos&#xff0c;直接抓包&#xff0c;创建用户。 三、登录网站&#xff0c;里面看到配置管理。 四、查看下redis.yml…

yolov8剪枝实践

本文使用的剪枝库是torch-pruning &#xff0c;实验了该库的三个剪枝算法GroupNormPruner、BNScalePruner和GrowingRegPruner。 安装使用 安装依赖库 pip install torch-pruning 把 https://github.com/VainF/Torch-Pruning/blob/master/examples/yolov8/yolov8_pruning.py&…

使用wireshark解析ipsec esp包

Ipsec esp包就是ipsec通过ike协议协商好后建立的通信隧道使用的加密包&#xff0c;该加密包里面就是用户的数据&#xff0c;比如通过的语音等。 那么如何将抓出来的esp包解析出来看呢&#xff1f; 获取相关的esp的key信息. 打开wireshark -> edit->preferences 找到pr…

【手写数字识别】GPU训练版本

SVM Adaboost Bagging 完整代码 I import torch import torch.nn.functional as F from torch.utils.data import DataLoader, TensorDataset from torchvision import transforms, datasets import matplotlib.pyplot as plt# 超参数 batch_size 64 num_epochs 10# 数据…

安卓三防平板在行业应用中有哪些优势

在工业维修和检测中&#xff0c;安卓三防平板的应用也十分广泛。它可以搭载各种专业软件和工具&#xff0c;帮助工人们进行设备故障排查和维护&#xff0c;降低了维修成本和停机时间。 一、产品卖点&#xff1a; 1. 防水性能&#xff1a;该手持平板采用了防水设计&#xff0c;…

国标28181 开源WVP-PRO项目部署

感谢大牛的开源框架 https://doc.wvp-pro.cn/#/ 一.直接使用源码部署&#xff08;在linux&#xff09; -- 安装环境 yum install -y java-1.8.0-openjdk.x86_64 git maven nodejs npm -- 下载源码-wvp项目 git clone https://gitee.com/pan648540858/wvp-GB28181-pro.git ---…

MyBatis-Plus为简化开发而生

简介 MyBatis-Plus 简称 MP是一个 MyBatis 的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。 他们的愿景是成为 MyBatis 最好的搭档&#xff0c;就像魂斗罗中的 1P、2P&#xff0c;基友搭配&#xff0c;效率翻倍。 特性 无…

【ARM CoreLink 系列 6 -- DMC-400控制器简介】

文章目录 1.1 DMC-400 简介1.1.1 DFI&#xff08;DDR PHY Interface&#xff09;1.1.2 DFI 接口组1.1.3 DMC-400 兼容协议1.1.4 DMC-400 特性1.1.5 DMC-400 Interface 1.1 DMC-400 简介 DMC-400是一个由ARM开发、测试和授权的动态内存控制器&#xff0c;同时 DMC-400也是一个符…

如何实现 Es 全文检索、高亮文本略缩处理

如何实现 Es 全文检索、高亮文本略缩处理 前言技术选型JAVA 常用语法说明全文检索开发高亮开发Es Map 转对象使用核心代码 Trans 接口&#xff08;支持父类属性的复杂映射&#xff09;Trans 接口的不足真实项目落地效果结语 前言 最近手上在做 Es 全文检索的需求&#xff0c;类…