基于SpringBoot的ES整合
Elasticsearch(ES)的作用可看之前的课件
这儿直接演示使用ES检索学习资料的功能。
步骤一:引入相关依赖,在文件中smpe-system下的pom.xml中引入下面依赖
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<!-- 这儿的版本需要和本地的版本保持一致 -->
<version>7.8.0</version>
</dependency>
步骤二:添加一个配置类,新建目录层级tiku/config/ElasticSearchClientConfig
[图片上传失败...(image-61aba2-1650806738439)]
@Configuration
public class ElasticSearchClientConfig {
@Bean
public RestHighLevelClient restHighLevelClient() {
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(new HttpHost("127.0.0.1", 9200, "http"))
);
return client;
}
}
步骤三:项目启动的时候将需要的数据加载进ES中
@Component
@Slf4j
@RequiredArgsConstructor
public class StudyDataRunner implements ApplicationRunner {
private final RestHighLevelClient restHighLevelClient;
private final IEStudyDataService studyDataService;
@Override
public void run(ApplicationArguments args) throws Exception {
// 查询所有的学习资料数据,加载到es中
log.info("往es中存储数据开始------------");
PageVO pageVO = new PageVO();
pageVO.setSize(-1);
pageVO.setCurrent(-1);
IPage<EStudyData> eStudyDataIPage = studyDataService.queryAll(new StudyDataQueryCriteria(), pageVO);
List<EStudyData> records = eStudyDataIPage.getRecords();
BulkRequest bulkRequest = new BulkRequest();
bulkRequest.timeout("2m");
for (EStudyData record : records) {
bulkRequest.add(new IndexRequest("study_data").source(JSON.toJSONString(record), XContentType.JSON));
}
restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
log.info("es存储数据结束----------------");
}
}
步骤四:对接查询操作
@ApiOperation(value="前台:分页查询某个安全类别的学习资料",notes="\n anthor:mfei")
@AnonymousGetMapping("/front-all")
public Result<Object> queryES(Long safeTypeId, String keyword,PageVO pageVO){
pageVO.setOrders("[{'column': 'create_time','asc': false}]");
StudyDataQueryCriteria criteria = new StudyDataQueryCriteria();
criteria.setKeywords(keyword);
criteria.setSafeTypeId(safeTypeId);
return Result.success(eStudyDataService.queryAllByES(criteria,pageVO));
}
}
IEStudyDataService接口
IPage<EStudyData> queryAllByES(StudyDataQueryCriteria criteria, PageVO pageVO);
实现类
@Override
public IPage<EStudyData> queryAllByES(StudyDataQueryCriteria criteria, PageVO pageVO) {
List<EStudyData> eStudyDataList = new ArrayList<>();
SearchRequest searchRequest = new SearchRequest("study_data");
// 构建搜索条件
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
if (ObjectUtil.isNotNull(criteria.getKeywords())){
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
.should(QueryBuilders.matchQuery("title", criteria.getKeywords()))
.should(QueryBuilders.matchQuery("keywords", criteria.getKeywords()));
sourceBuilder.query(boolQueryBuilder);
//构建高亮查询
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.requireFieldMatch(true); // 多个高亮显示
highlightBuilder.field("title");
highlightBuilder.preTags("<span style='color:red'>").postTags("</span>");
sourceBuilder.highlighter(highlightBuilder);
}
if (ObjectUtil.isNotNull(criteria.getSafeTypeId())) {
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("safeTypeId", criteria.getSafeTypeId());
sourceBuilder.query(termQueryBuilder);
}
searchRequest.source(sourceBuilder);
try {
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
for (SearchHit documentFields : searchResponse.getHits().getHits()) {
Map<String, HighlightField> highlightFields = documentFields.getHighlightFields();
HighlightField title = highlightFields.get("title");
Map<String, Object> sourceAsMap = documentFields.getSourceAsMap();// 最开始的结果
if (ObjectUtil.isNotNull(title)) {
Text[] fragments = title.fragments();
String n_title = "";
for (Text fragment : fragments) {
n_title += fragment;
}
sourceAsMap.put("title", n_title);
}
EStudyData eStudyData = BeanUtil.fillBeanWithMap(sourceAsMap, new EStudyData(), false);
eStudyDataList.add(eStudyData);
}
} catch (IOException e) {
e.printStackTrace();
}
IPage<EStudyData> eStudyDataIPage = new Page<>();
eStudyDataIPage.setRecords(eStudyDataList);
return eStudyDataIPage;
}
题库练习模块实现
- 查询该类型下所有的题型(ERepositoryController中)
/**
* 前台调用 返回题库和练习记录id
*
* @param id
* @return
*/
@ApiOperation(value = "按安全分类id查询")
@GetMapping(value = "/getBySafeTypeId")
public Result<ERepositoryAndPracticeRecordDTO> getRepositoryBySafeTypeId(Long id) {
if (id == null || id <= 0) {
throw new BadRequestException("id不能为空,且id不能小于0");
}
ERepositoryAndPracticeRecordDTO eRepositoryAndPracticeRecordDTO = eRepositoryService.getRepositoryAndPracticeRecordIdBySafeTypeId(id);
return Result.success(eRepositoryAndPracticeRecordDTO);
}
返回对象ERepositoryAndPracticeRecordDTO为
[图片上传失败...(image-bbead3-1650806738439)]
[图片上传失败...(image-f674ba-1650806738439)]
定义IERepositoryService中的查询接口
/**
* 根据分类id查询题目(前台 返回某个分类的全部题库和练习记录表中的id)
* @param id
* @return
*/
ERepositoryAndPracticeRecordDTO getRepositoryAndPracticeRecordIdBySafeTypeId(Long id);
实现方法
@Service
@RequiredArgsConstructor
@CacheConfig(cacheNames = "repository")
public class ERepositoryServiceImpl extends BasicServiceImpl<ERepositoryMapper, ERepository> implements IERepositoryService {
-----------------------------------------------------------------------------------------------------
@Override
@Cacheable(key = "'safeTypeId:'+ #safeTypeId")
public ERepositoryAndPracticeRecordDTO getRepositoryAndPracticeRecordIdBySafeTypeId(Long safeTypeId) {
// 声明返回的数据
ERepositoryAndPracticeRecordDTO practiceRecordDTO = new ERepositoryAndPracticeRecordDTO();
Long practiceRecordId = null;
Long userId = SecurityUtils.getCurrentUserId();
// 查询联系记录表中该用户的该分类数据
List<EPracticeRecord> practiceRecordList = ePracticeRecordMapper.getByUserIdAndSafeTypeId(userId, safeTypeId);
if (practiceRecordList.size() == 0) {
EPracticeRecord ePracticeRecord = new EPracticeRecord();
ePracticeRecord.setUserId(userId);
ePracticeRecord.setSafeTypeId(safeTypeId);
ePracticeRecordMapper.insert(ePracticeRecord);
practiceRecordId = ePracticeRecord.getId();
} else {
practiceRecordId = practiceRecordList.get(0).getId();
}
LambdaQueryWrapper<ERepository> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(ERepository::getSafeTypeId,safeTypeId);
PageVO pageVO = new PageVO();
// 查询该分类下所有的题库信息
IPage<ERepositoryDto> dtoIPage = eRepositoryMapper.selectRepositoryPage(pageVO.buildPage(), queryWrapper);
practiceRecordDTO.setPracticeRecordId(practiceRecordId);
practiceRecordDTO.setERepositoryDTOS(dtoIPage.getRecords());
return practiceRecordDTO;
}
@RequiredArgsConstructor
@RestController
@Slf4j
@Api(tags = "题库练习记录模块")
@RequestMapping("/api/ePracticeRecord")
public class EPracticeRecordController {
private final IEPracticeRecordService ePracticeRecordService;
/**
* 前台调用 传练习记录id
* @param id
* @return
*/
@ApiOperation(value = "根据练习记录id查询练习记录")
@GetMapping(value = "/getEPracticeRecordById")
public Result<List<EPracticeRecord>> getEPraticeRecord(Long id){
return Result.success(ePracticeRecordService.getEPracticeRecordByIdForReids(id));
}
@ApiOperation(value = "添加练习记录")
@PostMapping
public Result<Void> insertEPracticeRecord(@RequestBody EPracticeRecord ePracticeRecord){
ePracticeRecordService.addPracticeRecord(ePracticeRecord);
return Result.success();
}
}
public interface IEPracticeRecordService extends IBasicService<EPracticeRecord> {
/**
* 通过id查找redis中的练习记录
* @param id 练习记录id
* @return
*/
List<EPracticeRecord> getEPracticeRecordByIdForReids(Long id);
/**
* 用户每次点下一题,将上一题的练习记录存入缓存
*
* @param ePracticeRecord
*/
void addPracticeRecord(EPracticeRecord ePracticeRecord);
}
@Service
@RequiredArgsConstructor
public class EPracticeRecordServiceImpl extends BasicServiceImpl<EPracticeRecordMapper, EPracticeRecord> implements IEPracticeRecordService {
private final EPracticeRecordMapper ePracticeRecordMapper;
private final RedisUtils redisUtils;
@Override
public List<EPracticeRecord> getEPracticeRecordByIdForReids(Long id) {
List<EPracticeRecord> ePracticeRecordList = new ArrayList<>();
// EPracticeRecord ePracticeRecord = new EPracticeRecord();
Map<String, Object> ePracticeRecordRedis = new HashMap<>();
String key = CacheKey.PRACTICERECORD + id;
if (redisUtils.hasKey(key)) {
ePracticeRecordRedis =(Map<String, Object>) (Object) redisUtils.hmget(key);
Set<String> keySet = ePracticeRecordRedis.keySet();
for (Object keyReposiId : keySet) {
EPracticeRecord ePracticeRecord = new EPracticeRecord();
ePracticeRecord.setId(id);
ePracticeRecord.setFinishRepoIds((String) keyReposiId);
ePracticeRecord.setFinishQuesAnswer((String) ePracticeRecordRedis.get(keyReposiId));
ePracticeRecordList.add(ePracticeRecord);
}
return ePracticeRecordList;
}
//若redis中的key已过期,说明练习记录已入库,此时,需要查数据库
EPracticeRecord ePracticeRecord = ePracticeRecordMapper.selectById(id);
if (ObjectUtil.isNotNull(ePracticeRecord)) {
String repoidsString = ePracticeRecord.getFinishRepoIds();
String answersString = ePracticeRecord.getFinishQuesAnswer();
if (StrUtil.isNotBlank(repoidsString) && StrUtil.isNotBlank(answersString)) {
String[] repoids = repoidsString.split(",");
String[] answers = answersString.split(",");
for (int i = 0; i < repoids.length; i++) {
EPracticeRecord ePracticeRecord1 = new EPracticeRecord();
ePracticeRecordRedis.put(repoids[i],answers[i]);
ePracticeRecord1.setFinishRepoIds(repoids[i]);
ePracticeRecord1.setFinishQuesAnswer(answers[i]);
ePracticeRecordList.add(ePracticeRecord1);
}
//放入缓存
redisUtils.hmset(key, ePracticeRecordRedis);
}
}
return ePracticeRecordList;
}
@Override
public void addPracticeRecord(EPracticeRecord ePracticeRecord) {
Long practiceRecordId = ePracticeRecord.getId();
String key = CacheKey.PRACTICERECORD + practiceRecordId;
long time = Duration.between(LocalDateTime.now(), LocalDateTime.now().plusDays(2L)).getSeconds();
//用户练习记录存入缓存(key为练习记录id,map中的key为题目id,value为答案)
String answer = ePracticeRecord.getFinishQuesAnswer();
String repoId = ePracticeRecord.getFinishRepoIds();
if (!redisUtils.hasKey(key)) {
//没有此key,说明已经入库或者第一次添加记录
// 初始化redis
this.getEPracticeRecordByIdForReids(practiceRecordId);
}
redisUtils.hset(key, repoId, answer, time);
}
}
其中CacheKey.PRACTICERECORD为
/**
* 题库练习记录
*/
String PRACTICERECORD = "practiceRecord::practiceRecordId:";