16807 字
约 56 分钟
41
appendix_I
无标签

附录I 搜索服务模块源码详解

模块概览(面向 0 基础读者):

  • 基于 Elasticsearch 提供课程检索、条件过滤与分页。
  • 负责课程索引的新增、更新、删除,以及高亮展示。
  • 与内容发布联动,确保课程上线后可被快速检索。

核心目录:

  • xuecheng-plus-search/src/main/java/com/xuecheng/search/controller
  • xuecheng-plus-search/src/main/java/com/xuecheng/search/service
  • xuecheng-plus-search/src/main/java/com/xuecheng/search/config
  • xuecheng-plus-search/src/main/java/com/xuecheng/search/index (尚未找到,检查路径)
  • xuecheng-plus-search/src/main/resources

文件:xuecheng-plus-search/main/com/xuecheng/search/config/ElasticsearchConfig.java

package com.xuecheng.search.config; // 声明类所在的包路径

import org.apache.http.HttpHost; // 导入 HttpHost 类
import org.elasticsearch.client.RestClient; // 导入 RestClient 类
import org.elasticsearch.client.RestHighLevelClient; // 导入 RestHighLevelClient 类
import org.springframework.beans.factory.annotation.Value; // 导入 Value 类
import org.springframework.context.annotation.Bean; // 导入 Bean 类
import org.springframework.context.annotation.Configuration; // 导入 Configuration 类

@Configuration // 使用注解 @Configuration
public class ElasticsearchConfig { // 定义 class ElasticsearchConfig

    @Value("${elasticsearch.hostlist}") // 使用注解 @Value("${elasticsearch.hostlist}")
    private String hostlist; // 执行语句

    @Bean // 使用注解 @Bean
    public RestHighLevelClient restHighLevelClient(){ // 定义方法 restHighLevelClient(...)
        //解析hostlist配置信息 // 保留原作者写的行内注释
        String[] split = hostlist.split(","); // 把 hostlist.split(",") 赋值给 split
        //创建HttpHost数组,其中存放es主机和端口的配置信息 // 保留原作者写的行内注释
        HttpHost[] httpHostArray = new HttpHost[split.length]; // 创建 HttpHost[split.length] 对象并赋值给 httpHostArray
        for(int i=0;i<split.length;i++){ // 定义方法 方法(...)
            String item = split[i]; // 把 split[i] 赋值给 item
            httpHostArray[i] = new HttpHost(item.split(":")[0], Integer.parseInt(item.split(":")[1]), "http"); // 创建 HttpHost 对象并赋值给 httpHostArray[i]
        } // 代码块结束
        //创建RestHighLevelClient客户端 // 保留原作者写的行内注释
        return new RestHighLevelClient(RestClient.builder(httpHostArray)); // 返回 new RestHighLevelClient(RestClient.builder(httpHostArray))
    } // 代码块结束


} // 代码块结束

文件:xuecheng-plus-search/main/com/xuecheng/search/controller/CourseIndexController.java

package com.xuecheng.search.controller; // 声明类所在的包路径

import com.xuecheng.base.exception.XueChengPlusException; // 导入 XueChengPlusException 类
import com.xuecheng.search.po.CourseIndex; // 导入 CourseIndex 类
import com.xuecheng.search.service.IndexService; // 导入 IndexService 类
import io.swagger.annotations.Api; // 导入 Api 类
import io.swagger.annotations.ApiOperation; // 导入 ApiOperation 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.beans.factory.annotation.Value; // 导入 Value 类
import org.springframework.web.bind.annotation.PostMapping; // 导入 PostMapping 类
import org.springframework.web.bind.annotation.RequestBody; // 导入 RequestBody 类
import org.springframework.web.bind.annotation.RequestMapping; // 导入 RequestMapping 类
import org.springframework.web.bind.annotation.RestController; // 导入 RestController 类

/** // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 * @description 课程索引接口 // 保留原作者写的块注释
 * 创建课程索引 // 保留原作者写的块注释
 * @date 2022/9/24 22:31 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Api(value = "课程信息索引接口", tags = "课程信息索引接口") // 使用注解 @Api(value = "课程信息索引接口", tags = "课程信息索引接口")
@RestController // 使用注解 @RestController
@RequestMapping("/index") // 使用注解 @RequestMapping("/index")
public class CourseIndexController { // 定义 class CourseIndexController

    @Value("${elasticsearch.course.index}") // 使用注解 @Value("${elasticsearch.course.index}")
    private String courseIndexStore; // 执行语句

    @Autowired // 使用注解 @Autowired
    IndexService indexService; // 执行语句

    @ApiOperation("添加课程索引") // 使用注解 @ApiOperation("添加课程索引")
    @PostMapping("course") // 使用注解 @PostMapping("course")
    public Boolean add(@RequestBody CourseIndex courseIndex) { // 定义方法 add(...)

        Long id = courseIndex.getId(); // 把 courseIndex.getId() 的返回值赋给 id
        if(id==null){ // 定义方法 方法(...)
            XueChengPlusException.cast("课程id为空"); // 执行语句
        } // 代码块结束
        Boolean result = indexService.addCourseIndex(courseIndexStore, String.valueOf(id), courseIndex); // 把 indexService.addCourseIndex(courseIndexStore, String.valueOf(id), courseIndex) 赋值给 result
        if(!result){ // 定义方法 方法(...)
            XueChengPlusException.cast("添加课程索引失败"); // 执行语句
        } // 代码块结束
        return result; // 返回 result

    } // 代码块结束
} // 代码块结束

文件:xuecheng-plus-search/main/com/xuecheng/search/controller/CourseSearchController.java

package com.xuecheng.search.controller; // 声明类所在的包路径

import com.xuecheng.base.model.PageParams; // 导入 PageParams 类
import com.xuecheng.base.model.PageResult; // 导入 PageResult 类
import com.xuecheng.search.dto.SearchCourseParamDto; // 导入 SearchCourseParamDto 类
import com.xuecheng.search.dto.SearchPageResultDto; // 导入 SearchPageResultDto 类
import com.xuecheng.search.po.CourseIndex; // 导入 CourseIndex 类
import com.xuecheng.search.service.CourseSearchService; // 导入 CourseSearchService 类
import io.swagger.annotations.Api; // 导入 Api 类
import io.swagger.annotations.ApiOperation; // 导入 ApiOperation 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.web.bind.annotation.*; // 导入 * 类

/** // 保留原作者写的块注释
 * @description 课程搜索接口 // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @date 2022/9/24 22:31 // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Api(value = "课程搜索接口",tags = "课程搜索接口") // 使用注解 @Api(value = "课程搜索接口",tags = "课程搜索接口")
 @RestController // 使用注解 @RestController
 @RequestMapping("/course") // 使用注解 @RequestMapping("/course")
public class CourseSearchController { // 定义 class CourseSearchController

 @Autowired // 使用注解 @Autowired
 CourseSearchService courseSearchService; // 执行语句


 @ApiOperation("课程搜索列表") // 使用注解 @ApiOperation("课程搜索列表")
  @GetMapping("/list") // 使用注解 @GetMapping("/list")
 /** // 保留原作者写的块注释
  * 传入分页,课程收搜索条件 // 保留原作者写的块注释
  * 返回之前封装的dto // 保留原作者写的块注释
  * */ // 保留原作者写的块注释
 public SearchPageResultDto<CourseIndex> list(PageParams pageParams, SearchCourseParamDto searchCourseParamDto){ // 定义方法 list(...)

    return courseSearchService.queryCoursePubIndex(pageParams,searchCourseParamDto); // 返回 courseSearchService.queryCoursePubIndex(pageParams,searchCourseParamDto)
   
  } // 代码块结束
} // 代码块结束

文件:xuecheng-plus-search/main/com/xuecheng/search/dto/SearchCourseParamDto.java

package com.xuecheng.search.dto; // 声明类所在的包路径

import lombok.Data; // 导入 Data 类
import lombok.ToString; // 导入 ToString 类

/** // 保留原作者写的块注释
 * @description 搜索课程参数dtl // 保留原作者写的块注释
 * 结合内容管理模块 // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @date 2022/9/24 22:36 // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
 @Data // 使用注解 @Data
 @ToString // 使用注解 @ToString
public class SearchCourseParamDto { // 定义 class SearchCourseParamDto

  //关键字 // 保留原作者写的行内注释
  private String keywords; // 执行语句

  //大分类 // 保留原作者写的行内注释
  private String mt; // 执行语句

  //小分类 // 保留原作者写的行内注释
  private String st; // 执行语句
  //难度等级 // 保留原作者写的行内注释
  private String grade; // 执行语句




} // 代码块结束

文件:xuecheng-plus-search/main/com/xuecheng/search/dto/SearchPageResultDto.java

package com.xuecheng.search.dto; // 声明类所在的包路径

import com.xuecheng.base.model.PageResult; // 导入 PageResult 类
import lombok.Data; // 导入 Data 类
import lombok.ToString; // 导入 ToString 类

import java.util.List; // 导入 List 类

/** // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 * @description TODO // 保留原作者写的块注释
 * @date 2022/9/25 17:51 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@ToString // 使用注解 @ToString
public class SearchPageResultDto<T> extends PageResult { // 定义 class SearchPageResultDto<T>

    //大分类列表 // 保留原作者写的行内注释
    List<String> mtList; // 执行语句
    //小分类列表 // 保留原作者写的行内注释
    List<String> stList; // 执行语句

    public SearchPageResultDto(List<T> items, long counts, long page, long pageSize) { // 定义方法 SearchPageResultDto(...)
        super(items, counts, page, pageSize); // 执行语句
    } // 代码块结束

} // 代码块结束

文件:xuecheng-plus-search/main/com/xuecheng/search/po/CourseIndex.java

package com.xuecheng.search.po; // 声明类所在的包路径

import com.alibaba.fastjson.annotation.JSONField; // 导入 JSONField 类
import com.fasterxml.jackson.annotation.JsonFormat; // 导入 JsonFormat 类
import lombok.Data; // 导入 Data 类

import java.io.Serializable; // 导入 Serializable 类
import java.time.LocalDateTime; // 导入 LocalDateTime 类

/** // 保留原作者写的块注释
 * <p> // 保留原作者写的块注释
 * 课程索引信息 // 保留原作者写的块注释
 * 索引 // 保留原作者写的块注释
 * </p> // 保留原作者写的块注释
 * // 保留原作者写的块注释
 * @author itcast // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Data // 使用注解 @Data
public class CourseIndex implements Serializable { // 定义 class CourseIndex

    private static final long serialVersionUID = 1L; // 把 1L 赋值给 serialVersionUID

    /** // 保留原作者写的块注释
     * 主键 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private Long id; // 执行语句

    /** // 保留原作者写的块注释
     * 机构ID // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private Long companyId; // 执行语句

    /** // 保留原作者写的块注释
     * 公司名称 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String companyName; // 执行语句

    /** // 保留原作者写的块注释
     * 课程名称 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String name; // 执行语句

    /** // 保留原作者写的块注释
     * 适用人群 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String users; // 执行语句

    /** // 保留原作者写的块注释
     * 标签 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String tags; // 执行语句


    /** // 保留原作者写的块注释
     * 大分类 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String mt; // 执行语句

    /** // 保留原作者写的块注释
     * 大分类名称 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String mtName; // 执行语句

    /** // 保留原作者写的块注释
     * 小分类 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String st; // 执行语句

    /** // 保留原作者写的块注释
     * 小分类名称 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String stName; // 执行语句



    /** // 保留原作者写的块注释
     * 课程等级 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String grade; // 执行语句

    /** // 保留原作者写的块注释
     * 教育模式 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String teachmode; // 执行语句
    /** // 保留原作者写的块注释
     * 课程图片 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String pic; // 执行语句

    /** // 保留原作者写的块注释
     * 课程介绍 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String description; // 执行语句


    /** // 保留原作者写的块注释
     * 发布时间 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    @JSONField(format="yyyy-MM-dd HH:mm:ss") // 使用注解 @JSONField(format="yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") // 使用注解 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createDate; // 执行语句

    /** // 保留原作者写的块注释
     * 状态 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String status; // 执行语句

    /** // 保留原作者写的块注释
     * 备注 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String remark; // 执行语句

    /** // 保留原作者写的块注释
     * 收费规则,对应数据字典--203 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String charge; // 执行语句

    /** // 保留原作者写的块注释
     * 现价 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private Float price; // 执行语句
    /** // 保留原作者写的块注释
     * 原价 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private Float originalPrice; // 执行语句

    /** // 保留原作者写的块注释
     * 课程有效期天数 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private Integer validDays; // 执行语句


} // 代码块结束

文件:xuecheng-plus-search/main/com/xuecheng/search/service/CourseSearchService.java

package com.xuecheng.search.service; // 声明类所在的包路径

import com.xuecheng.base.model.PageParams; // 导入 PageParams 类
import com.xuecheng.base.model.PageResult; // 导入 PageResult 类
import com.xuecheng.search.dto.SearchCourseParamDto; // 导入 SearchCourseParamDto 类
import com.xuecheng.search.dto.SearchPageResultDto; // 导入 SearchPageResultDto 类
import com.xuecheng.search.po.CourseIndex; // 导入 CourseIndex 类

/** // 保留原作者写的块注释
 * @description 课程搜索service // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @date 2022/9/24 22:40 // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
public interface CourseSearchService { // 定义 interface CourseSearchService


    /** // 保留原作者写的块注释
     * @description 搜索课程列表 // 保留原作者写的块注释
     * @param pageParams 分页参数 // 保留原作者写的块注释
     * @param searchCourseParamDto 搜索条件 // 保留原作者写的块注释
     * @return com.xuecheng.base.model.PageResult<com.xuecheng.search.po.CourseIndex> 课程列表 // 保留原作者写的块注释
     * @author Mr.M // 保留原作者写的块注释
     * @date 2022/9/24 22:45 // 保留原作者写的块注释
    */ // 保留原作者写的块注释
    SearchPageResultDto<CourseIndex> queryCoursePubIndex(PageParams pageParams, SearchCourseParamDto searchCourseParamDto); // 执行语句

 } // 代码块结束

