ElasticSearch教程(详解版)

        本篇博客将向各位详细介绍elasticsearch,也算是对我最近学完elasticsearch的一个总结,对于如何在Kibana中使用DSL指令,本篇文章不会进行介绍,这里只会介绍在java中如何进行使用,保证你看完之后就会在项目中进行上手,那我们开始本篇教程吧~

什么是ElasticSearch

  • Elasticsearch,基于lucene.分布式的Restful实时搜索和分析引擎(实时)
  • 分布式的实时文件存储,每个字段都被索引并可被搜索
  • 高扩展性,可扩展至上百台服务器,处理PB级结构化或非结构化数据
  • Elasticsearch用于全文检索,结构化搜索,分析/合并使用

ElasticSearch是如何做到这么快的

  • 分布式存储:ElasticSearch把数据存储在多个节点上,从而减少单个节点的压力,从而提高性能
  • 索引分片:ElasticSearch把索引分成多个分片,这样可以让查询操作并行化,从而提高性能
  • 全文索引:ElasticSearch把文档转换成可搜索的结构化数据,从而提高效率
  • 倒排索引:ElasticSearch将文档进行分词处理,把每个词在哪个文档中出现过进行映射,并存储这些信息,从而在搜索时,查询这些分词和搜索这些分词存在在哪些文档中,提高查询效率
  • 异步请求处理:ElasticSearch能够在请求到达时立即返回,避免长时间等待,提高效率

全文索引和倒排索引是什么

        全文检索是指计算机索引程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。这个过程类似于通过字典中的检索字表查字的过程。全文搜索搜索引擎数据库中的数据。

  • 优点:

    • 可以给多个字段创建索引

    • 根据索引字段搜索、排序速度非常快

  • 缺点:

    • 根据非索引字段,或者索引字段中的部分词条查找时,只能全表扫描。

        倒排索引就和传统的索引结构相反,传统的索引是由文档组成的,每个文档中都包含了若干个词汇,然后根据这些词汇简历索引。而倒排索引则与其相反,倒排索引由词汇构成,每个词汇对应若干个文档,然后根据这些文档建立索引。

  • 优点:

    • 根据词条搜索、模糊搜索时,速度非常快

  • 缺点:

    • 只能给词条创建索引,而不是字段

    • 无法根据字段做排序

ElasticSearch和Mysql之间的映射关系

Mysql类型       ElasticSearch类型说明
VARCHARtext、keyword根据是否需要使用全文搜索或精确搜索选择使用text或keyword
CHAR        

keyword                       

通常映射为keyword,因为它们存储较短的、不经常变化的字符序列
BLOB/TEXT        text大文本块使用text,适用于全文检索
INT,BIGINTlong大多数整数型使用long,以支持更大的数值
TINYINTbyte较小的整数可以映射为byte类型
DECIMAL,FLOAT,DOUBLEdouble,float
DATE,DATETIME,TIMESTAMPdate
BOOLEANboolean

倒排索引建立步骤

es中建立倒排索引需要两步,首先对文档进行分词,其次建立倒排索引

分词

        分词的意思大概就是对文档中的数据通过es的分词器进行分割成一个个词项,比如 “我是银氨溶液” 这句话,经过分词过后就是 “我”、“是”、“银氨”、“溶液”,当然es的分词器分为ik_smart分词器和ik_max_word分词,所以实际操作时这句话会被分解为不同的词段。

es中的一些概念

        文档

        elasticsearch是面向文档(Document)存储的,可以是数据库中的一条商品数据,一个订单信息。文档数据会被序列化为json格式后存储在elasticsearch中。

        字段

Json文档中往往包含很多的字段(Field),类似于数据库中的列。

        索引

索引(Index),就是相同类型的文档的集合。因此,我们可以把索引当做是数据库中的表。

        映射

        数据库的表会有约束信息,用来定义表的结构、字段的名称、类型等信息。因此,索引库中就有映射(mapping),是索引中文档的字段约束信息,类似表的结构约束。

对照图表:

