- package com.admin.model;
-
-
- import com.fasterxml.jackson.annotation.JsonFormat;
- import com.admin.common.entity.BaseSJFZEntity;
- import lombok.Data;
- import org.springframework.data.elasticsearch.annotations.Document;
- import org.springframework.data.elasticsearch.annotations.Field;
- import org.springframework.data.elasticsearch.annotations.FieldType;
-
- import java.util.Date;
-
- /**
- * Es 索引库实体
- *
- * @author wangwei
- * @date 2024-04-25
- */
- /***
- * esmodel8、 esmodel9 是存储在es中的索引类型
- */
- @Document(indexName = "esmodel9")
- @Data
- public class EsModel extends BaseSJFZEntity {
-
- /*** 索引id*/
- @Field(type = FieldType.Long)
- private String id;
-
- /**** es中对应的数据库业务单据id*/
- @Field(analyzer = "ik_max_word")
- private String ctId;
-
- /**** es中业务数据 对应的业务数据库表名称*/
- @Field(analyzer = "ik_max_word")
- private String ctTableName;
-
- /**** es中业务数据 对应的 业务简称*/
- @Field(analyzer = "ik_max_word")
- private String ctName;
-
-
- /**** es中业务数据 对应的 业务内容详细信息*/
- @Field(analyzer = "ik_max_word")
- private String ctContent;
-
- /* *//** 创建者 *//*
- //@Field(analyzer = "ik_max_word")
- private String createUser;
-
- *//** 创建时间 *//*
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
- //@Field(analyzer = "ik_max_word")
- private Date createTime;
-
- *//** 更新者 *//*
- // @Field(analyzer = "ik_max_word")
- private String updateUser;
-
- *//** 更新时间 *//*
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
- // @Field(analyzer = "ik_max_word")
- private Date updateTime;*/
-
- /** 备注 */
- @Field(analyzer = "ik_max_word")
- private String remark;
-
- /** 备用1 */
- @Field(analyzer = "ik_max_word")
- private String by1;
-
- /** 备用2 */
- @Field(analyzer = "ik_max_word")
- private String by2;
-
- /** 备用3 */
- @Field(analyzer = "ik_max_word")
- private String by3;
-
- /** 备用4 */
- @Field(analyzer = "ik_max_word")
- private String by4;
-
- /** 备用5 */
- @Field(analyzer = "ik_max_word")
- private String by5;
-
- }
2.
- package com.admin.controller;
- import com.admin.common.annotation.Log;
- import com.admin.common.core.controller.BaseController;
- import com.admin.common.core.domain.AjaxResult;
- import com.admin.common.core.page.TableDataInfo;
- import com.admin.common.enums.BusinessType;
- import com.admin.model.EsModel;
- import com.admin.service.EsService;
- import io.swagger.annotations.Api;
- import io.swagger.annotations.ApiOperation;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.data.domain.Pageable;
- import org.springframework.web.bind.annotation.*;
-
- import java.util.List;
-
- /**
- * es -spi
- *
- * @author wangwei
- * @date 2024-04-25
- */
- @Api(tags = "ES-api")
- @RestController
- @RequestMapping("/es/api")
- public class EsController extends BaseController {
-
- @Autowired
- private EsService esService;
-
- /***
- *从es中按指定字段值获取数据
- * @param key
- * @return
- */
- @ApiOperation(value = "查询 从es中按指定字段值获取数据")
- @GetMapping("/list")
- public AjaxResult list(String key, Pageable pageable) {
- AjaxResult ajaxResult = esService.searchES(key, pageable);
- return ajaxResult;
- }
-
- /***
- * 全文检索
- *查询 从es中全文检索所包含的 业务数据信息
- * eg:es中的数据字段有 name, contene,等,接口查询条件key 包含在所有字段中的业务数据信息
- * @param key
- * @return
- */
- @ApiOperation(value = "查询 从es中全文检索所包含的 业务数据信息")
- @GetMapping("/whole")
- public TableDataInfo searchWhole(String key, Pageable pageable) {
- List<EsModel> list = esService.searchWhole(key, pageable);
- return getDataTable(list);
- }
-
- /****
- * es中数据新增
- */
- @ApiOperation(value = "es中数据新增" )
- @Log(title = "es中数据新增" , businessType = BusinessType.INSERT)
- @PostMapping
- public AjaxResult add(@RequestBody EsModel esModel) {
- return toAjax(esService.insertEsModel(esModel));
- }
-
- /****
- * es中数据修改
- */
- @ApiOperation(value = "es中数据修改" )
- @Log(title = "es中数据修改" , businessType = BusinessType.UPDATE)
- @PutMapping
- public AjaxResult put(@RequestBody EsModel esModel) {
- return toAjax(esService.updateEsModel(esModel));
- }
-
- /**
- * 删除es中的数据
- */
- @ApiOperation(value = "删除es中的数据")
- @Log(title = "删除es中的数据", businessType = BusinessType.DELETE)
- @DeleteMapping("/{ctId}")
- public AjaxResult remove(@PathVariable String ctId) {
- return toAjax(esService.deleteById(ctId));
- }
-
-
- }
3.
- package com.admin.service.impl;
-
- import com.admin.common.core.domain.AjaxResult;
- import com.admin.common.exception.CustomException;
- import com.admin.common.utils.StringUtils;
- import com.admin.constant.EsConstants;
- import com.admin.model.EsModel;
- import com.admin.repository.EsModelRepository;
- import com.admin.service.EsService;
- import com.admin.util.HighlightResultMapper;
- import com.alibaba.fastjson.JSON;
- import org.elasticsearch.action.update.UpdateRequest;
- import org.elasticsearch.action.update.UpdateResponse;
- import org.elasticsearch.client.RequestOptions;
- import org.elasticsearch.client.RestHighLevelClient;
- import org.elasticsearch.common.xcontent.XContentType;
- import org.elasticsearch.index.query.QueryBuilders;
- import org.elasticsearch.search.builder.SearchSourceBuilder;
- import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
- import org.elasticsearch.search.sort.SortBuilders;
- import org.elasticsearch.search.sort.SortOrder;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.data.domain.Page;
- import org.springframework.data.domain.Pageable;
- import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
- import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
- import org.springframework.data.elasticsearch.core.query.SearchQuery;
- import org.springframework.stereotype.Service;
- import java.io.IOException;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.UUID;
-
- import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
-
- @Service
- public class EsServiceImpl implements EsService {
-
- @Autowired
- private EsModelRepository esModelRepository;
-
- @Autowired
- private ElasticsearchRestTemplate elasticsearchRestTemplate;
-
- @Autowired
- private RestHighLevelClient client;
-
- @Override
- public AjaxResult searchES(String key, Pageable pageable) {
- Page<EsModel> ctContent = esModelRepository.findEsModelByCtContent(key, pageable);
- return AjaxResult.success(ctContent);
- }
-
- /***
- * 全文检索
- * @param key
- * @return
- */
- @Override
- public List<EsModel> searchWhole(String key, Pageable pageable) {
- //高亮字段设置
- String ctName = "ctName";
- String ctContent = "ctContent";
- String remark = "remark";
- String preTags = "color:#F56C6C\">";
- String postTags = "";
- HighlightBuilder.Field ctNameField = new HighlightBuilder.Field(ctName).preTags(preTags).postTags(postTags);
- HighlightBuilder.Field ctContentField = new HighlightBuilder.Field(ctContent).preTags(preTags).postTags(postTags);
- HighlightBuilder.Field remarkField = new HighlightBuilder.Field(remark).preTags(preTags).postTags(postTags);
-
- if (StringUtils.isEmpty(key)) {
- //throw new CustomException("请输入搜索内容!");
- List<EsModel> contentList = new ArrayList<>();
- return contentList;
- }
-
- //只要数据中包含就能检索到数据 (类似于模糊查询,有分词器的效果)
- //不同类别检索的进阶示例: https://www.cnblogs.com/jelly12345/p/14765477.html
- SearchQuery searchQuery = new NativeSearchQueryBuilder()
- .withPageable(pageable)//分页
- .withQuery(QueryBuilders.multiMatchQuery(key, "ctName", "ctContent", "remark"))
- .withHighlightFields(ctNameField, ctContentField, remarkField)//设置高亮
- // .withSort(SortBuilders.fieldSort("date").order(SortOrder.DESC))//排序
- .build();
-
- Page<EsModel> esModels = null;
- try {
- esModels = elasticsearchRestTemplate.queryForPage(searchQuery, EsModel.class, new HighlightResultMapper());
- }catch (Exception e){
- throw new CustomException("数据检索失败,请联系管理员处理!");
- }
-
- List<EsModel> contentList = esModels.getContent();
- return contentList;
- }
-
-
- /****
- *数据插入es中
- * @param esModel
- * @return
- */
- @Override
- public int insertEsModel(EsModel esModel) {
- try {
- esModel.setCtId(UUID.randomUUID().toString());
- EsModel save = esModelRepository.save(esModel);
- } catch (Exception e) {
- System.out.println("==================================错误信息是:"+e.getMessage()+"============================");
- throw new CustomException("ES数据新增失败,请联系管理员处理!");
- }
- return 1;
- }
-
- /***
- *es-update https://www.jb51.net/article/246798.htm
- * @param esModel
- * @return
- */
- @Override
- public int updateEsModel(EsModel esModel) {
- UpdateRequest updateRequest = new UpdateRequest(EsConstants.ES_INDEX, EsConstants.ES_INDEX_TYPE, String.valueOf(esModel.getCtId()));
- //更新 将对象转换为json
- updateRequest.doc(JSON.toJSONString(esModel), XContentType.JSON);
-
- //客户端发送请求,进行更新
- UpdateResponse update = null;
- try {
- update = client.update(updateRequest, RequestOptions.DEFAULT);
- } catch (IOException e) {
- throw new CustomException("ES数据同步失败可能原因是es中的业务ctId在数据库中不存在,请查看es客户端查询验证,请联系管理员处理!");
- }
-
- if (!"OK".equals(update.status().toString())) {
- throw new CustomException("ES数据修改失败,请联系管理员处理!");
- }
- return 1;
-
- }
-
- /***
- * 删除es中的数据
- * @param ctId
- * @return
- */
- @Override
- public int deleteById(String ctId) {
- try {
- esModelRepository.deleteById(ctId);
- }catch (Exception e){
- throw new CustomException("ES数据删除失败,请联系管理员处理!");
- }
- return 1;
- }
-
- }
-
-
4.
- package com.admin.repository;
- import com.admin.model.EsModel;
- import org.springframework.data.domain.Page;
- import org.springframework.data.domain.Pageable;
- import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
- import org.springframework.stereotype.Repository;
-
- /**
- * @author wangwei
- * @date 2024-04-25 14:12:36
- */
- @Repository
- public interface EsModelRepository extends ElasticsearchRepository<EsModel, String> {
-
-
- /*****
- * 这儿查询的 findBy 根据idea 的补全查询(eg:ByCtContent 将查询es中的 字段名称为 ctContent 中的值)
- * @param ket
- * @param pageable
- * @return
- */
- Page<EsModel> findEsModelByCtContent(String ket, Pageable pageable);
-
- /****
- * 删除es操作
- */
- public void deleteById(Long id);
-
-
- }
5.检索结果高亮显示
- package com.admin.util;
-
- import com.alibaba.fastjson.JSON;
- import org.elasticsearch.action.search.SearchResponse;
- import org.elasticsearch.search.SearchHit;
- import org.elasticsearch.search.SearchHits;
- import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
- import org.springframework.data.domain.Pageable;
- import org.springframework.data.elasticsearch.core.SearchResultMapper;
- import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
- import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
- import java.lang.reflect.Field;
-
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Map;
-
-
- /***
- * 检索高亮设置
- * @author wangwei
- * @date 2024-04-25 11:55
- */
- public class HighlightResultMapper implements SearchResultMapper {
- @Override
- public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
- long totalHits = response.getHits().getTotalHits();
- List<T> list = new ArrayList<>();
- SearchHits hits = response.getHits();
- if (hits.getHits().length> 0) {
- for (SearchHit searchHit : hits) {
- Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
- T item = JSON.parseObject(searchHit.getSourceAsString(), clazz);
- Field[] fields = clazz.getDeclaredFields();
- for (Field field : fields) {
- field.setAccessible(true);
- if (highlightFields.containsKey(field.getName())) {
- try {
- field.set(item, highlightFields.get(field.getName()).fragments()[0].toString());
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- }
- }
- }
- list.add(item);
- }
- }
- return new AggregatedPageImpl<>(list, pageable, totalHits);
- }
-
- @Override
- public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
- return null;
- }
- }
6.vue
- <template>
- <div class="app-container">
- <el-row :gutter="20">
-
- <!--用户数据-->
- <el-col :span="20" :xs="24">
- <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px" style="text-align: center">
- <el-form-item label="检索内容" prop="key" >
- <el-input
- v-model="queryParams.key"
- placeholder="请输入检索内容"
- clearable
- size="small"
- style="width: 240px"
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item>
- <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
- <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
- </el-form-item>
- </el-form>
-
-
- <el-table v-loading="loading" :data="tableList" >
- <el-table-column label="编号" align="center" key="ctId" prop="ctId" v-if="columns[0].visible" />
- <el-table-column label="名称" align="center" key="ctName" prop="ctName" v-if="columns[1].visible" :show-overflow-tooltip="true" />
- <el-table-column label="内容" align="center" key="ctContent" prop="ctContent" v-if="columns[2].visible" :show-overflow-tooltip="true" />
- <el-table-column label="备注" align="center" key="remark" prop="remark" v-if="columns[2].visible" :show-overflow-tooltip="true" />
- </el-table>
-
- <pagination
- v-show="total>0"
- :total="total"
- :page.sync="queryParams.number"
- :limit.sync="queryParams.size"
- @pagination="getList"
- />
- </el-col>
- </el-row>
-
- </div>
- </template>
-
- <script>
- import { list, getWholeList, addEsModel, editEsModel, removeEsModel} from "@/api/search";
-
- import { getToken } from "@/utils/auth";
- import { treeselect } from "@/api/system/dept";
- import Treeselect from "@riophae/vue-treeselect";
- import "@riophae/vue-treeselect/dist/vue-treeselect.css";
-
- export default {
- name: "User",
- components: { Treeselect },
- data() {
- return {
- // 遮罩层
- loading: true,
- // 选中数组
- ids: [],
- // 非单个禁用
- single: true,
- // 非多个禁用
- multiple: true,
- // 显示搜索条件
- showSearch: true,
- // 总条数
- total: 0,
- // 表格数据
- tableList: [],
- // 弹出层标题
- title: "",
- // 部门树选项
- deptOptions: undefined,
- // 是否显示弹出层
- open: false,
- // 部门名称
- deptName: undefined,
- // 默认密码
- initPassword: undefined,
- // 日期范围
- dateRange: [],
- // 状态数据字典
- statusOptions: [],
- // 性别状态字典
- sexOptions: [],
- // 岗位选项
- postOptions: [],
- // 角色选项
- roleOptions: [],
- // 表单参数
- form: {},
- defaultProps: {
- children: "children",
- label: "label"
- },
- // 查询参数
- queryParams: {
- number: 1,
- size: 10,
- },
- // 列信息
- columns: [
- { key: 0, label: `编号`, visible: true },
- { key: 1, label: `名称`, visible: true },
- { key: 2, label: `内容`, visible: true },
- ],
- // 表单校验
- rules: {
-
- }
- };
- },
- watch: {
-
- },
- created() {
- this.getList();
- },
- methods: {
- /** 查询用户列表 */
- getList() {
- this.loading = true;
- console.log(this.queryParams)
- getWholeList(this.queryParams).then(response => {
- this.tableList = response.rows;
- this.total = response.total;
- this.loading = false;
- });
- },
-
- // 取消按钮
- cancel() {
- this.open = false;
- this.reset();
- },
- // 表单重置
- reset() {
- this.form = {
- ctId: undefined,
- ctName: undefined,
- ctContent: undefined,
- remark: undefined,
- };
- this.resetForm("form");
- },
- /** 搜索按钮操作 */
- handleQuery() {
- //this.queryParams.page = 1;
- this.getList();
- },
- /** 重置按钮操作 */
- resetQuery() {
- this.dateRange = [];
- this.resetForm("queryForm");
- this.handleQuery();
- },
- }
- };
- </script>
7.