文件:xuecheng-plus-search/main/com/xuecheng/search/service/impl/CourseSearchServiceImpl.java

package com.xuecheng.search.service.impl; // 声明类所在的包路径

import com.alibaba.fastjson.JSON; // 导入 JSON 类
import com.xuecheng.base.model.PageParams; // 导入 PageParams 类
import com.xuecheng.base.model.PageResult; // 导入 PageResult 类
import com.xuecheng.search.dto.SearchCourseParamDto; // 导入 SearchCourseParamDto 类
import com.xuecheng.search.dto.SearchPageResultDto; // 导入 SearchPageResultDto 类
import com.xuecheng.search.po.CourseIndex; // 导入 CourseIndex 类
import com.xuecheng.search.service.CourseSearchService; // 导入 CourseSearchService 类
import lombok.extern.slf4j.Slf4j; // 导入 Slf4j 类
import org.apache.commons.lang3.StringUtils; // 导入 StringUtils 类
import org.apache.lucene.search.TotalHits; // 导入 TotalHits 类
import org.elasticsearch.action.search.SearchRequest; // 导入 SearchRequest 类
import org.elasticsearch.action.search.SearchResponse; // 导入 SearchResponse 类
import org.elasticsearch.client.RequestOptions; // 导入 RequestOptions 类
import org.elasticsearch.client.RestHighLevelClient; // 导入 RestHighLevelClient 类
import org.elasticsearch.common.text.Text; // 导入 Text 类
import org.elasticsearch.index.query.BoolQueryBuilder; // 导入 BoolQueryBuilder 类
import org.elasticsearch.index.query.MultiMatchQueryBuilder; // 导入 MultiMatchQueryBuilder 类
import org.elasticsearch.index.query.QueryBuilders; // 导入 QueryBuilders 类
import org.elasticsearch.search.SearchHit; // 导入 SearchHit 类
import org.elasticsearch.search.SearchHits; // 导入 SearchHits 类
import org.elasticsearch.search.aggregations.AggregationBuilders; // 导入 AggregationBuilders 类
import org.elasticsearch.search.aggregations.Aggregations; // 导入 Aggregations 类
import org.elasticsearch.search.aggregations.bucket.terms.Terms; // 导入 Terms 类
import org.elasticsearch.search.builder.SearchSourceBuilder; // 导入 SearchSourceBuilder 类
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder; // 导入 HighlightBuilder 类
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField; // 导入 HighlightField 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.beans.factory.annotation.Value; // 导入 Value 类
import org.springframework.stereotype.Service; // 导入 Service 类

import java.io.IOException; // 导入 IOException 类
import java.util.ArrayList; // 导入 ArrayList 类
import java.util.List; // 导入 List 类
import java.util.Map; // 导入 Map 类

/** // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 * @description 课程搜索service实现类 // 保留原作者写的块注释
 * @date 2022/9/24 22:48 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
@Service // 使用注解 @Service
public class CourseSearchServiceImpl implements CourseSearchService { // 定义 class CourseSearchServiceImpl

    @Value("${elasticsearch.course.index}") // 使用注解 @Value("${elasticsearch.course.index}")
    private String courseIndexStore; // 执行语句
    @Value("${elasticsearch.course.source_fields}") // 使用注解 @Value("${elasticsearch.course.source_fields}")
    private String sourceFields; // 执行语句

    @Autowired // 使用注解 @Autowired
    RestHighLevelClient client; // 执行语句

    @Override // 使用注解 @Override
    public SearchPageResultDto<CourseIndex> queryCoursePubIndex(PageParams pageParams, SearchCourseParamDto courseSearchParam) { // 定义方法 queryCoursePubIndex(...)

        //设置索引,查询courseIndexStore // 保留原作者写的行内注释
        SearchRequest searchRequest = new SearchRequest(courseIndexStore); // 创建 SearchRequest 对象并赋值给 searchRequest

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); // 创建 SearchSourceBuilder 对象并赋值给 searchSourceBuilder
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); // 把 QueryBuilders.boolQuery() 的返回值赋给 boolQueryBuilder
        //source源字段过虑 // 保留原作者写的行内注释
        String[] sourceFieldsArray = sourceFields.split(","); // 把 sourceFields.split(",") 赋值给 sourceFieldsArray
        searchSourceBuilder.fetchSource(sourceFieldsArray, new String[]{}); // 执行语句
        if(courseSearchParam==null){ // 定义方法 方法(...)
            courseSearchParam = new SearchCourseParamDto(); // 创建 SearchCourseParamDto 对象并赋值给 courseSearchParam
        } // 代码块结束
        //关键字 // 保留原作者写的行内注释
        if(StringUtils.isNotEmpty(courseSearchParam.getKeywords())){ // 定义方法 方法(...)
            //匹配关键字 // 保留原作者写的行内注释
            MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(courseSearchParam.getKeywords(), "name", "description"); // 把 QueryBuilders.multiMatchQuery(courseSearchParam.getKeywords(), "name", "description") 赋值给 multiMatchQueryBuilder
            //设置匹配占比 // 保留原作者写的行内注释
            multiMatchQueryBuilder.minimumShouldMatch("70%"); // 执行语句
            //提升另个字段的Boost值 // 保留原作者写的行内注释
            multiMatchQueryBuilder.field("name",10); // 执行语句
            boolQueryBuilder.must(multiMatchQueryBuilder); // 执行语句
        } // 代码块结束
        //过虑 // 保留原作者写的行内注释
        if(StringUtils.isNotEmpty(courseSearchParam.getMt())){ // 定义方法 方法(...)
            boolQueryBuilder.filter(QueryBuilders.termQuery("mtName",courseSearchParam.getMt())); // 执行语句
        } // 代码块结束
        if(StringUtils.isNotEmpty(courseSearchParam.getSt())){ // 定义方法 方法(...)
            boolQueryBuilder.filter(QueryBuilders.termQuery("stName",courseSearchParam.getSt())); // 执行语句
        } // 代码块结束
        if(StringUtils.isNotEmpty(courseSearchParam.getGrade())){ // 定义方法 方法(...)
            boolQueryBuilder.filter(QueryBuilders.termQuery("grade",courseSearchParam.getGrade())); // 执行语句
        } // 代码块结束
        //分页 // 保留原作者写的行内注释
        Long pageNo = pageParams.getPageNo(); // 把 pageParams.getPageNo() 的返回值赋给 pageNo
        Long pageSize = pageParams.getPageSize(); // 把 pageParams.getPageSize() 的返回值赋给 pageSize
        int start = (int) ((pageNo-1)*pageSize); // 把 (int) ((pageNo-1)*pageSize) 赋值给 start
        searchSourceBuilder.from(start); // 执行语句
        searchSourceBuilder.size(Math.toIntExact(pageSize)); // 执行语句
        //布尔查询 // 保留原作者写的行内注释
        searchSourceBuilder.query(boolQueryBuilder); // 执行语句
        //高亮设置 // 保留原作者写的行内注释
        HighlightBuilder highlightBuilder = new HighlightBuilder(); // 创建 HighlightBuilder 对象并赋值给 highlightBuilder
        highlightBuilder.preTags("<font class='eslight'>"); // 把 'eslight'>") 赋值给 class
        highlightBuilder.postTags("</font>"); // 执行语句
        //设置高亮字段 // 保留原作者写的行内注释
        highlightBuilder.fields().add(new HighlightBuilder.Field("name")); // 执行语句
        searchSourceBuilder.highlighter(highlightBuilder); // 执行语句
        //请求搜索 // 保留原作者写的行内注释
        searchRequest.source(searchSourceBuilder); // 执行语句
        //聚合设置 // 保留原作者写的行内注释
        buildAggregation(searchRequest); // 执行语句
        SearchResponse searchResponse = null; // 把变量 searchResponse 初始化为 null
        try { // 尝试执行可能抛出异常的代码
            searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); // 把 client.search(searchRequest, RequestOptions.DEFAULT) 赋值给 searchResponse
        } catch (IOException e) { // 定义方法 catch(...)
            e.printStackTrace(); // 执行语句
            log.error("课程搜索异常:{}",e.getMessage()); // 执行语句
            return new SearchPageResultDto<CourseIndex>(new ArrayList(),0,0,0); // 返回 new SearchPageResultDto<CourseIndex>(new ArrayList(),0,0,0)
        } // 代码块结束

        //结果集处理 // 保留原作者写的行内注释
        SearchHits hits = searchResponse.getHits(); // 把 searchResponse.getHits() 的返回值赋给 hits
        SearchHit[] searchHits = hits.getHits(); // 把 hits.getHits() 的返回值赋给 searchHits
        //记录总数 // 保留原作者写的行内注释
        TotalHits totalHits = hits.getTotalHits(); // 把 hits.getTotalHits() 的返回值赋给 totalHits
        //数据列表 // 保留原作者写的行内注释
        List<CourseIndex> list = new ArrayList<>(); // 创建 ArrayList<> 对象并赋值给 list

        for (SearchHit hit : searchHits) { // 定义方法 方法(...)

            String sourceAsString = hit.getSourceAsString(); // 把 hit.getSourceAsString() 的返回值赋给 sourceAsString
            CourseIndex courseIndex = JSON.parseObject(sourceAsString, CourseIndex.class); // 把 JSON.parseObject(sourceAsString, CourseIndex.class) 赋值给 courseIndex

            //取出source // 保留原作者写的行内注释
            Map<String, Object> sourceAsMap = hit.getSourceAsMap(); // 把 hit.getSourceAsMap() 的返回值赋给 sourceAsMap

            //课程id // 保留原作者写的行内注释
            Long id = courseIndex.getId(); // 把 courseIndex.getId() 的返回值赋给 id
            //取出名称 // 保留原作者写的行内注释
            String name = courseIndex.getName(); // 把 courseIndex.getName() 的返回值赋给 name
            //取出高亮字段内容 // 保留原作者写的行内注释
            Map<String, HighlightField> highlightFields = hit.getHighlightFields(); // 把 hit.getHighlightFields() 的返回值赋给 highlightFields
            if(highlightFields!=null){ // 定义方法 方法(...)
                HighlightField nameField = highlightFields.get("name"); // 把 highlightFields.get("name") 赋值给 nameField
                if(nameField!=null){ // 定义方法 方法(...)
                    Text[] fragments = nameField.getFragments(); // 把 nameField.getFragments() 的返回值赋给 fragments
                    StringBuffer stringBuffer = new StringBuffer(); // 创建 StringBuffer 对象并赋值给 stringBuffer
                    for (Text str : fragments) { // 定义方法 方法(...)
                        stringBuffer.append(str.string()); // 执行语句
                    } // 代码块结束
                    name = stringBuffer.toString(); // 把 stringBuffer.toString() 的返回值赋给 name

                } // 代码块结束
            } // 代码块结束
            courseIndex.setId(id); // 执行语句
            courseIndex.setName(name); // 执行语句

            list.add(courseIndex); // 执行语句

        } // 代码块结束
        SearchPageResultDto<CourseIndex> pageResult = new SearchPageResultDto<>(list, totalHits.value,pageNo,pageSize); // 创建 SearchPageResultDto<> 对象并赋值给 pageResult

        //获取聚合结果 // 保留原作者写的行内注释
        List<String> mtList= getAggregation(searchResponse.getAggregations(), "mtAgg"); // 把 getAggregation(searchResponse.getAggregations(), "mtAgg") 赋值给 mtList
        List<String> stList = getAggregation(searchResponse.getAggregations(), "stAgg"); // 把 getAggregation(searchResponse.getAggregations(), "stAgg") 赋值给 stList

        pageResult.setMtList(mtList); // 执行语句
        pageResult.setStList(stList); // 执行语句

        return pageResult; // 返回 pageResult
    } // 代码块结束


    private void buildAggregation(SearchRequest request) { // 定义方法 buildAggregation(...)
        request.source().aggregation(AggregationBuilders // 代码逻辑
                .terms("mtAgg") // 代码逻辑
                .field("mtName") // 代码逻辑
                .size(100) // 代码逻辑
        ); // 执行语句
        request.source().aggregation(AggregationBuilders // 代码逻辑
                .terms("stAgg") // 代码逻辑
                .field("stName") // 代码逻辑
                .size(100) // 代码逻辑
        ); // 执行语句

    } // 代码块结束

    private List<String> getAggregation(Aggregations aggregations, String aggName) { // 定义方法 getAggregation(...)
        // 4.1.根据聚合名称获取聚合结果 // 保留原作者写的行内注释
        Terms brandTerms = aggregations.get(aggName); // 把 aggregations.get(aggName) 赋值给 brandTerms
        // 4.2.获取buckets // 保留原作者写的行内注释
        List<? extends Terms.Bucket> buckets = brandTerms.getBuckets(); // 把 brandTerms.getBuckets() 的返回值赋给 buckets
        // 4.3.遍历 // 保留原作者写的行内注释
        List<String> brandList = new ArrayList<>(); // 创建 ArrayList<> 对象并赋值给 brandList
        for (Terms.Bucket bucket : buckets) { // 定义方法 方法(...)
            // 4.4.获取key // 保留原作者写的行内注释
            String key = bucket.getKeyAsString(); // 把 bucket.getKeyAsString() 的返回值赋给 key
            brandList.add(key); // 执行语句
        } // 代码块结束
        return brandList; // 返回 brandList
    } // 代码块结束
} // 代码块结束

文件:xuecheng-plus-search/main/com/xuecheng/search/service/impl/IndexServiceImpl.java

package com.xuecheng.search.service.impl; // 声明类所在的包路径

import com.alibaba.fastjson.JSON; // 导入 JSON 类
import com.xuecheng.base.exception.XueChengPlusException; // 导入 XueChengPlusException 类
import com.xuecheng.search.po.CourseIndex; // 导入 CourseIndex 类
import com.xuecheng.search.service.IndexService; // 导入 IndexService 类
import lombok.extern.slf4j.Slf4j; // 导入 Slf4j 类
import org.elasticsearch.action.DocWriteResponse; // 导入 DocWriteResponse 类
import org.elasticsearch.action.delete.DeleteRequest; // 导入 DeleteRequest 类
import org.elasticsearch.action.delete.DeleteResponse; // 导入 DeleteResponse 类
import org.elasticsearch.action.index.IndexRequest; // 导入 IndexRequest 类
import org.elasticsearch.action.index.IndexResponse; // 导入 IndexResponse 类
import org.elasticsearch.action.update.UpdateRequest; // 导入 UpdateRequest 类
import org.elasticsearch.action.update.UpdateResponse; // 导入 UpdateResponse 类
import org.elasticsearch.client.RequestOptions; // 导入 RequestOptions 类
import org.elasticsearch.client.RestHighLevelClient; // 导入 RestHighLevelClient 类
import org.elasticsearch.common.xcontent.XContentType; // 导入 XContentType 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.beans.factory.annotation.Value; // 导入 Value 类
import org.springframework.stereotype.Service; // 导入 Service 类

import java.io.IOException; // 导入 IOException 类

/** // 保留原作者写的块注释
 * @description 课程索引管理接口实现 // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @date 2022/9/25 7:23 // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
@Service // 使用注解 @Service
public class IndexServiceImpl implements IndexService { // 定义 class IndexServiceImpl



 @Autowired // 使用注解 @Autowired
 RestHighLevelClient client; // 执行语句

 @Override // 使用注解 @Override
 public Boolean addCourseIndex(String indexName,String id,Object object) { // 定义方法 addCourseIndex(...)
  // 将课程数据转换为js // 保留原作者写的行内注释
  String jsonString = JSON.toJSONString(object); // 把 JSON.toJSONString(object) 赋值给 jsonString
  // 将索引存储 // 保留原作者写的行内注释
  IndexRequest indexRequest = new IndexRequest(indexName).id(id); // 创建 IndexRequest 对象并赋值给 indexRequest
  //指定索引文档内容 // 保留原作者写的行内注释
  // XContentType.JSON是json格式 // 保留原作者写的行内注释
  indexRequest.source(jsonString,XContentType.JSON); // 执行语句
  //索引响应对象 // 保留原作者写的行内注释
  IndexResponse indexResponse = null; // 把变量 indexResponse 初始化为 null
  try { // 尝试执行可能抛出异常的代码
   // 将索引存储到es // 保留原作者写的行内注释
   indexResponse = client.index(indexRequest, RequestOptions.DEFAULT); // 把 client.index(indexRequest, RequestOptions.DEFAULT) 赋值给 indexResponse
  } catch (IOException e) { // 定义方法 catch(...)
   log.error("添加索引出错:{}",e.getMessage()); // 执行语句
   e.printStackTrace(); // 执行语句
   XueChengPlusException.cast("添加索引出错"); // 执行语句
  } // 代码块结束
  String name = indexResponse.getResult().name(); // 把 indexResponse.getResult().name() 的返回值赋给 name
  System.out.println(name); // 执行语句
  return name.equalsIgnoreCase("created") || name.equalsIgnoreCase("updated"); // 返回 name.equalsIgnoreCase("created") || name.equalsIgnoreCase("updated")

 } // 代码块结束

 @Override // 使用注解 @Override
 public Boolean updateCourseIndex(String indexName,String id,Object object) { // 定义方法 updateCourseIndex(...)

  String jsonString = JSON.toJSONString(object); // 把 JSON.toJSONString(object) 赋值给 jsonString
  UpdateRequest updateRequest = new UpdateRequest(indexName, id); // 创建 UpdateRequest 对象并赋值给 updateRequest
  updateRequest.doc(jsonString, XContentType.JSON); // 执行语句
  UpdateResponse updateResponse = null; // 把变量 updateResponse 初始化为 null
  try { // 尝试执行可能抛出异常的代码
   updateResponse = client.update(updateRequest, RequestOptions.DEFAULT); // 把 client.update(updateRequest, RequestOptions.DEFAULT) 赋值给 updateResponse
  } catch (IOException e) { // 定义方法 catch(...)
   log.error("更新索引出错:{}",e.getMessage()); // 执行语句
   e.printStackTrace(); // 执行语句
   XueChengPlusException.cast("更新索引出错"); // 执行语句
  } // 代码块结束
  DocWriteResponse.Result result = updateResponse.getResult(); // 把 updateResponse.getResult() 的返回值赋给 result
  return result.name().equalsIgnoreCase("updated"); // 返回 result.name().equalsIgnoreCase("updated")

 } // 代码块结束

 @Override // 使用注解 @Override
 public Boolean deleteCourseIndex(String indexName,String id) { // 定义方法 deleteCourseIndex(...)

  //删除索引请求对象 // 保留原作者写的行内注释
  DeleteRequest deleteRequest = new DeleteRequest(indexName,id); // 创建 DeleteRequest 对象并赋值给 deleteRequest
  //响应对象 // 保留原作者写的行内注释
  DeleteResponse deleteResponse = null; // 把变量 deleteResponse 初始化为 null
  try { // 尝试执行可能抛出异常的代码
   deleteResponse = client.delete(deleteRequest, RequestOptions.DEFAULT); // 把 client.delete(deleteRequest, RequestOptions.DEFAULT) 赋值给 deleteResponse
  } catch (IOException e) { // 定义方法 catch(...)
   log.error("删除索引出错:{}",e.getMessage()); // 执行语句
   e.printStackTrace(); // 执行语句
   XueChengPlusException.cast("删除索引出错"); // 执行语句
  } // 代码块结束
  //获取响应结果 // 保留原作者写的行内注释
  DocWriteResponse.Result result = deleteResponse.getResult(); // 把 deleteResponse.getResult() 的返回值赋给 result
  return result.name().equalsIgnoreCase("deleted"); // 返回 result.name().equalsIgnoreCase("deleted")
 } // 代码块结束
} // 代码块结束

文件:xuecheng-plus-search/main/com/xuecheng/search/service/IndexService.java

package com.xuecheng.search.service; // 声明类所在的包路径

import com.xuecheng.search.po.CourseIndex; // 导入 CourseIndex 类

/** // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 * @description 课程索引service // 保留原作者写的块注释
 * @date 2022/9/24 22:40 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
public interface IndexService { // 定义 interface IndexService
    //增,删,改 // 保留原作者写的行内注释

    /** // 保留原作者写的块注释
     * @param indexName 索引名称 // 保留原作者写的块注释
     * @param id 主键 // 保留原作者写的块注释
     * @param object 索引对象 // 保留原作者写的块注释
     * @return Boolean true表示成功,false失败 // 保留原作者写的块注释
     * @description 添加索引 // 保留原作者写的块注释
     * @author Mr.M // 保留原作者写的块注释
     * @date 2022/9/24 22:57 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    public Boolean addCourseIndex(String indexName,String id,Object object); // 执行语句


    /** // 保留原作者写的块注释
     * @description 更新索引 // 保留原作者写的块注释
     * @param indexName 索引名称 // 保留原作者写的块注释
     * @param id 主键 // 保留原作者写的块注释
     * @param object 索引对象 // 保留原作者写的块注释
     * @return Boolean true表示成功,false失败 // 保留原作者写的块注释
     * @author Mr.M // 保留原作者写的块注释
     * @date 2022/9/25 7:49 // 保留原作者写的块注释
    */ // 保留原作者写的块注释
    public Boolean updateCourseIndex(String indexName,String id,Object object); // 执行语句

    /** // 保留原作者写的块注释
     * @description 删除索引 // 保留原作者写的块注释
     * @param indexName 索引名称 // 保留原作者写的块注释
     * @param id  主键 // 保留原作者写的块注释
     * @return java.lang.Boolean // 保留原作者写的块注释
     * @author Mr.M // 保留原作者写的块注释
     * @date 2022/9/25 9:27 // 保留原作者写的块注释
    */ // 保留原作者写的块注释
    public Boolean deleteCourseIndex(String indexName,String id); // 执行语句

} // 代码块结束

文件:xuecheng-plus-search/main/com/xuecheng/SearchApplication.java

package com.xuecheng; // 声明类所在的包路径

import org.springframework.boot.SpringApplication; // 导入 SpringApplication 类
import org.springframework.boot.autoconfigure.SpringBootApplication; // 导入 SpringBootApplication 类

@SpringBootApplication // 使用注解 @SpringBootApplication
public class SearchApplication { // 定义 class SearchApplication

    public static void main(String[] args) { // 定义方法 main(...)
        SpringApplication.run(SearchApplication.class, args); // 执行语句
    } // 代码块结束

} // 代码块结束

文件:xuecheng-plus-search/pom.xml