MySQLElasticsearch说明
TableIndex索引(index),就是文档的集合,类似数据库的表(table)
RowDocument文档(Document),就是一条条的数据,类似数据库中的行(Row),文档都是JSON格式
ColumnField字段(Field),就是JSON文档中的字段,类似数据库中的列(Column)
SchemaMappingMapping(映射)是索引中文档的约束,例如字段类型约束。类似数据库的表结构(Schema)
SQLDSLDSL是elasticsearch提供的JSON风格的请求语句,用来操作elasticsearch,实现CRUD

RestAPI

首先,在这篇文章中不会将所有api都介绍完,所以这了贴上官方文档的地址,以共各位查看:

ElasticSearch官方文档

这里需要先引入es的依赖

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

同时,你需要在pom文件中修改es的版本和你本地的一样

 然后,我们需要把es注入到spring容器中

@Configuration
public class ElasticSearchClientConfig {

    @Bean
    public RestHighLevelClient restHighLevelClient(){
        RestHighLevelClient client=new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost("127.0.0.1", 9200, "http")
                )
        );
        return client;
    }
}

 准备工作完成之后就可以开始接下来的学习啦~

索引的CRUD操作

索引的操作较为简单,而且项目中实际都是对文档进行操作,所以我这里贴出索引的相关操作代码,并做出解释,各位可以了解一下

 @Autowired
    @Qualifier("restHighLevelClient")
    private RestHighLevelClient client;

    //    测试索引的创建  Request
    @Test
    void testCreateIndex() throws Exception {
//        1、创建索引请求
        CreateIndexRequest request = new CreateIndexRequest("yinan_index");
//       2、客户端执行请求,请求后获得响应
        CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);
        System.out.println(createIndexResponse);
    }

    //    测试获取索引
    @Test
    void testGetIndex() throws IOException {
        GetIndexRequest getIndex = new GetIndexRequest("yinan_index");
        boolean exists = client.indices().exists(getIndex, RequestOptions.DEFAULT);
        System.out.println(exists);
    }

    //    删除索引
    @Test
    void testDeleteIndex() throws Exception {
        DeleteIndexRequest request = new DeleteIndexRequest("yinan_index");
        AcknowledgedResponse delete = client.indices().delete(request, RequestOptions.DEFAULT);
        System.out.println(delete.isAcknowledged());
    }

其中indices中包含了操作索引库的所有方法,在创建索引的时候如果有多个字段,可以提前写好 一个字符串常量,例如:

   public static final String MAPPING_TEMPLATE = "{\n" +
            "  \"mappings\": {\n" +
            "    \"properties\": {\n" +
            "      \"id\": {\n" +
            "        \"type\": \"keyword\"\n" +
            "      },\n" +
            "      \"name\":{\n" +
            "        \"type\": \"text\",\n" +
            "        \"analyzer\": \"ik_max_word\",\n" +
            "        \"copy_to\": \"all\"\n" +
            "      },\n" +
            "      \"address\":{\n" +
            "        \"type\": \"keyword\",\n" +
            "        \"index\": false\n" +
            "      },\n" +
            "      \"price\":{\n" +
            "        \"type\": \"integer\"\n" +
            "      },\n" +
            "      \"score\":{\n" +
            "        \"type\": \"integer\"\n" +
            "      },\n" +
            "      \"brand\":{\n" +
            "        \"type\": \"keyword\",\n" +
            "        \"copy_to\": \"all\"\n" +
            "      },\n" +
            "      \"city\":{\n" +
            "        \"type\": \"keyword\",\n" +
            "        \"copy_to\": \"all\"\n" +
            "      },\n" +
            "      \"starName\":{\n" +
            "        \"type\": \"keyword\"\n" +
            "      },\n" +
            "      \"business\":{\n" +
            "        \"type\": \"keyword\"\n" +
            "      },\n" +
            "      \"location\":{\n" +
            "        \"type\": \"geo_point\"\n" +
            "      },\n" +
            "      \"pic\":{\n" +
            "        \"type\": \"keyword\",\n" +
            "        \"index\": false\n" +
            "      },\n" +
            "      \"all\":{\n" +
            "        \"type\": \"text\",\n" +
            "        \"analyzer\": \"ik_max_word\"\n" +
            "      }\n" +
            "    }\n" +
            "  }\n" +
            "}";

 然后将新增索引中的代码修改成以下:

文档的CRUD操作

对于文档这里将重点介绍查询的相关方法,其它操作只做简单介绍。

