• Spring Data Elasticsearch集成SpringBoot 2.3.12.RELEASE


    官网

    Spring Data Elasticsearch基于Spring Data API简化 Elasticsearch 操作,将原始操作Elasticsearch 的客户端API进行封装。Spring Data为Elasticsearch 项目提供集成搜索引擎。Spring Data Elasticsearch POJO的关键功能区域为中心的模型与Elastichsearch交互文档和轻松地编写一个存储索引库数据访问层。

    spring-data-elasticsearch与ES、SpringBoot的对应关系

    在这里插入图片描述
    Spring Data通过注解来声明字段的映射属性,有下面的三个注解:

    • @Document 作用在类,标记实体类为文档对象,一般有两个属性
      indexName:对应索引库名称
      type:对应在索引库中的类型
      shards:分片数量,默认5
      replicas:副本数量,默认1
    • @Id 作用在成员变量,标记一个字段作为id主键
    • @Field 作用在成员变量,标记为文档的字段,并指定字段映射属性:
      type:字段类型,取值是枚举:FieldType
      index:是否索引,布尔类型,默认是true
      store:是否存储,布尔类型,默认是false
      analyzer:分词器名称

    本文使用的是:
    spring-boot(2.3.12.RELEASE)
    spring-data-elasticsearch(2.3.12.RELEASE)

    • 导入依赖

    spring-data-elasticsearch

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
    </dependency>
    
    • 1
    • 2
    • 3
    • 4

    全部pom

    <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.3.12.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.example</groupId>
        <artifactId>ES-test</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>ES-test</name>
        <description>ES-test</description>
        <properties>
            <java.version>1.8</java.version>
        </properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
            </dependency>
            <dependency>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-core</artifactId>
                <version>2.8.2</version>
            </dependency>
            <!-- junit 单元测试 -->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
            </dependency>
    
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 配置文件
    spring.elasticsearch.rest.uris=http://127.0.0.1:9200
    spring.elasticsearch.rest.read-timeout= 30
    spring.elasticsearch.rest.connection-timeout= 30
    
    • 1
    • 2
    • 3
    • 创建索引
    请求地址:http://localhost:9200/blog
    请求类型:PUT 
    请求体:
    
    {
        "settings": {
            "number_of_shards": 5,
            "number_of_replicas": 1
        },
        "mappings": {
            "properties": {
                "id":{
                    "type":"long"
                },
                "title": {
                    "type": "text"
                },
                "content": {
                    "type": "text"
                },
                "author":{
                    "type": "text"
                },
                "category":{
                    "type": "keyword"
                },
                "createTime": {
                    "type": "date",
                    "format":"yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd'T'HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss||epoch_millis"
                },
                "updateTime": {
                    "type": "date",
                    "format":"yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd'T'HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss||epoch_millis"
                },
                "status":{
                    "type":"integer"
                },
                "serialNum": {
                    "type": "keyword"
                }
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 编写实体类
    import com.fasterxml.jackson.annotation.JsonFormat;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import org.springframework.data.annotation.Id;
    import org.springframework.data.elasticsearch.annotations.DateFormat;
    import org.springframework.data.elasticsearch.annotations.Document;
    import org.springframework.data.elasticsearch.annotations.Field;
    import org.springframework.data.elasticsearch.annotations.FieldType;
    
    import java.util.Date;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Document(indexName = "blog", shards = 1, replicas = 1)
    public class Blog {
        //此项作为id,不会写到_source里边。
        @Id
        private Long blogId;
    
         @Field(type = FieldType.Text, analyzer = "ik_max_word")
        private String title;
    
         @Field(type = FieldType.Text, analyzer = "ik_max_word")
        private String content;
    
        @Field(type = FieldType.Text)
        private String author;
    
        //博客所属分类。
        @Field(type = FieldType.Keyword)
        private String category;
    
        //0: 未发布(草稿) 1:已发布 2:已删除
        @Field(type = FieldType.Integer)
        private int status;
    
        //序列号,用于给外部展示的id
        @Field(type = FieldType.Keyword)
        private String serialNum;
    
        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS")
        @Field(type= FieldType.Date, format= DateFormat.custom, pattern="yyyy-MM-dd HH:mm:ss.SSS")
        private Date createTime;
    
        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS")
        @Field(type=FieldType.Date, format=DateFormat.custom, pattern="yyyy-MM-dd HH:mm:ss.SSS")
        private Date updateTime;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 编写Dao
    import com.example.estest.bean.Blog;
    import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
     
    /**
     * 自定义的dao.类似于mybatis的dao,在此处可以自定义方法
     */
    public interface BlogRepository extends ElasticsearchRepository<Blog, Long> {
     
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 增删改查
    import com.example.estest.bean.Blog;
    import com.example.estest.dao.BlogRepository;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.PageRequest;
    import org.springframework.data.domain.Sort;
    import org.springframework.data.elasticsearch.core.SearchHit;
    import org.springframework.web.bind.annotation.*;
    import java.util.*;
    
    
    /**
     * 测试ES
     */
    @RestController
    @RequestMapping("crud")
    public class CrudController {
    
        @Autowired
        private BlogRepository blogRepository;
    
        /**
         * 添加单个文档
         * @return
         */
        @GetMapping("addDocument")
        public Blog addDocument() {
            Long id = 1L;
            Blog blog = new Blog();
            blog.setBlogId(id);
            blog.setTitle("我是一个大标题" + id);
            blog.setContent("这是添加单个文档的实例" + id);
            blog.setAuthor("wf");
            blog.setCategory("ElasticSearch");
            blog.setCreateTime(new Date());
            blog.setStatus(1);
            blog.setSerialNum(id.toString());
            blog.setUpdateTime(new Date());
            return blogRepository.save(blog);
        }
    
        /**
         * 查找指定文档
         * @param id
         * @return
         */
        @GetMapping("findById")
        public Blog findById(Long id) {
            return blogRepository.findById(id).get();
        }
    
        /**
         * 添加多个文档
         * @param count
         * @return
         */
        @GetMapping("addDocuments")
        public Object addDocuments(Integer count) {
            List<Blog> blogs = new ArrayList<>();
            for (int i = 1; i <= count; i++) {
                Long id = (long)i;
                Blog blog = new Blog();
                blog.setBlogId(id);
                blog.setTitle("我是一个大标题" + id);
                blog.setContent("这是博客内容" + id);
                blog.setAuthor("wf");
                blog.setCategory("ElasticSearch");
                blog.setCreateTime(new Date());
                blog.setStatus(1);
                blog.setSerialNum(id.toString());
                blogs.add(blog);
            }
    
            return blogRepository.saveAll(blogs);
        }
    
        /**
         * 修改单个文档,相当于是覆盖,没有设置的内容为null,也会一同替换
         * @return
         */
        @GetMapping("editDocument")
        public Blog editDocument(Long id) {
            Blog blog = new Blog();
            blog.setBlogId(id);
            blog.setTitle("Spring Data ElasticSearch学习教程" + id);
            blog.setContent("这是修改单个文档的实例" + id);
            return blogRepository.save(blog);
        }
    
    
        /**
         * 删除指定文档
         * @param id
         * @return
         */
        @GetMapping("deleteDocument")
        public String deleteDocument(Long id) {
            blogRepository.deleteById(id);
            return "success";
        }
    
        /**
         * 删除所有文档
         * @return
         */
        @GetMapping("deleteDocumentAll")
        public String deleteDocumentAll() {
            blogRepository.deleteAll();
            return "success";
        }
    
        /**
         * 查询全部文档
         * @return
         */
        @GetMapping("queryAll")
        public Object queryAll() {
           
            return  blogRepository.findAll();
        }
    
        /**
         * 分页查询文档
         *
         * 注意:
         * 这里的分页和mysql的分页有所不同,此处分页只需要传递页码即可,无需计算起始位置
         * 第一页的页码为 0, 第二页为 1,第三页为 2,以此类推
         *
         */
        @GetMapping("findByPageable/{page}/{size}")
        public  List<Blog> findByPageable(@PathVariable("page") Integer page, @PathVariable("size") Integer size){
            //设置排序(排序方式,正序还是倒序,排序的 id)
            Sort sort = Sort.by(Sort.Direction.DESC,"blogId");
            //设置查询分页
            PageRequest pageRequest = PageRequest.of(page, size,sort);
            //分页查询
            Page<Blog> productPage = blogRepository.findAll(pageRequest);
            System.out.println("总页数:"+productPage.getTotalPages());
            System.out.println("分页参数信息:"+productPage.getPageable());
            System.out.println("总条数:"+productPage.getTotalElements());
            System.out.println("当前页码:"+productPage.getNumber());
            System.out.println("单页展示条数:"+productPage.getNumberOfElements());
            System.out.println("排序字段及方式:"+productPage.getSort());
            System.out.println("当前集合总数:"+productPage.getSize());
            return  productPage.getContent();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 自定义查询方法及高亮查询

    跟Spring Data JPA类似,spring data elsaticsearch提供了自定义方法的查询方式,
    在Repository接口中自定义方法,spring data根据方法名,自动生成实现类,但是方法名必须符合一定的规则

    官网方法名规则

    在自定义的Dao中编写如下方法:

    
    import com.example.estest.bean.Blog;
    import org.springframework.data.elasticsearch.annotations.Highlight;
    import org.springframework.data.elasticsearch.annotations.HighlightField;
    import org.springframework.data.elasticsearch.annotations.HighlightParameters;
    import org.springframework.data.elasticsearch.core.SearchHit;
    import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
    
    import java.util.List;
    
    /**
     * 自定义的dao.类似于mybatis的dao,在此处可以自定义方法
     */
    public interface BlogRepository extends ElasticsearchRepository<Blog, Long> {
    
        /**
         * 自定义根据title搜索查询,并高亮显示title属性
         * 此处高亮使用的是,默认的 <em></em> 斜体标签
         *
         * @param title 模糊查询的 title 值
         * @return
         */
        @Highlight(fields = {
                @HighlightField(name = "title")
        })
        List<SearchHit<Blog>> findByTitle(String title);
    
    
        /**
         * 根据content模糊查询
         * 此处高亮使用的是,自定义的span标签
         *
         * @param content 模糊查询的 title 值
         * @return
         */
        @Highlight(fields = {
                @HighlightField(name = "content")
        }, parameters = @HighlightParameters(
                preTags = "<span style='color:red'>",
                postTags = "</span>"
        ))
        List<SearchHit<Blog>> findByContent(String content);
    
    
        /**
         * 根据title,content模糊查询
         * 此处高亮使用的是,自定义的span标签
         *
         * @param content 模糊查询的 title 值
         * @return
         */
        @Highlight(
                fields = {
                        @HighlightField(name = "title"),
                        @HighlightField(name = "content")
                },
                parameters = @HighlightParameters(
                        preTags = "<span style='color:red'>",
                        postTags = "</span>"
                ))
        List<SearchHit<Blog>> findByTitleAndContent(String title, String content);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    编写接口:

    import com.example.estest.bean.Blog;
    import com.example.estest.dao.BlogRepository;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.PageRequest;
    import org.springframework.data.domain.Sort;
    import org.springframework.data.elasticsearch.core.SearchHit;
    import org.springframework.web.bind.annotation.*;
    import java.util.*;
    
    
    /**
     * 测试ES
     */
    @RestController
    @RequestMapping("crud")
    public class CrudController {
    
        @Autowired
        private BlogRepository blogRepository;
    
     	 ……
     	   此处省略上文接口
     	 ……
     	
        /**
         * 默认高亮标签模糊查询 title
         * @param title
         * @return
         */
        @GetMapping("highlightQueryTitle/{title}")
        public List<SearchHit<Blog>>  highlightQueryTitle(@PathVariable("title") String title) {
            return blogRepository.findByTitle(title);
        }
    
        /**
         * 自定义高亮标签查询 content
         * @param content
         * @return
         */
        @GetMapping("highlightQueryContent/{content}")
        public List<SearchHit<Blog>>  highlightQueryContent(@PathVariable("content") String content) {
            return blogRepository.findByContent(content);
        }
    
        /**
         * 自定义高亮标签查询 content 和 title
         * @param content
         * @return
         */
        @GetMapping("highlightQueryTitleAndContent/{title}/{content}")
        public List<SearchHit<Blog>>  highlightQueryTitleAndContent(@PathVariable("title") String title,@PathVariable("content") String content) {
            return blogRepository.findByTitleAndContent(title,content);
        }
    
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 高亮查询效果
      在这里插入图片描述
    • 自定义DSL查询

    跟JPA一样,Spring Data ElasticSearch可以使用@Query自定义语句进行查询。
    但Spring Data ElasticSearch不能通过冒号指定参数(比如:title),只能用问号加序号,比如?0)

    在自定义的Dao中编写如下方法:

    import com.example.estest.bean.Blog;
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.elasticsearch.annotations.Highlight;
    import org.springframework.data.elasticsearch.annotations.HighlightField;
    import org.springframework.data.elasticsearch.annotations.HighlightParameters;
    import org.springframework.data.elasticsearch.annotations.Query;
    import org.springframework.data.elasticsearch.core.SearchHit;
    import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
    import org.springframework.data.repository.query.Param;
    
    import java.util.List;
    
    /**
     * 自定义的dao.类似于mybatis的dao,在此处可以自定义方法
     */
    public interface BlogRepository extends ElasticsearchRepository<Blog, Long> {
    
    	………………
    	………此处省略前文内容………
    	………………
    
           /**
         * 根据标题和内筒查询
         * @param title
         * @param content
         * @return
         */
        @Query("{\"bool\":{\"must\":[{\"match\":{\"title\":\"?0\"}}," +
                "{\"match\":{\"content\":\"?1\"}}]}}")
        List<Blog> findByTitleAndContentCustom(@Param("title") String title, @Param("content") String content);
    
    
        /**
         * 根据标题和内容分页查询
         * @param title
         * @param content
         * @param pageable
         * @return
         */
        @Query("{\"bool\":{\"must\":[{\"match\":{\"title\":\"?0\"}}," +
                "{\"match\":{\"content\":\"?1\"}}]}}")
        Page<Blog> findByTitleAndContentCustom(@Param("title") String title, @Param("content") String content,Pageable pageable);
    
    
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    编写接口:

    import com.example.estest.bean.Blog;
    import com.example.estest.dao.BlogRepository;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.PageRequest;
    import org.springframework.data.domain.Sort;
    import org.springframework.data.elasticsearch.core.SearchHit;
    import org.springframework.web.bind.annotation.*;
    import java.util.*;
    
    
    /**
     * 测试ES
     */
    @RestController
    @RequestMapping("crud")
    public class CrudController {
    
        @Autowired
        private BlogRepository blogRepository;
    
    	………………
    	………此处省略前文内容………
    	………………
    
    
        /**
         * 根据标题和内筒查询
         * @param title
         * @param content
         * @return
         */
        @GetMapping("listByTitleAndContent/{title}/{content}")
        public List<Blog> listByTitleAndContent(@PathVariable("title") String title,@PathVariable("content") String content) {
            return blogRepository.findByTitleAndContentCustom(title, content);
        }
    
        /**
         * 根据标题和内容分页查询
         * @param title
         * @param content
         * @return
         */
        @GetMapping("pageByTitleAndContent/{title}/{content}")
        public Page<Blog> pageByTitleAndContent(@PathVariable("title") String title,@PathVariable("content") String content) {
            PageRequest pageRequest = PageRequest.of(0, 2);
            return blogRepository.findByTitleAndContentCustom(title, content, pageRequest);
        }
    
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 测试
      在这里插入图片描述
  • 相关阅读:
    国产龙芯安装minio失败
    windows11中安装curl
    Git --》Git常用命令使用
    淘宝大数据揭秘:购物狂欢节背后的秘密
    什么是半波整流器?半波整流器的使用方法
    【C语言】-文件操作
    计算机网络自顶向下方法笔记03
    遥感影像正射矫正
    C++11、17、20的内存管理-指针、智能指针和内存池从基础到实战(上)
    ESP8266-Arduino编程实例-L3G4200D三轴陀螺仪驱动
  • 原文地址:https://blog.csdn.net/qq_46122292/article/details/125485819