<?xml version="1.0" encoding="UTF-8"?> <!-- XML 声明 -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <!-- SQL 语句片段 -->
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <!-- SQL 语句片段 -->
    <modelVersion>4.0.0</modelVersion> <!-- SQL 语句片段 -->
    <parent> <!-- SQL 语句片段 -->
        <artifactId>xuecheng-plus-parent</artifactId> <!-- SQL 语句片段 -->
        <groupId>com.xuecheng</groupId> <!-- SQL 语句片段 -->
        <version>0.0.1-SNAPSHOT</version> <!-- SQL 语句片段 -->
        <relativePath>../xuecheng-plus-parent</relativePath> <!-- SQL 语句片段 -->
    </parent> <!-- SQL 语句片段 -->
    <artifactId>xuecheng-plus-search</artifactId> <!-- SQL 语句片段 -->


    <dependencies> <!-- SQL 语句片段 -->
        <dependency> <!-- SQL 语句片段 -->
            <groupId>com.xuecheng</groupId> <!-- SQL 语句片段 -->
            <artifactId>xuecheng-plus-base</artifactId> <!-- SQL 语句片段 -->
            <version>0.0.1-SNAPSHOT</version> <!-- SQL 语句片段 -->
        </dependency> <!-- SQL 语句片段 -->
        <dependency> <!-- SQL 语句片段 -->
            <groupId>com.alibaba.cloud</groupId> <!-- SQL 语句片段 -->
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <!-- SQL 语句片段 -->
        </dependency> <!-- SQL 语句片段 -->
        <dependency> <!-- SQL 语句片段 -->
            <groupId>com.alibaba.cloud</groupId> <!-- SQL 语句片段 -->
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> <!-- SQL 语句片段 -->
        </dependency> <!-- SQL 语句片段 -->
        <dependency> <!-- SQL 语句片段 -->
            <groupId>org.elasticsearch.client</groupId> <!-- SQL 语句片段 -->
            <artifactId>elasticsearch-rest-high-level-client</artifactId> <!-- SQL 语句片段 -->
        </dependency> <!-- SQL 语句片段 -->

        <dependency> <!-- SQL 语句片段 -->
            <groupId>org.elasticsearch</groupId> <!-- SQL 语句片段 -->
            <artifactId>elasticsearch</artifactId> <!-- SQL 语句片段 -->
        </dependency> <!-- SQL 语句片段 -->



        <!-- Spring Boot 的 Spring Web MVC 集成 -->
        <dependency> <!-- SQL 语句片段 -->
            <groupId>org.springframework.boot</groupId> <!-- SQL 语句片段 -->
            <artifactId>spring-boot-starter-web</artifactId> <!-- SQL 语句片段 -->
        </dependency> <!-- SQL 语句片段 -->
        <dependency> <!-- SQL 语句片段 -->
            <groupId>org.springframework.boot</groupId> <!-- SQL 语句片段 -->
            <artifactId>spring-boot-starter-validation</artifactId> <!-- SQL 语句片段 -->
        </dependency> <!-- SQL 语句片段 -->
        <!-- 排除 Spring Boot 依赖的日志包冲突 -->
        <dependency> <!-- SQL 语句片段 -->
            <groupId>org.springframework.boot</groupId> <!-- SQL 语句片段 -->
            <artifactId>spring-boot-starter</artifactId> <!-- SQL 语句片段 -->
            <exclusions> <!-- SQL 语句片段 -->
                <exclusion> <!-- SQL 语句片段 -->
                    <groupId>org.springframework.boot</groupId> <!-- SQL 语句片段 -->
                    <artifactId>spring-boot-starter-logging</artifactId> <!-- SQL 语句片段 -->
                </exclusion> <!-- SQL 语句片段 -->
            </exclusions> <!-- SQL 语句片段 -->
        </dependency> <!-- SQL 语句片段 -->
        <!-- Spring Boot 集成 Junit -->
        <dependency> <!-- SQL 语句片段 -->
            <groupId>org.springframework.boot</groupId> <!-- SQL 语句片段 -->
            <artifactId>spring-boot-starter-test</artifactId> <!-- SQL 语句片段 -->
            <scope>test</scope> <!-- SQL 语句片段 -->
        </dependency> <!-- SQL 语句片段 -->
        <!-- Spring Boot 集成 log4j2 -->
        <dependency> <!-- SQL 语句片段 -->
            <groupId>org.springframework.boot</groupId> <!-- SQL 语句片段 -->
            <artifactId>spring-boot-starter-log4j2</artifactId> <!-- SQL 语句片段 -->
        </dependency> <!-- SQL 语句片段 -->

        <!-- Spring Boot 集成 swagger -->
        <dependency> <!-- SQL 语句片段 -->
            <groupId>com.spring4all</groupId> <!-- SQL 语句片段 -->
            <artifactId>swagger-spring-boot-starter</artifactId> <!-- SQL 语句片段 -->
        </dependency> <!-- SQL 语句片段 -->
        <dependency> <!-- SQL 语句片段 -->
            <groupId>org.projectlombok</groupId> <!-- SQL 语句片段 -->
            <artifactId>lombok</artifactId> <!-- SQL 语句片段 -->
        </dependency> <!-- SQL 语句片段 -->
    </dependencies> <!-- SQL 语句片段 -->



</project> <!-- SQL 语句片段 -->

文件:xuecheng-plus-search/resources/bootstrap.yml

spring:
  application:
    name: search
  cloud:
    nacos:
      server-addr: 192.168.101.65:8848
      discovery:
        namespace: dev402
        group: xuecheng-plus-project
      config:
        namespace: dev402
        group: xuecheng-plus-project
        file-extension: yaml
        refresh-enabled: true
        shared-configs:
          - data-id: swagger-${spring.profiles.active}.yaml
            group: xuecheng-plus-common
            refresh: true
          - data-id: logging-${spring.profiles.active}.yaml
            group: xuecheng-plus-common
            refresh: true

  profiles:
    active: dev

文件:xuecheng-plus-search/resources/log4j2-dev.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration monitorInterval="180" packages="">
    <properties>
        <property name="logdir">logs</property>
        <property name="PATTERN">%date{YYYY-MM-dd HH:mm:ss,SSS} %level [%thread][%file:%line] - %msg%n%throwable</property>
    </properties>
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="${PATTERN}"/>
        </Console>

        <RollingFile name="ErrorAppender" fileName="${logdir}/error.log"
            filePattern="${logdir}/$${date:yyyy-MM-dd}/error.%d{yyyy-MM-dd-HH}.log" append="true">
            <PatternLayout pattern="${PATTERN}"/>
            <ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>
            <Policies>
                <TimeBasedTriggeringPolicy interval="1" modulate="true" />
            </Policies>
        </RollingFile>

        <RollingFile name="DebugAppender" fileName="${logdir}/info.log"
            filePattern="${logdir}/$${date:yyyy-MM-dd}/info.%d{yyyy-MM-dd-HH}.log" append="true">
            <PatternLayout pattern="${PATTERN}"/>
            <ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
            <Policies>
                <TimeBasedTriggeringPolicy interval="1" modulate="true" />
            </Policies>
        </RollingFile>
        
        <!--异步appender-->
         <Async name="AsyncAppender" includeLocation="true">
            <AppenderRef ref="ErrorAppender"/>
            <AppenderRef ref="DebugAppender"/>
        </Async>
    </Appenders>
    
    <Loggers>
         <!--过滤掉spring和mybatis的一些无用的debug信息-->
        <logger name="org.springframework" level="INFO">
        </logger>
        <logger name="org.mybatis" level="INFO">
        </logger>
        <logger name="cn.itcast.wanxinp2p.consumer.mapper" level="DEBUG">
        </logger>

        <logger name="springfox" level="INFO">
        </logger>
		<logger name="org.apache.http" level="INFO">
        </logger>
        <logger name="com.netflix.discovery" level="INFO">
        </logger>
        
        <logger name="RocketmqCommon"  level="INFO" >
		</logger>
		
		<logger name="RocketmqRemoting" level="INFO"  >
		</logger>
		
		<logger name="RocketmqClient" level="WARN">
		</logger>

        <logger name="org.dromara.hmily" level="WARN">
        </logger>

        <logger name="org.dromara.hmily.lottery" level="WARN">
        </logger>

        <logger name="org.dromara.hmily.bonuspoint" level="WARN">
        </logger>
		
        <!--OFF   0-->
        <!--FATAL   100-->
        <!--ERROR   200-->
        <!--WARN   300-->
        <!--INFO   400-->
        <!--DEBUG   500-->
        <!--TRACE   600-->
        <!--ALL   Integer.MAX_VALUE-->
        <Root level="DEBUG" includeLocation="true">
            <AppenderRef ref="AsyncAppender"/>
            <AppenderRef ref="Console"/>
            <AppenderRef ref="DebugAppender"/>
        </Root>
    </Loggers>
</Configuration>

文件:xuecheng-plus-search/src/main/java/com/xuecheng/search/config/ElasticsearchConfig.java

package com.xuecheng.search.config; // 声明类所在的包路径

import org.apache.http.HttpHost; // 导入 HttpHost 类
import org.elasticsearch.client.RestClient; // 导入 RestClient 类
import org.elasticsearch.client.RestHighLevelClient; // 导入 RestHighLevelClient 类
import org.springframework.beans.factory.annotation.Value; // 导入 Value 类
import org.springframework.context.annotation.Bean; // 导入 Bean 类
import org.springframework.context.annotation.Configuration; // 导入 Configuration 类

@Configuration // 使用注解 @Configuration
public class ElasticsearchConfig { // 定义 class ElasticsearchConfig

    @Value("${elasticsearch.hostlist}") // 使用注解 @Value("${elasticsearch.hostlist}")
    private String hostlist; // 执行语句

    @Bean // 使用注解 @Bean
    public RestHighLevelClient restHighLevelClient(){ // 定义方法 restHighLevelClient(...)
        //解析hostlist配置信息 // 保留原作者写的行内注释
        String[] split = hostlist.split(","); // 把 hostlist.split(",") 赋值给 split
        //创建HttpHost数组,其中存放es主机和端口的配置信息 // 保留原作者写的行内注释
        HttpHost[] httpHostArray = new HttpHost[split.length]; // 创建 HttpHost[split.length] 对象并赋值给 httpHostArray
        for(int i=0;i<split.length;i++){ // 定义方法 方法(...)
            String item = split[i]; // 把 split[i] 赋值给 item
            httpHostArray[i] = new HttpHost(item.split(":")[0], Integer.parseInt(item.split(":")[1]), "http"); // 创建 HttpHost 对象并赋值给 httpHostArray[i]
        } // 代码块结束
        //创建RestHighLevelClient客户端 // 保留原作者写的行内注释
        return new RestHighLevelClient(RestClient.builder(httpHostArray)); // 返回 new RestHighLevelClient(RestClient.builder(httpHostArray))
    } // 代码块结束


} // 代码块结束

文件:xuecheng-plus-search/src/main/java/com/xuecheng/search/controller/CourseIndexController.java

package com.xuecheng.search.controller; // 声明类所在的包路径

import com.xuecheng.base.exception.XueChengPlusException; // 导入 XueChengPlusException 类
import com.xuecheng.search.po.CourseIndex; // 导入 CourseIndex 类
import com.xuecheng.search.service.IndexService; // 导入 IndexService 类
import io.swagger.annotations.Api; // 导入 Api 类
import io.swagger.annotations.ApiOperation; // 导入 ApiOperation 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.beans.factory.annotation.Value; // 导入 Value 类
import org.springframework.web.bind.annotation.PostMapping; // 导入 PostMapping 类
import org.springframework.web.bind.annotation.RequestBody; // 导入 RequestBody 类
import org.springframework.web.bind.annotation.RequestMapping; // 导入 RequestMapping 类
import org.springframework.web.bind.annotation.RestController; // 导入 RestController 类

/** // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 * @description 课程索引接口 // 保留原作者写的块注释
 * 创建课程索引 // 保留原作者写的块注释
 * @date 2022/9/24 22:31 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Api(value = "课程信息索引接口", tags = "课程信息索引接口") // 使用注解 @Api(value = "课程信息索引接口", tags = "课程信息索引接口")
@RestController // 使用注解 @RestController
@RequestMapping("/index") // 使用注解 @RequestMapping("/index")
public class CourseIndexController { // 定义 class CourseIndexController

    @Value("${elasticsearch.course.index}") // 使用注解 @Value("${elasticsearch.course.index}")
    private String courseIndexStore; // 执行语句

    @Autowired // 使用注解 @Autowired
    IndexService indexService; // 执行语句

    @ApiOperation("添加课程索引") // 使用注解 @ApiOperation("添加课程索引")
    @PostMapping("course") // 使用注解 @PostMapping("course")
    public Boolean add(@RequestBody CourseIndex courseIndex) { // 定义方法 add(...)

        Long id = courseIndex.getId(); // 把 courseIndex.getId() 的返回值赋给 id
        if(id==null){ // 定义方法 方法(...)
            XueChengPlusException.cast("课程id为空"); // 执行语句
        } // 代码块结束
        Boolean result = indexService.addCourseIndex(courseIndexStore, String.valueOf(id), courseIndex); // 把 indexService.addCourseIndex(courseIndexStore, String.valueOf(id), courseIndex) 赋值给 result
        if(!result){ // 定义方法 方法(...)
            XueChengPlusException.cast("添加课程索引失败"); // 执行语句
        } // 代码块结束
        return result; // 返回 result

    } // 代码块结束
} // 代码块结束

文件:xuecheng-plus-search/src/main/java/com/xuecheng/search/controller/CourseSearchController.java

package com.xuecheng.search.controller; // 声明类所在的包路径

import com.xuecheng.base.model.PageParams; // 导入 PageParams 类
import com.xuecheng.base.model.PageResult; // 导入 PageResult 类
import com.xuecheng.search.dto.SearchCourseParamDto; // 导入 SearchCourseParamDto 类
import com.xuecheng.search.dto.SearchPageResultDto; // 导入 SearchPageResultDto 类
import com.xuecheng.search.po.CourseIndex; // 导入 CourseIndex 类
import com.xuecheng.search.service.CourseSearchService; // 导入 CourseSearchService 类
import io.swagger.annotations.Api; // 导入 Api 类
import io.swagger.annotations.ApiOperation; // 导入 ApiOperation 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.web.bind.annotation.*; // 导入 * 类

/** // 保留原作者写的块注释
 * @description 课程搜索接口 // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @date 2022/9/24 22:31 // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Api(value = "课程搜索接口",tags = "课程搜索接口") // 使用注解 @Api(value = "课程搜索接口",tags = "课程搜索接口")
 @RestController // 使用注解 @RestController
 @RequestMapping("/course") // 使用注解 @RequestMapping("/course")
public class CourseSearchController { // 定义 class CourseSearchController

 @Autowired // 使用注解 @Autowired
 CourseSearchService courseSearchService; // 执行语句


 @ApiOperation("课程搜索列表") // 使用注解 @ApiOperation("课程搜索列表")
  @GetMapping("/list") // 使用注解 @GetMapping("/list")
 /** // 保留原作者写的块注释
  * 传入分页,课程收搜索条件 // 保留原作者写的块注释
  * 返回之前封装的dto // 保留原作者写的块注释
  * */ // 保留原作者写的块注释
 public SearchPageResultDto<CourseIndex> list(PageParams pageParams, SearchCourseParamDto searchCourseParamDto){ // 定义方法 list(...)

    return courseSearchService.queryCoursePubIndex(pageParams,searchCourseParamDto); // 返回 courseSearchService.queryCoursePubIndex(pageParams,searchCourseParamDto)
   
  } // 代码块结束
} // 代码块结束

文件:xuecheng-plus-search/src/main/java/com/xuecheng/search/dto/SearchCourseParamDto.java

package com.xuecheng.search.dto; // 声明类所在的包路径

import lombok.Data; // 导入 Data 类
import lombok.ToString; // 导入 ToString 类

/** // 保留原作者写的块注释
 * @description 搜索课程参数dtl // 保留原作者写的块注释
 * 结合内容管理模块 // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @date 2022/9/24 22:36 // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
 @Data // 使用注解 @Data
 @ToString // 使用注解 @ToString
public class SearchCourseParamDto { // 定义 class SearchCourseParamDto

  //关键字 // 保留原作者写的行内注释
  private String keywords; // 执行语句

  //大分类 // 保留原作者写的行内注释
  private String mt; // 执行语句

  //小分类 // 保留原作者写的行内注释
  private String st; // 执行语句
  //难度等级 // 保留原作者写的行内注释
  private String grade; // 执行语句




} // 代码块结束

文件:xuecheng-plus-search/src/main/java/com/xuecheng/search/dto/SearchPageResultDto.java

package com.xuecheng.search.dto; // 声明类所在的包路径

import com.xuecheng.base.model.PageResult; // 导入 PageResult 类
import lombok.Data; // 导入 Data 类
import lombok.ToString; // 导入 ToString 类

import java.util.List; // 导入 List 类

/** // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 * @description TODO // 保留原作者写的块注释
 * @date 2022/9/25 17:51 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@ToString // 使用注解 @ToString
public class SearchPageResultDto<T> extends PageResult { // 定义 class SearchPageResultDto<T>

    //大分类列表 // 保留原作者写的行内注释
    List<String> mtList; // 执行语句
    //小分类列表 // 保留原作者写的行内注释
    List<String> stList; // 执行语句

    public SearchPageResultDto(List<T> items, long counts, long page, long pageSize) { // 定义方法 SearchPageResultDto(...)
        super(items, counts, page, pageSize); // 执行语句
    } // 代码块结束

} // 代码块结束

文件:xuecheng-plus-search/src/main/java/com/xuecheng/search/po/CourseIndex.java

package com.xuecheng.search.po; // 声明类所在的包路径

import com.alibaba.fastjson.annotation.JSONField; // 导入 JSONField 类
import com.fasterxml.jackson.annotation.JsonFormat; // 导入 JsonFormat 类
import lombok.Data; // 导入 Data 类

import java.io.Serializable; // 导入 Serializable 类
import java.time.LocalDateTime; // 导入 LocalDateTime 类

/** // 保留原作者写的块注释
 * <p> // 保留原作者写的块注释
 * 课程索引信息 // 保留原作者写的块注释
 * 索引 // 保留原作者写的块注释
 * </p> // 保留原作者写的块注释
 * // 保留原作者写的块注释
 * @author itcast // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Data // 使用注解 @Data
public class CourseIndex implements Serializable { // 定义 class CourseIndex

    private static final long serialVersionUID = 1L; // 把 1L 赋值给 serialVersionUID

    /** // 保留原作者写的块注释
     * 主键 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private Long id; // 执行语句

    /** // 保留原作者写的块注释
     * 机构ID // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private Long companyId; // 执行语句

    /** // 保留原作者写的块注释
     * 公司名称 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String companyName; // 执行语句

    /** // 保留原作者写的块注释
     * 课程名称 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String name; // 执行语句

    /** // 保留原作者写的块注释
     * 适用人群 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String users; // 执行语句

    /** // 保留原作者写的块注释
     * 标签 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String tags; // 执行语句


    /** // 保留原作者写的块注释
     * 大分类 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String mt; // 执行语句

    /** // 保留原作者写的块注释
     * 大分类名称 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String mtName; // 执行语句

    /** // 保留原作者写的块注释
     * 小分类 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String st; // 执行语句

    /** // 保留原作者写的块注释
     * 小分类名称 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String stName; // 执行语句



    /** // 保留原作者写的块注释
     * 课程等级 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String grade; // 执行语句

    /** // 保留原作者写的块注释
     * 教育模式 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String teachmode; // 执行语句
    /** // 保留原作者写的块注释
     * 课程图片 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String pic; // 执行语句

    /** // 保留原作者写的块注释
     * 课程介绍 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String description; // 执行语句


    /** // 保留原作者写的块注释
     * 发布时间 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    @JSONField(format="yyyy-MM-dd HH:mm:ss") // 使用注解 @JSONField(format="yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") // 使用注解 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createDate; // 执行语句

    /** // 保留原作者写的块注释
     * 状态 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String status; // 执行语句

    /** // 保留原作者写的块注释
     * 备注 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String remark; // 执行语句

    /** // 保留原作者写的块注释
     * 收费规则,对应数据字典--203 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String charge; // 执行语句

    /** // 保留原作者写的块注释
     * 现价 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private Float price; // 执行语句
    /** // 保留原作者写的块注释
     * 原价 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private Float originalPrice; // 执行语句

    /** // 保留原作者写的块注释
     * 课程有效期天数 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private Integer validDays; // 执行语句


} // 代码块结束

文件:xuecheng-plus-search/src/main/java/com/xuecheng/search/service/CourseSearchService.java

package com.xuecheng.search.service; // 声明类所在的包路径

import com.xuecheng.base.model.PageParams; // 导入 PageParams 类
import com.xuecheng.base.model.PageResult; // 导入 PageResult 类
import com.xuecheng.search.dto.SearchCourseParamDto; // 导入 SearchCourseParamDto 类
import com.xuecheng.search.dto.SearchPageResultDto; // 导入 SearchPageResultDto 类
import com.xuecheng.search.po.CourseIndex; // 导入 CourseIndex 类

/** // 保留原作者写的块注释
 * @description 课程搜索service // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @date 2022/9/24 22:40 // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
public interface CourseSearchService { // 定义 interface CourseSearchService


    /** // 保留原作者写的块注释
     * @description 搜索课程列表 // 保留原作者写的块注释
     * @param pageParams 分页参数 // 保留原作者写的块注释
     * @param searchCourseParamDto 搜索条件 // 保留原作者写的块注释
     * @return com.xuecheng.base.model.PageResult<com.xuecheng.search.po.CourseIndex> 课程列表 // 保留原作者写的块注释
     * @author Mr.M // 保留原作者写的块注释
     * @date 2022/9/24 22:45 // 保留原作者写的块注释
    */ // 保留原作者写的块注释
    SearchPageResultDto<CourseIndex> queryCoursePubIndex(PageParams pageParams, SearchCourseParamDto searchCourseParamDto); // 执行语句

 } // 代码块结束

文件:xuecheng-plus-search/src/main/java/com/xuecheng/search/service/impl/CourseSearchServiceImpl.java

package com.xuecheng.search.service.impl; // 声明类所在的包路径

import com.alibaba.fastjson.JSON; // 导入 JSON 类
import com.xuecheng.base.model.PageParams; // 导入 PageParams 类
import com.xuecheng.base.model.PageResult; // 导入 PageResult 类
import com.xuecheng.search.dto.SearchCourseParamDto; // 导入 SearchCourseParamDto 类
import com.xuecheng.search.dto.SearchPageResultDto; // 导入 SearchPageResultDto 类
import com.xuecheng.search.po.CourseIndex; // 导入 CourseIndex 类
import com.xuecheng.search.service.CourseSearchService; // 导入 CourseSearchService 类
import lombok.extern.slf4j.Slf4j; // 导入 Slf4j 类
import org.apache.commons.lang3.StringUtils; // 导入 StringUtils 类
import org.apache.lucene.search.TotalHits; // 导入 TotalHits 类
import org.elasticsearch.action.search.SearchRequest; // 导入 SearchRequest 类
import org.elasticsearch.action.search.SearchResponse; // 导入 SearchResponse 类
import org.elasticsearch.client.RequestOptions; // 导入 RequestOptions 类
import org.elasticsearch.client.RestHighLevelClient; // 导入 RestHighLevelClient 类
import org.elasticsearch.common.text.Text; // 导入 Text 类
import org.elasticsearch.index.query.BoolQueryBuilder; // 导入 BoolQueryBuilder 类
import org.elasticsearch.index.query.MultiMatchQueryBuilder; // 导入 MultiMatchQueryBuilder 类
import org.elasticsearch.index.query.QueryBuilders; // 导入 QueryBuilders 类
import org.elasticsearch.search.SearchHit; // 导入 SearchHit 类
import org.elasticsearch.search.SearchHits; // 导入 SearchHits 类
import org.elasticsearch.search.aggregations.AggregationBuilders; // 导入 AggregationBuilders 类
import org.elasticsearch.search.aggregations.Aggregations; // 导入 Aggregations 类
import org.elasticsearch.search.aggregations.bucket.terms.Terms; // 导入 Terms 类
import org.elasticsearch.search.builder.SearchSourceBuilder; // 导入 SearchSourceBuilder 类
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder; // 导入 HighlightBuilder 类
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField; // 导入 HighlightField 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.beans.factory.annotation.Value; // 导入 Value 类
import org.springframework.stereotype.Service; // 导入 Service 类

import java.io.IOException; // 导入 IOException 类
import java.util.ArrayList; // 导入 ArrayList 类
import java.util.List; // 导入 List 类
import java.util.Map; // 导入 Map 类

/** // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 * @description 课程搜索service实现类 // 保留原作者写的块注释
 * @date 2022/9/24 22:48 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
@Service // 使用注解 @Service
public class CourseSearchServiceImpl implements CourseSearchService { // 定义 class CourseSearchServiceImpl

    @Value("${elasticsearch.course.index}") // 使用注解 @Value("${elasticsearch.course.index}")
    private String courseIndexStore; // 执行语句
    @Value("${elasticsearch.course.source_fields}") // 使用注解 @Value("${elasticsearch.course.source_fields}")
    private String sourceFields; // 执行语句

    @Autowired // 使用注解 @Autowired
    RestHighLevelClient client; // 执行语句

    @Override // 使用注解 @Override
    public SearchPageResultDto<CourseIndex> queryCoursePubIndex(PageParams pageParams, SearchCourseParamDto courseSearchParam) { // 定义方法 queryCoursePubIndex(...)

        //设置索引,查询courseIndexStore // 保留原作者写的行内注释
        SearchRequest searchRequest = new SearchRequest(courseIndexStore); // 创建 SearchRequest 对象并赋值给 searchRequest

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); // 创建 SearchSourceBuilder 对象并赋值给 searchSourceBuilder
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); // 把 QueryBuilders.boolQuery() 的返回值赋给 boolQueryBuilder
        //source源字段过虑 // 保留原作者写的行内注释
        String[] sourceFieldsArray = sourceFields.split(","); // 把 sourceFields.split(",") 赋值给 sourceFieldsArray
        searchSourceBuilder.fetchSource(sourceFieldsArray, new String[]{}); // 执行语句
        if(courseSearchParam==null){ // 定义方法 方法(...)
            courseSearchParam = new SearchCourseParamDto(); // 创建 SearchCourseParamDto 对象并赋值给 courseSearchParam
        } // 代码块结束
        //关键字 // 保留原作者写的行内注释
        if(StringUtils.isNotEmpty(courseSearchParam.getKeywords())){ // 定义方法 方法(...)
            //匹配关键字 // 保留原作者写的行内注释
            MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(courseSearchParam.getKeywords(), "name", "description"); // 把 QueryBuilders.multiMatchQuery(courseSearchParam.getKeywords(), "name", "description") 赋值给 multiMatchQueryBuilder
            //设置匹配占比 // 保留原作者写的行内注释
            multiMatchQueryBuilder.minimumShouldMatch("70%"); // 执行语句
            //提升另个字段的Boost值 // 保留原作者写的行内注释
            multiMatchQueryBuilder.field("name",10); // 执行语句
            boolQueryBuilder.must(multiMatchQueryBuilder); // 执行语句
        } // 代码块结束
        //过虑 // 保留原作者写的行内注释
        if(StringUtils.isNotEmpty(courseSearchParam.getMt())){ // 定义方法 方法(...)
            boolQueryBuilder.filter(QueryBuilders.termQuery("mtName",courseSearchParam.getMt())); // 执行语句
        } // 代码块结束
        if(StringUtils.isNotEmpty(courseSearchParam.getSt())){ // 定义方法 方法(...)
            boolQueryBuilder.filter(QueryBuilders.termQuery("stName",courseSearchParam.getSt())); // 执行语句
        } // 代码块结束
        if(StringUtils.isNotEmpty(courseSearchParam.getGrade())){ // 定义方法 方法(...)
            boolQueryBuilder.filter(QueryBuilders.termQuery("grade",courseSearchParam.getGrade())); // 执行语句
        } // 代码块结束
        //分页 // 保留原作者写的行内注释
        Long pageNo = pageParams.getPageNo(); // 把 pageParams.getPageNo() 的返回值赋给 pageNo
        Long pageSize = pageParams.getPageSize(); // 把 pageParams.getPageSize() 的返回值赋给 pageSize
        int start = (int) ((pageNo-1)*pageSize); // 把 (int) ((pageNo-1)*pageSize) 赋值给 start
        searchSourceBuilder.from(start); // 执行语句
        searchSourceBuilder.size(Math.toIntExact(pageSize)); // 执行语句
        //布尔查询 // 保留原作者写的行内注释
        searchSourceBuilder.query(boolQueryBuilder); // 执行语句
        //高亮设置 // 保留原作者写的行内注释
        HighlightBuilder highlightBuilder = new HighlightBuilder(); // 创建 HighlightBuilder 对象并赋值给 highlightBuilder
        highlightBuilder.preTags("<font class='eslight'>"); // 把 'eslight'>") 赋值给 class
        highlightBuilder.postTags("</font>"); // 执行语句
        //设置高亮字段 // 保留原作者写的行内注释
        highlightBuilder.fields().add(new HighlightBuilder.Field("name")); // 执行语句
        searchSourceBuilder.highlighter(highlightBuilder); // 执行语句
        //请求搜索 // 保留原作者写的行内注释
        searchRequest.source(searchSourceBuilder); // 执行语句
        //聚合设置 // 保留原作者写的行内注释
        buildAggregation(searchRequest); // 执行语句
        SearchResponse searchResponse = null; // 把变量 searchResponse 初始化为 null
        try { // 尝试执行可能抛出异常的代码
            searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); // 把 client.search(searchRequest, RequestOptions.DEFAULT) 赋值给 searchResponse
        } catch (IOException e) { // 定义方法 catch(...)
            e.printStackTrace(); // 执行语句
            log.error("课程搜索异常:{}",e.getMessage()); // 执行语句
            return new SearchPageResultDto<CourseIndex>(new ArrayList(),0,0,0); // 返回 new SearchPageResultDto<CourseIndex>(new ArrayList(),0,0,0)
        } // 代码块结束

        //结果集处理 // 保留原作者写的行内注释
        SearchHits hits = searchResponse.getHits(); // 把 searchResponse.getHits() 的返回值赋给 hits
        SearchHit[] searchHits = hits.getHits(); // 把 hits.getHits() 的返回值赋给 searchHits
        //记录总数 // 保留原作者写的行内注释
        TotalHits totalHits = hits.getTotalHits(); // 把 hits.getTotalHits() 的返回值赋给 totalHits
        //数据列表 // 保留原作者写的行内注释
        List<CourseIndex> list = new ArrayList<>(); // 创建 ArrayList<> 对象并赋值给 list

        for (SearchHit hit : searchHits) { // 定义方法 方法(...)

            String sourceAsString = hit.getSourceAsString(); // 把 hit.getSourceAsString() 的返回值赋给 sourceAsString
            CourseIndex courseIndex = JSON.parseObject(sourceAsString, CourseIndex.class); // 把 JSON.parseObject(sourceAsString, CourseIndex.class) 赋值给 courseIndex

            //取出source // 保留原作者写的行内注释
            Map<String, Object> sourceAsMap = hit.getSourceAsMap(); // 把 hit.getSourceAsMap() 的返回值赋给 sourceAsMap

            //课程id // 保留原作者写的行内注释
            Long id = courseIndex.getId(); // 把 courseIndex.getId() 的返回值赋给 id
            //取出名称 // 保留原作者写的行内注释
            String name = courseIndex.getName(); // 把 courseIndex.getName() 的返回值赋给 name
            //取出高亮字段内容 // 保留原作者写的行内注释
            Map<String, HighlightField> highlightFields = hit.getHighlightFields(); // 把 hit.getHighlightFields() 的返回值赋给 highlightFields
            if(highlightFields!=null){ // 定义方法 方法(...)
                HighlightField nameField = highlightFields.get("name"); // 把 highlightFields.get("name") 赋值给 nameField
                if(nameField!=null){ // 定义方法 方法(...)
                    Text[] fragments = nameField.getFragments(); // 把 nameField.getFragments() 的返回值赋给 fragments
                    StringBuffer stringBuffer = new StringBuffer(); // 创建 StringBuffer 对象并赋值给 stringBuffer
                    for (Text str : fragments) { // 定义方法 方法(...)
                        stringBuffer.append(str.string()); // 执行语句
                    } // 代码块结束
                    name = stringBuffer.toString(); // 把 stringBuffer.toString() 的返回值赋给 name

                } // 代码块结束
            } // 代码块结束
            courseIndex.setId(id); // 执行语句
            courseIndex.setName(name); // 执行语句

            list.add(courseIndex); // 执行语句

        } // 代码块结束
        SearchPageResultDto<CourseIndex> pageResult = new SearchPageResultDto<>(list, totalHits.value,pageNo,pageSize); // 创建 SearchPageResultDto<> 对象并赋值给 pageResult

        //获取聚合结果 // 保留原作者写的行内注释
        List<String> mtList= getAggregation(searchResponse.getAggregations(), "mtAgg"); // 把 getAggregation(searchResponse.getAggregations(), "mtAgg") 赋值给 mtList
        List<String> stList = getAggregation(searchResponse.getAggregations(), "stAgg"); // 把 getAggregation(searchResponse.getAggregations(), "stAgg") 赋值给 stList

        pageResult.setMtList(mtList); // 执行语句
        pageResult.setStList(stList); // 执行语句

        return pageResult; // 返回 pageResult
    } // 代码块结束


    private void buildAggregation(SearchRequest request) { // 定义方法 buildAggregation(...)
        request.source().aggregation(AggregationBuilders // 代码逻辑
                .terms("mtAgg") // 代码逻辑
                .field("mtName") // 代码逻辑
                .size(100) // 代码逻辑
        ); // 执行语句
        request.source().aggregation(AggregationBuilders // 代码逻辑
                .terms("stAgg") // 代码逻辑
                .field("stName") // 代码逻辑
                .size(100) // 代码逻辑
        ); // 执行语句

    } // 代码块结束

    private List<String> getAggregation(Aggregations aggregations, String aggName) { // 定义方法 getAggregation(...)
        // 4.1.根据聚合名称获取聚合结果 // 保留原作者写的行内注释
        Terms brandTerms = aggregations.get(aggName); // 把 aggregations.get(aggName) 赋值给 brandTerms
        // 4.2.获取buckets // 保留原作者写的行内注释
        List<? extends Terms.Bucket> buckets = brandTerms.getBuckets(); // 把 brandTerms.getBuckets() 的返回值赋给 buckets
        // 4.3.遍历 // 保留原作者写的行内注释
        List<String> brandList = new ArrayList<>(); // 创建 ArrayList<> 对象并赋值给 brandList
        for (Terms.Bucket bucket : buckets) { // 定义方法 方法(...)
            // 4.4.获取key // 保留原作者写的行内注释
            String key = bucket.getKeyAsString(); // 把 bucket.getKeyAsString() 的返回值赋给 key
            brandList.add(key); // 执行语句
        } // 代码块结束
        return brandList; // 返回 brandList
    } // 代码块结束
} // 代码块结束

文件:xuecheng-plus-search/src/main/java/com/xuecheng/search/service/impl/IndexServiceImpl.java

package com.xuecheng.search.service.impl; // 声明类所在的包路径

import com.alibaba.fastjson.JSON; // 导入 JSON 类
import com.xuecheng.base.exception.XueChengPlusException; // 导入 XueChengPlusException 类
import com.xuecheng.search.po.CourseIndex; // 导入 CourseIndex 类
import com.xuecheng.search.service.IndexService; // 导入 IndexService 类
import lombok.extern.slf4j.Slf4j; // 导入 Slf4j 类
import org.elasticsearch.action.DocWriteResponse; // 导入 DocWriteResponse 类
import org.elasticsearch.action.delete.DeleteRequest; // 导入 DeleteRequest 类
import org.elasticsearch.action.delete.DeleteResponse; // 导入 DeleteResponse 类
import org.elasticsearch.action.index.IndexRequest; // 导入 IndexRequest 类
import org.elasticsearch.action.index.IndexResponse; // 导入 IndexResponse 类
import org.elasticsearch.action.update.UpdateRequest; // 导入 UpdateRequest 类
import org.elasticsearch.action.update.UpdateResponse; // 导入 UpdateResponse 类
import org.elasticsearch.client.RequestOptions; // 导入 RequestOptions 类
import org.elasticsearch.client.RestHighLevelClient; // 导入 RestHighLevelClient 类
import org.elasticsearch.common.xcontent.XContentType; // 导入 XContentType 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.beans.factory.annotation.Value; // 导入 Value 类
import org.springframework.stereotype.Service; // 导入 Service 类

import java.io.IOException; // 导入 IOException 类

/** // 保留原作者写的块注释
 * @description 课程索引管理接口实现 // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @date 2022/9/25 7:23 // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
@Service // 使用注解 @Service
public class IndexServiceImpl implements IndexService { // 定义 class IndexServiceImpl



 @Autowired // 使用注解 @Autowired
 RestHighLevelClient client; // 执行语句

 @Override // 使用注解 @Override
 public Boolean addCourseIndex(String indexName,String id,Object object) { // 定义方法 addCourseIndex(...)
  // 将课程数据转换为js // 保留原作者写的行内注释
  String jsonString = JSON.toJSONString(object); // 把 JSON.toJSONString(object) 赋值给 jsonString
  // 将索引存储 // 保留原作者写的行内注释
  IndexRequest indexRequest = new IndexRequest(indexName).id(id); // 创建 IndexRequest 对象并赋值给 indexRequest
  //指定索引文档内容 // 保留原作者写的行内注释
  // XContentType.JSON是json格式 // 保留原作者写的行内注释
  indexRequest.source(jsonString,XContentType.JSON); // 执行语句
  //索引响应对象 // 保留原作者写的行内注释
  IndexResponse indexResponse = null; // 把变量 indexResponse 初始化为 null
  try { // 尝试执行可能抛出异常的代码
   // 将索引存储到es // 保留原作者写的行内注释
   indexResponse = client.index(indexRequest, RequestOptions.DEFAULT); // 把 client.index(indexRequest, RequestOptions.DEFAULT) 赋值给 indexResponse
  } catch (IOException e) { // 定义方法 catch(...)
   log.error("添加索引出错:{}",e.getMessage()); // 执行语句
   e.printStackTrace(); // 执行语句
   XueChengPlusException.cast("添加索引出错"); // 执行语句
  } // 代码块结束
  String name = indexResponse.getResult().name(); // 把 indexResponse.getResult().name() 的返回值赋给 name
  System.out.println(name); // 执行语句
  return name.equalsIgnoreCase("created") || name.equalsIgnoreCase("updated"); // 返回 name.equalsIgnoreCase("created") || name.equalsIgnoreCase("updated")

 } // 代码块结束

 @Override // 使用注解 @Override
 public Boolean updateCourseIndex(String indexName,String id,Object object) { // 定义方法 updateCourseIndex(...)

  String jsonString = JSON.toJSONString(object); // 把 JSON.toJSONString(object) 赋值给 jsonString
  UpdateRequest updateRequest = new UpdateRequest(indexName, id); // 创建 UpdateRequest 对象并赋值给 updateRequest
  updateRequest.doc(jsonString, XContentType.JSON); // 执行语句
  UpdateResponse updateResponse = null; // 把变量 updateResponse 初始化为 null
  try { // 尝试执行可能抛出异常的代码
   updateResponse = client.update(updateRequest, RequestOptions.DEFAULT); // 把 client.update(updateRequest, RequestOptions.DEFAULT) 赋值给 updateResponse
  } catch (IOException e) { // 定义方法 catch(...)
   log.error("更新索引出错:{}",e.getMessage()); // 执行语句
   e.printStackTrace(); // 执行语句
   XueChengPlusException.cast("更新索引出错"); // 执行语句
  } // 代码块结束
  DocWriteResponse.Result result = updateResponse.getResult(); // 把 updateResponse.getResult() 的返回值赋给 result
  return result.name().equalsIgnoreCase("updated"); // 返回 result.name().equalsIgnoreCase("updated")

 } // 代码块结束

 @Override // 使用注解 @Override
 public Boolean deleteCourseIndex(String indexName,String id) { // 定义方法 deleteCourseIndex(...)

  //删除索引请求对象 // 保留原作者写的行内注释
  DeleteRequest deleteRequest = new DeleteRequest(indexName,id); // 创建 DeleteRequest 对象并赋值给 deleteRequest
  //响应对象 // 保留原作者写的行内注释
  DeleteResponse deleteResponse = null; // 把变量 deleteResponse 初始化为 null
  try { // 尝试执行可能抛出异常的代码
   deleteResponse = client.delete(deleteRequest, RequestOptions.DEFAULT); // 把 client.delete(deleteRequest, RequestOptions.DEFAULT) 赋值给 deleteResponse
  } catch (IOException e) { // 定义方法 catch(...)
   log.error("删除索引出错:{}",e.getMessage()); // 执行语句
   e.printStackTrace(); // 执行语句
   XueChengPlusException.cast("删除索引出错"); // 执行语句
  } // 代码块结束
  //获取响应结果 // 保留原作者写的行内注释
  DocWriteResponse.Result result = deleteResponse.getResult(); // 把 deleteResponse.getResult() 的返回值赋给 result
  return result.name().equalsIgnoreCase("deleted"); // 返回 result.name().equalsIgnoreCase("deleted")
 } // 代码块结束
} // 代码块结束

文件:xuecheng-plus-search/src/main/java/com/xuecheng/search/service/IndexService.java

package com.xuecheng.search.service; // 声明类所在的包路径

import com.xuecheng.search.po.CourseIndex; // 导入 CourseIndex 类

/** // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 * @description 课程索引service // 保留原作者写的块注释
 * @date 2022/9/24 22:40 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
public interface IndexService { // 定义 interface IndexService
    //增,删,改 // 保留原作者写的行内注释

    /** // 保留原作者写的块注释
     * @param indexName 索引名称 // 保留原作者写的块注释
     * @param id 主键 // 保留原作者写的块注释
     * @param object 索引对象 // 保留原作者写的块注释
     * @return Boolean true表示成功,false失败 // 保留原作者写的块注释
     * @description 添加索引 // 保留原作者写的块注释
     * @author Mr.M // 保留原作者写的块注释
     * @date 2022/9/24 22:57 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    public Boolean addCourseIndex(String indexName,String id,Object object); // 执行语句


    /** // 保留原作者写的块注释
     * @description 更新索引 // 保留原作者写的块注释
     * @param indexName 索引名称 // 保留原作者写的块注释
     * @param id 主键 // 保留原作者写的块注释
     * @param object 索引对象 // 保留原作者写的块注释
     * @return Boolean true表示成功,false失败 // 保留原作者写的块注释
     * @author Mr.M // 保留原作者写的块注释
     * @date 2022/9/25 7:49 // 保留原作者写的块注释
    */ // 保留原作者写的块注释
    public Boolean updateCourseIndex(String indexName,String id,Object object); // 执行语句

    /** // 保留原作者写的块注释
     * @description 删除索引 // 保留原作者写的块注释
     * @param indexName 索引名称 // 保留原作者写的块注释
     * @param id  主键 // 保留原作者写的块注释
     * @return java.lang.Boolean // 保留原作者写的块注释
     * @author Mr.M // 保留原作者写的块注释
     * @date 2022/9/25 9:27 // 保留原作者写的块注释
    */ // 保留原作者写的块注释
    public Boolean deleteCourseIndex(String indexName,String id); // 执行语句

} // 代码块结束