查询操作
MatchAll
/**
     * 查询全部
     */
    @Test
    void testMatchAll() throws IOException {
        //1.准备request
        SearchRequest request = new SearchRequest("hotel");
        //2.准备参数
        request.source().query(QueryBuilders.matchAllQuery());

        //3.发起请求得到响应结果
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);

        //4.解析响应
        handleResponse(response);
    }

结果如下:

 从结果我们也可以看到这个api是查询所有数据的方法,但是控制台只显示了10条数据,这是因为这个方法自动进行分页处理,每页10条数据。

Match
   /**
     * 全文检索
     */
    @Test
    void testMatch() throws IOException {
        //1.准备request
        SearchRequest request = new SearchRequest("hotel");
        //2.准备参数
        request.source().query(QueryBuilders.matchQuery("all","如家"));
        //3.发起请求得到响应结果
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);

        //4.解析响应
        handleResponse(response);
    }

结果:

match用来做基本的模糊匹配,在es中会对文本进行分词,在match查询的时候也会对查询条件进行分词,然后通过倒排索引找到匹配的数据。

term
 @Test
    void testMatch() throws IOException {
        //1.准备request
        SearchRequest request = new SearchRequest("hotel");
        //2.准备参数
//        request.source().query(QueryBuilders.matchQuery("all","如家"));
        request.source().query(QueryBuilders.termQuery("city","北京"));
        //3.发起请求得到响应结果
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);

        //4.解析响应
        handleResponse(response);
    }

结果:

 从结果来看,term是做精确查询的,所以一般可以用在查询某个具体的属性的时候

multiMatchQuery
 @Test
    void testMatch() throws IOException {
        //1.准备request
        SearchRequest request = new SearchRequest("hotel");
        //2.准备参数
//        request.source().query(QueryBuilders.matchQuery("all","如家"));
//        request.source().query(QueryBuilders.termQuery("city","北京"));
        request.source().query(QueryBuilders.multiMatchQuery("如家", "city", "name"));
        //3.发起请求得到响应结果
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //4.解析响应
        handleResponse(response);
    }

 结果:

    multiMatchQuery接受两个参数,一个是text,一个是fieldname,前者表示要查询的内容,后者表示要在哪些字段中进行查询,如果后者中的数据只有一个,那该方法和matchall一致,如果后者有多个,那查询的结果必须要满足其中的一个。
rangeQuery
 @Test
    void testMatch() throws IOException {
        //1.准备request
        SearchRequest request = new SearchRequest("hotel");
        //2.准备参数
//        request.source().query(QueryBuilders.matchQuery("all","如家"));
//        request.source().query(QueryBuilders.termQuery("city","北京"));
//        request.source().query(QueryBuilders.multiMatchQuery("如家", "city", "name"));
                request.source().query(QueryBuilders.rangeQuery("price").gte(100).lte(150));
        //3.发起请求得到响应结果
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //4.解析响应
        handleResponse(response);
    }

结果:

该方法主要做范围查询,相当于sql语句中的between....and...

布尔查询
/**
     * 布尔查询
     * @throws IOException
     */
    @Test
    void testBool() throws IOException {
        //1.准备request
        SearchRequest request = new SearchRequest("hotel");
        //2.准备参数
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.must(QueryBuilders.termQuery("city","北京"));
        boolQuery.filter(QueryBuilders.rangeQuery("price").lte(300));

        request.source().query(boolQuery);

        //3.发起请求得到响应结果
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        System.out.println( "========"+response.getHits());

        //4.解析响应
        handleResponse(response);

    }


 /**
     * 解析响应结果
     * @param response
     */
    private void handleResponse(SearchResponse response) {
        SearchHits searchHits = response.getHits();
        //总条数
        long total = searchHits.getTotalHits().value;

        System.out.println("共搜索到"+total+"条数据");
        //文档数组
        SearchHit[] hits = searchHits.getHits();
        //遍历
        for (SearchHit hit : hits){
            //获取文档source
            String json = hit.getSourceAsString();
            //反序列化
            HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
            //获取高亮结果
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            if(!CollectionUtils.isEmpty(highlightFields)){
                //根据字段名获取高亮结果
                HighlightField highlightField = highlightFields.get("name");
                if(highlightField != null){
                    //获取高亮值
                    String name = highlightField.getFragments()[0].string();
                    //替换
                    hotelDoc.setName(name);
                }
            }
            System.out.println("hotDoc = "+hotelDoc);
        }

这里简单说一下怎么得到的 handleResponse函数

通过以上图片我们就不难看出 response的响应结构,因此我们就可以具体推出相关信息,所以没有学习过在Kibana上使用DSL指令的朋友可以先去学习一下,然后再来运用到java中事半功倍。

当然,如果你只需要获取数据和总条数,可以修改成以下形式:

 private PageResult handleResponse(SearchResponse response) {
        SearchHits hits = response.getHits();
        long total = hits.getTotalHits().value;
        SearchHit[] searchHits = hits.getHits();
        List<HotelDoc> hotels = new ArrayList<>();
        for (SearchHit searchHit : searchHits) {
            String source = searchHit.getSourceAsString();
//            反序列化
            HotelDoc hotelDoc = JSON.parseObject(source, HotelDoc.class);
            hotels.add(hotelDoc);
        }
        return new PageResult(total,hotels);
    }
分页和排序 对结果的处理
/**
     * 分页和排序 对结果的处理
     */
    @Test
    void testPageAndSort() throws IOException {

        int page = 1,size = 5;
        //1.准备request
        SearchRequest request = new SearchRequest("hotel");
        //2.准备参数
        request.source().query(QueryBuilders.matchAllQuery());
        //排序
        request.source().sort("price", SortOrder.ASC);
        //分页
        request.source().from((page-1)*size).size(size);

        //3.发起请求得到响应结果
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);

        //4.解析响应
        handleResponse(response);
    }

当然,还有其它一些api这里还没有介绍到,各位可以去官网进行查看详细文档说明~

 添加文档
@Data
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {
    private String name;
    private Integer age;
}
 @Test
    void testAddDocument() throws IOException {
//        1、创建对象
        User user = new User("yinan", 20);
//        2、创建请求
        IndexRequest request = new IndexRequest("yinan_index");
//        规则  put /yinan_index/_doc/1
        request.id("1");
        request.timeout(TimeValue.timeValueSeconds(1));
        request.timeout("1s");
//        将数据放入请求  json
        request.source(JSON.toJSONString(user), XContentType.JSON);
//        客户端发送请求,获取相应的结果
        IndexResponse indexResponse = client.index(request, RequestOptions.DEFAULT);

        System.out.println(indexResponse.toString());
        System.out.println(indexResponse.status());  //对应我们命令返回状态

    }
批量添加文档
 @Test
    void testBulkRequest() throws Exception {
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout("10s");
        ArrayList<User> userList = new ArrayList<>();
        userList.add(new User("yinan1", 21));
        userList.add(new User("yinan1", 21));
        userList.add(new User("yinan3", 26));
        userList.add(new User("yinan4", 24));
        userList.add(new User("yinan5", 27));
        userList.add(new User("yinan12", 20));

        for (int i = 0; i < userList.size(); i++) {
            bulkRequest.add(
                    new IndexRequest("yinan_index")
                            .id("" + (i + 1))
                            .source(JSON.toJSONString(userList.get(i)), XContentType.JSON)
            );
        }
        BulkResponse itemResponses = client.bulk(bulkRequest, RequestOptions.DEFAULT);
        System.out.println(itemResponses.hasFailures());
    }
修改文档
 @Test
    void testUpdateDocument() throws Exception {
        UpdateRequest request = new UpdateRequest("yinan_index", "1");
        request.timeout("1s");
        User user = new User("yinan_update", 21);
        request.doc(JSON.toJSONString(user), XContentType.JSON);
        UpdateResponse updateResponse = client.update(request, RequestOptions.DEFAULT);
        System.out.println(updateResponse.status());
    }
删除文档
   @Test
    void testDeleteDocument() throws Exception {
        DeleteRequest request = new DeleteRequest("yinan_index", "1");
        request.timeout("1s");
        DeleteResponse deleteResponse = client.delete(request, RequestOptions.DEFAULT);
        System.out.println(deleteResponse.status());
    }

以上就是对es部分api的讲解,当然只看api使用是远远不够的,所以我们需要做一个小训练来巩固我们学习的东西。

资料已经置顶在本篇博客,有需要的请自取~

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