文件:xuecheng-plus-search/src/main/java/com/xuecheng/SearchApplication.java

package com.xuecheng; // 声明类所在的包路径

import org.springframework.boot.SpringApplication; // 导入 SpringApplication 类
import org.springframework.boot.autoconfigure.SpringBootApplication; // 导入 SpringBootApplication 类

@SpringBootApplication // 使用注解 @SpringBootApplication
public class SearchApplication { // 定义 class SearchApplication

    public static void main(String[] args) { // 定义方法 main(...)
        SpringApplication.run(SearchApplication.class, args); // 执行语句
    } // 代码块结束

} // 代码块结束

文件:xuecheng-plus-search/src/main/resources/bootstrap.yml

spring:
  application:
    name: search
  cloud:
    nacos:
      server-addr: 192.168.101.65:8848
      discovery:
        namespace: dev402
        group: xuecheng-plus-project
      config:
        namespace: dev402
        group: xuecheng-plus-project
        file-extension: yaml
        refresh-enabled: true
        shared-configs:
          - data-id: swagger-${spring.profiles.active}.yaml
            group: xuecheng-plus-common
            refresh: true
          - data-id: logging-${spring.profiles.active}.yaml
            group: xuecheng-plus-common
            refresh: true

  profiles:
    active: dev

文件:xuecheng-plus-search/src/main/resources/log4j2-dev.xml

<?xml version="1.0" encoding="UTF-8"?> <!-- XML 声明 -->
<Configuration monitorInterval="180" packages=""> <!-- SQL 语句片段 -->
    <properties> <!-- SQL 语句片段 -->
        <property name="logdir">logs</property> <!-- SQL 语句片段 -->
        <property name="PATTERN">%date{YYYY-MM-dd HH:mm:ss,SSS} %level [%thread][%file:%line] - %msg%n%throwable</property> <!-- SQL 语句片段 -->
    </properties> <!-- SQL 语句片段 -->
    <Appenders> <!-- SQL 语句片段 -->
        <Console name="Console" target="SYSTEM_OUT"> <!-- SQL 语句片段 -->
            <PatternLayout pattern="${PATTERN}"/> <!-- SQL 语句片段 -->
        </Console> <!-- SQL 语句片段 -->

        <RollingFile name="ErrorAppender" fileName="${logdir}/error.log" <!-- SQL 语句片段 -->
            filePattern="${logdir}/$${date:yyyy-MM-dd}/error.%d{yyyy-MM-dd-HH}.log" append="true"> <!-- SQL 语句片段 -->
            <PatternLayout pattern="${PATTERN}"/> <!-- SQL 语句片段 -->
            <ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/> <!-- SQL 语句片段 -->
            <Policies> <!-- SQL 语句片段 -->
                <TimeBasedTriggeringPolicy interval="1" modulate="true" /> <!-- SQL 语句片段 -->
            </Policies> <!-- SQL 语句片段 -->
        </RollingFile> <!-- SQL 语句片段 -->

        <RollingFile name="DebugAppender" fileName="${logdir}/info.log" <!-- SQL 语句片段 -->
            filePattern="${logdir}/$${date:yyyy-MM-dd}/info.%d{yyyy-MM-dd-HH}.log" append="true"> <!-- SQL 语句片段 -->
            <PatternLayout pattern="${PATTERN}"/> <!-- SQL 语句片段 -->
            <ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/> <!-- SQL 语句片段 -->
            <Policies> <!-- SQL 语句片段 -->
                <TimeBasedTriggeringPolicy interval="1" modulate="true" /> <!-- SQL 语句片段 -->
            </Policies> <!-- SQL 语句片段 -->
        </RollingFile> <!-- SQL 语句片段 -->
        
        <!--异步appender-->
         <Async name="AsyncAppender" includeLocation="true"> <!-- SQL 语句片段 -->
            <AppenderRef ref="ErrorAppender"/> <!-- SQL 语句片段 -->
            <AppenderRef ref="DebugAppender"/> <!-- SQL 语句片段 -->
        </Async> <!-- SQL 语句片段 -->
    </Appenders> <!-- SQL 语句片段 -->
    
    <Loggers> <!-- SQL 语句片段 -->
         <!--过滤掉spring和mybatis的一些无用的debug信息-->
        <logger name="org.springframework" level="INFO"> <!-- SQL 语句片段 -->
        </logger> <!-- SQL 语句片段 -->
        <logger name="org.mybatis" level="INFO"> <!-- SQL 语句片段 -->
        </logger> <!-- SQL 语句片段 -->
        <logger name="cn.itcast.wanxinp2p.consumer.mapper" level="DEBUG"> <!-- SQL 语句片段 -->
        </logger> <!-- SQL 语句片段 -->

        <logger name="springfox" level="INFO"> <!-- SQL 语句片段 -->
        </logger> <!-- SQL 语句片段 -->
		<logger name="org.apache.http" level="INFO"> <!-- SQL 语句片段 -->
        </logger> <!-- SQL 语句片段 -->
        <logger name="com.netflix.discovery" level="INFO"> <!-- SQL 语句片段 -->
        </logger> <!-- SQL 语句片段 -->
        
        <logger name="RocketmqCommon"  level="INFO" > <!-- SQL 语句片段 -->
		</logger> <!-- SQL 语句片段 -->
		
		<logger name="RocketmqRemoting" level="INFO"  > <!-- SQL 语句片段 -->
		</logger> <!-- SQL 语句片段 -->
		
		<logger name="RocketmqClient" level="WARN"> <!-- SQL 语句片段 -->
		</logger> <!-- SQL 语句片段 -->

        <logger name="org.dromara.hmily" level="WARN"> <!-- SQL 语句片段 -->
        </logger> <!-- SQL 语句片段 -->

        <logger name="org.dromara.hmily.lottery" level="WARN"> <!-- SQL 语句片段 -->
        </logger> <!-- SQL 语句片段 -->

        <logger name="org.dromara.hmily.bonuspoint" level="WARN"> <!-- SQL 语句片段 -->
        </logger> <!-- SQL 语句片段 -->
		
        <!--OFF   0-->
        <!--FATAL   100-->
        <!--ERROR   200-->
        <!--WARN   300-->
        <!--INFO   400-->
        <!--DEBUG   500-->
        <!--TRACE   600-->
        <!--ALL   Integer.MAX_VALUE-->
        <Root level="DEBUG" includeLocation="true"> <!-- SQL 语句片段 -->
            <AppenderRef ref="AsyncAppender"/> <!-- SQL 语句片段 -->
            <AppenderRef ref="Console"/> <!-- SQL 语句片段 -->
            <AppenderRef ref="DebugAppender"/> <!-- SQL 语句片段 -->
        </Root> <!-- SQL 语句片段 -->
    </Loggers> <!-- SQL 语句片段 -->
</Configuration> <!-- SQL 语句片段 -->

文件:xuecheng-plus-search/src/test/java/com/xuecheng/search/CourseIndexSearchTest.java

package com.xuecheng.search; // 声明类所在的包路径