为何选择 MindMapper

MindMapper是一款专业的可视化思维导图软件&#xff0c;通过智能绘图方法&#xff0c;在管理信息和 处理工作流程中&#xff0c;帮助提高组织、审查、合作、分享和交流能力。 企业创造力 在企业界&#xff0c;MindMapper思维导图软件可以提高生产力和沟通效果&#xff0c;以及…

复试不考机试,初试300分以上,上岸稳了?东北林业大学计算机考研考情分析!

东北林业大学&#xff08;Northeast Forestry University&#xff09;&#xff0c;简称东北林大&#xff08;NEFU&#xff09;&#xff0c;位于黑龙江省哈尔滨市&#xff0c;是一所以林科为优势、林业工程为特色的中华人民共和国教育部直属高校&#xff0c;由教育部、国家林业局…

LIO-EKF: 运行数据UrbanNav与mid360设备详细教程

一、代码连接 代码下载连接&#xff1a; YibinWu/LIO-EKF: Maybe the simplest LiDAR-inertial odometry that one can have. (github.com) 编译步骤&#xff1a; cd srcgit clone gitgithub.com:YibinWu/LIO-EKF.gitcatkin_makesource devel/setup.bash 运行步骤&#xff1a; …

2024年6月1日 (周六) 叶子游戏新闻

Embracer探讨单机游戏大作涨价超过70美元的可能性在Embracer集团等待公布新公司名称的同时&#xff0c;他们对游戏大作的价格上涨做出了评论。几年来&#xff0c;游戏大作的价格已经达到了70美元的门槛。Embracer集团的CEO Lars Wingefors在采访中表示&#xff0c;电子游戏行业…

STM32 定时器与PWM的LED控制

学习目标&#xff1a; 1. 使用定时器的某一个通道控制LED周期性亮灭&#xff1b; 2. 采用定时器PWM模式&#xff0c;让 LED 以呼吸灯方式渐亮渐灭。 一、定时器 1、STM32定时器介绍 STMicroelectronics是STM32微控制器中的重要块&#xff0c;具有丰富的外设和功能&#xff0…

纯Java实现Google地图的KMZ和KML文件的解析

目录 前言 一、关于KMZ和KML 1、KMZ是什么 2、KML是什么 二、Java解析实例 1、POM.xml引用 2、KML 基类定义 3、空间对象的定义 4、Kml解析工具类 三、KML文件的解析 1、KML解析测试 2、KMZ解析测试 四、总结 前言 今天是六.一儿童节&#xff0c;在这里祝各位大朋友…

网络运维的重要性

一、介绍 网络运维&#xff0c;英文名为Network Operations (NetOps)&#xff0c;指的是负责维护和管理企业或组织内部网络设备和系统的团队或个人。网络运维的主要目标是确保网络的稳定运行和高效性能&#xff0c;以满足企业或组织的需求。 网络运维工作涵盖了多个方面&…

5.算法讲解之-二分查找(简单易懂)

1.简介 1.二分查找的思路简单易懂&#xff0c;较难的是如何处理查找过程中的边界条件&#xff0c;当较长时间没写二分查找的时候就容易忘记如何处理边界条件。 2.只有多写代码&#xff0c;多做笔记就不易忘记边界条件 2.算法思路 正常查找都是从头到尾查找一个数字是否在数组中…

WIFI 万[néng]钥匙 v5.0.10/v4.9.80 SVIP版!

WiFi Master Key v5.0.10/v4.9.80 WIFI万[Nng]钥匙APP是一款专业的网络连接工具&#xff0c;设计宗旨在于为用户提供方便快捷的WiFi接入方案。本应用集成了覆盖全国的大量免费WiFi热点信息&#xff0c;确保用户能够在不同地区快速而稳定地连接到互联网。此外&#xff0c;该应用…

UMLChina为什么叒要翻译《分析模式》?

UMLChina受机械工业出版社委托&#xff0c;重新翻译《分析模式》。 Martin Fowler的“Analysis Patterns&#xff0c;Reusable Object Models”&#xff0c;原书出版于1997年&#xff0c;至今为止未出第2版。 2004年&#xff0c;机械工业出版社出版该书中译本《分析模式》。 …

Llama 3-V: 比GPT4-V小100倍的SOTA