import com.xuecheng.search.po.CourseIndex; // 导入 CourseIndex 类
import com.xuecheng.search.service.IndexService; // 导入 IndexService 类
import org.junit.jupiter.api.Test; // 导入 Test 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.beans.factory.annotation.Value; // 导入 Value 类
import org.springframework.boot.test.context.SpringBootTest; // 导入 SpringBootTest 类

import java.time.LocalDateTime; // 导入 LocalDateTime 类

/** // 保留原作者写的块注释
 * @description 课程索引与搜索测试 // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @date 2022/9/25 7:39 // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
 @SpringBootTest // 使用注解 @SpringBootTest
public class CourseIndexSearchTest { // 定义 class CourseIndexSearchTest


  @Value("${elasticsearch.course.index}") // 使用注解 @Value("${elasticsearch.course.index}")
  private String courseIndexStore; // 执行语句

  @Autowired // 使用注解 @Autowired
  IndexService courseIndexService; // 执行语句

  @Test // 使用注解 @Test
 public void test_addindex(){ // 定义方法 test_addindex(...)

   CourseIndex courseIndex = new CourseIndex(); // 创建 CourseIndex 对象并赋值给 courseIndex
   courseIndex.setId(101L); // 执行语句
   courseIndex.setName("Java编程思想"); // 执行语句
   courseIndex.setDescription("《Java编程思想》是2007年6月1日机械工业出版社出版的图书,作者是埃克尔,译者是陈昊鹏。主要内容本书赢得了全球程序员的广泛赞誉,即使是最晦涩的概念,在Bruce Eckel的文字亲和力和小而直接的编程示例面前也会化解于无形。从Java的基础语法到最高级特性(深入的面向对象概念、多线程、自动项目构建、单元测试和调试等),本书都能逐步指导你轻松掌握。从本书获得的各项大奖以及来自世界各地的读者评论中,不难看出这是一本经典之作"); // 执行语句
   courseIndex.setCompanyId(100000L); // 执行语句
   courseIndex.setCompanyName("北京黑马程序"); // 执行语句
   courseIndex.setCharge("10011"); // 执行语句
   courseIndex.setMt("1-1"); // 执行语句
   courseIndex.setSt("1-1-1"); // 执行语句
   courseIndex.setMtName("后端编程"); // 执行语句
   courseIndex.setStName("Java语言"); // 执行语句
   courseIndex.setGrade("20202"); // 执行语句
   courseIndex.setCreateDate(LocalDateTime.now()); // 执行语句
   courseIndex.setPic("http://file.xuecheng-plus.com/mediafiles/ssss.jpg"); // 代码逻辑
   courseIndex.setPrice(100f); // 执行语句
   courseIndex.setOriginalPrice(200f); // 执行语句
   courseIndex.setRemark("没有备注"); // 执行语句
   courseIndex.setStatus("1"); // 执行语句
   courseIndex.setTags("没有标签"); // 执行语句
   courseIndex.setValidDays(222); // 执行语句
   courseIndex.setTeachmode("40020"); // 执行语句

   Boolean result = courseIndexService.addCourseIndex(courseIndexStore,"101",courseIndex); // 把 courseIndexService.addCourseIndex(courseIndexStore,"101",courseIndex) 赋值给 result
   System.out.println(result); // 执行语句

  } // 代码块结束
  @Test // 使用注解 @Test
 public void test_updateIndex(){ // 定义方法 test_updateIndex(...)

   CourseIndex courseIndex = new CourseIndex(); // 创建 CourseIndex 对象并赋值给 courseIndex
   courseIndex.setId(101L); // 执行语句
   courseIndex.setName("Java编程思想"); // 执行语句
   courseIndex.setDescription("《Java编程思想》是2007年6月1日机械工业出版社出版的图书,作者是埃克尔,译者是陈昊鹏。主要内容本书赢得了全球程序员的广泛赞誉,即使是最晦涩的概念,在Bruce Eckel的文字亲和力和小而直接的编程示例面前也会化解于无形。从Java的基础语法到最高级特性(深入的面向对象概念、多线程、自动项目构建、单元测试和调试等),本书都能逐步指导你轻松掌握。从本书获得的各项大奖以及来自世界各地的读者评论中,不难看出这是一本经典之作"); // 执行语句
   courseIndex.setCompanyId(100000L); // 执行语句
   courseIndex.setCompanyName("北京黑马程序"); // 执行语句
   courseIndex.setCharge("10011"); // 执行语句
   courseIndex.setMt("1-1"); // 执行语句
   courseIndex.setSt("1-1-1"); // 执行语句
   courseIndex.setMtName("后端编程"); // 执行语句
   courseIndex.setStName("Java语言"); // 执行语句
   courseIndex.setGrade("20202"); // 执行语句
   courseIndex.setCreateDate(LocalDateTime.now()); // 执行语句
   courseIndex.setPic("http://file.xuecheng-plus.com/mediafiles/ssss.jpg"); // 代码逻辑
   courseIndex.setPrice(100f); // 执行语句
   courseIndex.setOriginalPrice(200f); // 执行语句
   courseIndex.setRemark("没有备注"); // 执行语句
   courseIndex.setStatus("1"); // 执行语句
   courseIndex.setTags("没有标签"); // 执行语句
   courseIndex.setValidDays(222); // 执行语句
   courseIndex.setTeachmode("40020"); // 执行语句

   Boolean result = courseIndexService.updateCourseIndex(courseIndexStore,"101",courseIndex); // 把 courseIndexService.updateCourseIndex(courseIndexStore,"101",courseIndex) 赋值给 result
   System.out.println(result); // 执行语句

  } // 代码块结束
} // 代码块结束

文件:xuecheng-plus-search/src/test/java/com/xuecheng/search/SearchApplication.java

package com.xuecheng.search; // 声明类所在的包路径

import org.springframework.boot.SpringApplication; // 导入 SpringApplication 类
import org.springframework.boot.autoconfigure.SpringBootApplication; // 导入 SpringBootApplication 类

@SpringBootApplication // 使用注解 @SpringBootApplication
public class SearchApplication { // 定义 class SearchApplication

    public static void main(String[] args) { // 定义方法 main(...)
        SpringApplication.run(SearchApplication.class, args); // 执行语句
    } // 代码块结束

} // 代码块结束

文件:xuecheng-plus-search/test/com/xuecheng/search/CourseIndexSearchTest.java

package com.xuecheng.search; // 声明类所在的包路径

import com.xuecheng.search.po.CourseIndex; // 导入 CourseIndex 类
import com.xuecheng.search.service.IndexService; // 导入 IndexService 类
import org.junit.jupiter.api.Test; // 导入 Test 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.beans.factory.annotation.Value; // 导入 Value 类
import org.springframework.boot.test.context.SpringBootTest; // 导入 SpringBootTest 类

import java.time.LocalDateTime; // 导入 LocalDateTime 类

/** // 保留原作者写的块注释
 * @description 课程索引与搜索测试 // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @date 2022/9/25 7:39 // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
 @SpringBootTest // 使用注解 @SpringBootTest
public class CourseIndexSearchTest { // 定义 class CourseIndexSearchTest


  @Value("${elasticsearch.course.index}") // 使用注解 @Value("${elasticsearch.course.index}")
  private String courseIndexStore; // 执行语句

  @Autowired // 使用注解 @Autowired
  IndexService courseIndexService; // 执行语句

  @Test // 使用注解 @Test
 public void test_addindex(){ // 定义方法 test_addindex(...)

   CourseIndex courseIndex = new CourseIndex(); // 创建 CourseIndex 对象并赋值给 courseIndex
   courseIndex.setId(101L); // 执行语句
   courseIndex.setName("Java编程思想"); // 执行语句
   courseIndex.setDescription("《Java编程思想》是2007年6月1日机械工业出版社出版的图书,作者是埃克尔,译者是陈昊鹏。主要内容本书赢得了全球程序员的广泛赞誉,即使是最晦涩的概念,在Bruce Eckel的文字亲和力和小而直接的编程示例面前也会化解于无形。从Java的基础语法到最高级特性(深入的面向对象概念、多线程、自动项目构建、单元测试和调试等),本书都能逐步指导你轻松掌握。从本书获得的各项大奖以及来自世界各地的读者评论中,不难看出这是一本经典之作"); // 执行语句
   courseIndex.setCompanyId(100000L); // 执行语句
   courseIndex.setCompanyName("北京黑马程序"); // 执行语句
   courseIndex.setCharge("10011"); // 执行语句
   courseIndex.setMt("1-1"); // 执行语句
   courseIndex.setSt("1-1-1"); // 执行语句
   courseIndex.setMtName("后端编程"); // 执行语句
   courseIndex.setStName("Java语言"); // 执行语句
   courseIndex.setGrade("20202"); // 执行语句
   courseIndex.setCreateDate(LocalDateTime.now()); // 执行语句
   courseIndex.setPic("http://file.xuecheng-plus.com/mediafiles/ssss.jpg"); // 代码逻辑
   courseIndex.setPrice(100f); // 执行语句
   courseIndex.setOriginalPrice(200f); // 执行语句
   courseIndex.setRemark("没有备注"); // 执行语句
   courseIndex.setStatus("1"); // 执行语句
   courseIndex.setTags("没有标签"); // 执行语句
   courseIndex.setValidDays(222); // 执行语句
   courseIndex.setTeachmode("40020"); // 执行语句

   Boolean result = courseIndexService.addCourseIndex(courseIndexStore,"101",courseIndex); // 把 courseIndexService.addCourseIndex(courseIndexStore,"101",courseIndex) 赋值给 result
   System.out.println(result); // 执行语句

  } // 代码块结束
  @Test // 使用注解 @Test
 public void test_updateIndex(){ // 定义方法 test_updateIndex(...)

   CourseIndex courseIndex = new CourseIndex(); // 创建 CourseIndex 对象并赋值给 courseIndex
   courseIndex.setId(101L); // 执行语句
   courseIndex.setName("Java编程思想"); // 执行语句
   courseIndex.setDescription("《Java编程思想》是2007年6月1日机械工业出版社出版的图书,作者是埃克尔,译者是陈昊鹏。主要内容本书赢得了全球程序员的广泛赞誉,即使是最晦涩的概念,在Bruce Eckel的文字亲和力和小而直接的编程示例面前也会化解于无形。从Java的基础语法到最高级特性(深入的面向对象概念、多线程、自动项目构建、单元测试和调试等),本书都能逐步指导你轻松掌握。从本书获得的各项大奖以及来自世界各地的读者评论中,不难看出这是一本经典之作"); // 执行语句
   courseIndex.setCompanyId(100000L); // 执行语句
   courseIndex.setCompanyName("北京黑马程序"); // 执行语句
   courseIndex.setCharge("10011"); // 执行语句
   courseIndex.setMt("1-1"); // 执行语句
   courseIndex.setSt("1-1-1"); // 执行语句
   courseIndex.setMtName("后端编程"); // 执行语句
   courseIndex.setStName("Java语言"); // 执行语句
   courseIndex.setGrade("20202"); // 执行语句
   courseIndex.setCreateDate(LocalDateTime.now()); // 执行语句
   courseIndex.setPic("http://file.xuecheng-plus.com/mediafiles/ssss.jpg"); // 代码逻辑
   courseIndex.setPrice(100f); // 执行语句
   courseIndex.setOriginalPrice(200f); // 执行语句
   courseIndex.setRemark("没有备注"); // 执行语句
   courseIndex.setStatus("1"); // 执行语句
   courseIndex.setTags("没有标签"); // 执行语句
   courseIndex.setValidDays(222); // 执行语句
   courseIndex.setTeachmode("40020"); // 执行语句

   Boolean result = courseIndexService.updateCourseIndex(courseIndexStore,"101",courseIndex); // 把 courseIndexService.updateCourseIndex(courseIndexStore,"101",courseIndex) 赋值给 result
   System.out.println(result); // 执行语句

  } // 代码块结束
} // 代码块结束

文件:xuecheng-plus-search/test/com/xuecheng/search/SearchApplication.java

package com.xuecheng.search; // 声明类所在的包路径

import org.springframework.boot.SpringApplication; // 导入 SpringApplication 类
import org.springframework.boot.autoconfigure.SpringBootApplication; // 导入 SpringBootApplication 类

@SpringBootApplication // 使用注解 @SpringBootApplication
public class SearchApplication { // 定义 class SearchApplication

    public static void main(String[] args) { // 定义方法 main(...)
        SpringApplication.run(SearchApplication.class, args); // 执行语句
    } // 代码块结束

} // 代码块结束
appendix_I
https://clxhxhhr.top/posts/4376/
作者
clxstart
发布于
2026-09-26
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。