大模型技术论文不断&#xff0c;每个月总会新增上千篇。本专栏精选论文重点解读&#xff0c;主题还是围绕着行业实践和工程量产。若在某个环节出现卡点&#xff0c;可以回到大模型必备腔调重新阅读。而最新科技&#xff08;Mamba&#xff0c;xLSTM,KAN&#xff09;则提供了大模…

python猜数字游戏

猜数字游戏 计算机随机产生一个1~100的随机数&#xff0c;人输入自己猜的数字&#xff0c; 计算机给出对应的提示“大一点”&#xff0c;”小一点“或”恭喜你猜对了“&#xff0c;直到猜中为止。 如果猜的次数超过7次&#xff0c;计算机温馨提示“智商余额明显不足” import …

K8s(Kubernetes)常用命令

大家好&#xff0c;当谈及容器编排工具时&#xff0c;Kubernetes&#xff08;常简称为K8s&#xff09;无疑是当今最受欢迎和广泛使用的解决方案之一。作为一个开源的容器编排平台&#xff0c;Kubernetes 提供了丰富的功能&#xff0c;可以帮助开发人员和运维团队管理、部署和扩…

能耗监测系统在上海交通大学闵行校区理科实验楼群的设计与应用

引言 建筑能耗系统&#xff0c;除了基本的电力参数监测、配电系统的运行状况&#xff0c;更加关注能耗的去向。除了常规的园区楼层出线电能计量&#xff0c;还会涉及水&#xff0c;气等能耗计量。 针对上海交通大学闵行校区理科实验楼群能耗监测系统的具体要求&#xff0c;以…

小熊家务帮day8-day9 客户管理模块2 (用户定位,地址簿,实名认证,银行卡信息上传等功能)

客户管理模块 0.用户定位功能0.1 需求0.2 接口分析0.3 接口开发Controller层开发Service层开发 1.我的地址簿功能1.1 需求1.2 数据库设计1.3 新增地址簿1.3.1 接口设计1.3.2 接口开发Controller层开发Service层开发测试功能 1.4 地址簿查询1.4.1 接口设计1.4.2 接口开发Control…

游戏主播到底是为游戏宣传还是蹭游戏带来的热度

易采游戏网6月1日最新消息&#xff1a;近日知名游戏主播周淑怡在社交平台上发表了自己对《地下城与勇士》手游(简称DNF手游)的点评。作为一款拥有庞大粉丝基础的端游改编作品&#xff0c;DNF手游自发布以来便受到了广泛关注。而周淑怡的点评不仅聚焦于游戏体验本身&#xff0c;…

visual studis 安装教程

1、下载软件 2、直接安装。根据自己的需求选择需要的模板类型。 如果是.net环境&#xff0c;可以选择.net项目&#xff1b; 如果是c环境&#xff0c;可以选择c项目模板&#xff0c;多个模板可以同时并存。 3、选择C模板&#xff0c;然后重新启动项目。 我是小路&#xff0c;一枚…

Flutter基础 -- Dart 语言 -- 列表集合枚举

目录 1. 列表 List 1.1 初始 1.2 声明 1.2.1 自动 1.2.2 定长 1.2.3 生成数据 1.3 属性 1.4 方法 1.4.1 添加 1.4.2 查询 1.4.3 删除 1.4.4 Range 1.4.5 洗牌 1.4.6 排序 1.4.7 复制子列表 1.4.8 操作符 2. 集合 Map 2.1 初始 2.2 声明 2.2.1 松散 2.2.2 …

7、架构-架构的安全性

即使只限定在“软件架构设计”这个语境下&#xff0c;系统安全仍然是一 个很大的话题。我们谈论的计算机系统安全&#xff0c;不仅仅是指“防御系统 被黑客攻击”这样狭隘的安全&#xff0c;还至少应包括&#xff08;不限于&#xff09;以下这些问 题的具体解决方案。 认证&am…

小白教你搭建测试环境(docker部署版)

如何使用docker创建多数据库端口&#xff08;云服务器版&#xff09; 背景&#xff1a; 需要搭建一个测试环境&#xff0c;同时还需要不同的端口映射mysql端口。那么我采用的docker拉取mysql镜像&#xff0c;通过宿主机和docker容器端口映射完成。 准备一台云服务器服务器安装…