1. 业务开发
基本步骤:
- 配置字典
ES索引
增加索引配置 - 使用注解,在需要同步es的方法上面使用注解
- 创建模型Bean,创建业务es文档模型
- 创建Service,实现对es的curd
- 创建拦截Aop,创建业务es同步aop
- 创建搜索action,创建控制层对外部提供查询接口
[!tip]
下面代码片段截取自政务版本的内容搜索
1.1. 字典配置
通过配置字典ES索引
来增加es索引,特别注意字典的数据值
的json格式
{"name":"GovESContentBean","url":"/gov/es/sync.do"}
name:模型bean的名称,具体开发参考模型Bean
,必须与ESBaseBean
的子类上的@Component
名称一致;
url:es同步请求的方法,具体开发参考 同步方法
1.2. 注解
在对应的业务代码使用
1.2.1. @ESSave、@ESDelete
在对应的方法上进行注解,提供给aop进行拦截,
[!tip] 主要提供AOP拦截,在AOP中进行ES库的同步,所有涉及数据更新的地方都需要使用此注解
1.2.2. 实例
...
//保存方法
@ESSave
public ResultData save(@ModelAttribute ContentEntity content) {
contentBiz.saveEntity(_product);
return ResultData.build().success(_product);
}
//更新方法
@ESSave
public ResultData update(@ModelAttribute ContentEntity content) {
contentBiz.updateEntity(_product);
return ResultData.build().success(_product);
}
//删除方法
@ESDelete
public ResultData delete(@RequestBody List<ContentEntity> contents,HttpServletResponse response, HttpServletRequest request) {
int[] ids = new int[contents.size()];
for(int i = 0;i<contents.size();i++){
ids[i] =Integer.parseInt(contents.get(i).getId()) ;
}
contentBiz.delete(ids);
return ResultData.build().success();
}
...
1.3. 模型Bean
创建业务中需要的ES文档模型 public class *Bean extends ESBaseBean
,业务Bean继承ESBaseBean
注解参考
es文档定义,indexName可以定义不同的es库,注意:高版本es容器已经废弃了type的设置
@Document(indexName = "cms",type = "content")
es关键id注解
@Id
es关键字定义,例如:我是中国人,只能通过我是中国人搜索到,
@Field(type = FieldType.Keyword)
es关键字定义,分词搜索,例如:我是中国人,可以通过我是、中国人、中国、都能搜索到,
@Field(type = FieldType.Keyword, analyzer = "ik_max_word")
es长文本关键字定义,推荐加上analyzer = "ik_max_word"
@Field(type = FieldType.Text, analyzer = "ik_max_word")
es数值定义
@Field(type = FieldType.Integer )
es日期定义
@Field(type = FieldType.Date)
1.3.1. 范例
以文章为例,创建es文档模型bean,只需要定义需要存入es库的字段
@Document(indexName = "es-cms")
@Component("ESContentBean")
public class ESContentBean extends ESBaseBean {
/**
* 存储文章作者
*/
@Field(type = FieldType.Keyword)
private String author;
/**
* 存储自定义扩张模型
*/
@Field(type = FieldType.Object)
private Map<Object, Object> MDiyModel;
@Field(type = FieldType.Keyword)
private String typeId;
@Field(type = FieldType.Text)
private String litPic;
@Field(type = FieldType.Keyword)
private String flag;
/**
* 存储文章发布到
*/
@Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer="ik_smart")
private String styles;
/**
* 存储类型
*/
private String type;
/**
* 存储栏目父ID集合
*/
@Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer="ik_smart")
private String parentIds;
/**
* 站点ID
*/
@Field(type = FieldType.Keyword)
private String appId;
/**
* 文章副标题
*/
@Field(type = FieldType.Text)
private String shortTitle;
/**
* 栏目副标题
*/
@Field(type = FieldType.Text)
private String typeShortTitle;
/**
* 存储栏目标题
*/
@Field(type = FieldType.Text)
private String typeTitle;
/**
* 自定义排序
*/
@Field(type = FieldType.Integer)
private Integer sort;
@Field(type = FieldType.Text)
private String descrip;
/**
* 文章审批进度
*/
@Field(type = FieldType.Keyword)
private String progressStatus;
@Field(type = FieldType.Date,format = DateFormat.custom, pattern="yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
private Date date;
/**
* 链接地址
*/
@Field(type = FieldType.Text,index=false)
private String url;
// .. 省略 set get 方法
}
1.4. 同步方法
通过业务代码查询出所有的数据再通过 `Service` 提供的方法同步到es库
...
@Autowired
private IContentBiz contentBiz;
@Autowired
private IModelBiz modelBiz;
@Autowired
private ICategoryBiz categoryBiz;
@Autowired
private IESContentService esContentService;
/**
* 同步es文章
* @return
*/
@ApiOperation(value = "同步es文章接口")
@PostMapping("/sync")
@RequiresPermissions("es:sync")
@ResponseBody
public ResultData sync() {
// 获取栏目列表
LambdaQueryWrapper<CategoryEntity> categoryWrapper = new LambdaQueryWrapper<>();
categoryWrapper.ne(CategoryEntity::getCategoryType, CategoryTypeEnum.LINK.toString());
List<CategoryEntity> categoryList = categoryBiz.list(categoryWrapper);
for (CategoryEntity category : categoryList) {
// 获取文章列表
LambdaQueryWrapper<ContentEntity> contentWrapper = new LambdaQueryWrapper<>();
contentWrapper.eq(ContentEntity::getCategoryId, category.getId());
List<ContentEntity> contentList = contentBiz.list(contentWrapper);
boolean hasModel = false;
ModelEntity model = null;
if (StringUtils.isNotBlank(category.getMdiyModelId())) {
hasModel = true;
// 获取模型实体
model = modelBiz.getById(category.getMdiyModelId());
}
List<ESContentBean> beanList = new ArrayList<>();
for (ContentEntity content : contentList) {
ESContentBean esContentBean = new ESContentBean();
ESContentBeanUtil.fixESContentBean(esContentBean, content, category);
if (hasModel) {
//配置link_id Map
Map<String, String> modelMap = new HashMap<>(1);
modelMap.put("link_id", content.getId());
List<Map<String, Object>> modelFieldList = contentBiz.queryBySQL(
model.getModelTableName(),
null ,
modelMap, null, null, null, null, null);
// 防止NP
if (CollUtil.isNotEmpty(modelFieldList)) {
// 模型字段MAP
Map<String, Object> objectMap = modelFieldList.get(0);
for (String key : objectMap.keySet()) {
// 类型为BigInteger时需要转换为long防止es类型构造器转换错误
if (objectMap.get(key) instanceof BigInteger) {
objectMap.put(key, ((BigInteger) objectMap.get(key)).longValue());
}
}
esContentBean.setMDiyModel(objectMap);
}
}
beanList.add(esContentBean);
}
if (CollUtil.isNotEmpty(beanList)) {
try {
esContentService.saveAll(beanList);
}catch (DataAccessResourceFailureException e) {
return ResultData.build().error("未找到当前ES信息,请检查当前ES链接是否正常");
}catch (NoSuchIndexException e) {
return ResultData.build().error("未找到当前ES索引信息,请检查是否创建索引");
}
}
}
return ResultData.build().success().msg("全部同步完成!");
}
...
1.5. Service继承ElasticsearchRepository
继承后能进行简单的增删改查操作,具体可以参考CrudRepository
@Service("IESContentService")
@ConditionalOnClass({ Client.class, ElasticsearchRepository.class })
public interface IESContentService extends ElasticsearchRepository<ESContentBean, String> {
}
[!tip] 基于spring boot data 快速实现ES的CURD
1.6. AOP拦截
创建AOP public class *Aop extends ESBaseAop {}
,需要进行es全文检索的数据,通过aop的方式同步到es库,业务Aop继承ESBaseAop
1.6.1. 实例
通过拦截的方式将模型Bean的内容同步到es库
@Component("esContentAop")
@Aspect
public class ESContentAop extends ESBaseAop {
@Autowired
private IESContentService esContentService;
@Autowired
private ICategoryBiz categoryBiz;
//保存更新同步
@Override
public void save(JoinPoint joinPoint) {
try {
BaseEntity obj = this.getType(joinPoint, BaseEntity.class, true);
ESContentBean bean = new ESContentBean();
if(obj instanceof ContentEntity){
ContentEntity content = (ContentEntity)obj;
CategoryEntity category = categoryBiz.getById(content.getCategoryId());
bean.setTitle(content.getContentTitle());
bean.setContent(content.getContentDetails());
bean.setAuthor(content.getContentAuthor());
bean.setDate(content.getContentDatetime());
bean.setTypeId(content.getCategoryId());
bean.setDescrip(content.getContentDescription());
bean.setSort(content.getContentSort());
bean.setLitPic(content.getContentImg());
bean.setFlag(content.getContentType());
bean.setUrl(category.getCategoryPath();
// 有appId则存放
AppEntity app = BasicUtil.getWebsiteApp();
if (app != null) {
// 查询时会自动拼接appID,也就是当前session,所以这里可以直接设置
bean.setAppId(app.getId());
bean.setStyles(content.getContentStyle());
}
}
LOG.info("保存es库");
esContentService.save(bean);
} catch (Exception e) {
e.printStackTrace();
}
}
//删除同步
@Override
public void delete(JoinPoint joinPoint, ResultData result) {
try {
//注意!!!默认接收切入方法第一个参数
List<BaseEntity> arrayList = this.getType(joinPoint, ArrayList.class, true);
BaseEntity obj ;
obj = this.getType(joinPoint, BaseEntity.class, true);
if (arrayList != null) {
obj = arrayList.get(0);
}
// 单个删除
if(ObjectUtil.isNotEmpty(obj)){
esContentService.deleteById(obj.getId());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
[!tip] 所有涉及到文字内容变化的控制层都需要别拦截到,否则会出现es库数据不同步的问题产生
1.7. 搜索Action
创建 *Action
,根据业务编写对应的控制层,调用ESUtils的方法进行搜索
/**
* 高亮搜索,保留搜索字段keyword、order、orderBy、pageNo、pageSize,其余字段根据实际业务调整
*
* @param keyword 关键字
* @return 内容
*/
@ApiOperation(value = "高亮搜索接口")
@ApiImplicitParams({
@ApiImplicitParam(name = "keyword", value = "搜索关键字", required = true, paramType = "query"),
@ApiImplicitParam(name = "order", value = "排序方式", required = false, paramType = "query"),
@ApiImplicitParam(name = "orderBy", value = "排序的字段", required = false, paramType = "query"),
@ApiImplicitParam(name = "pageNo", value = "页数", required = false, paramType = "query", dataType = "Integer"),
@ApiImplicitParam(name = "pageSize", value = "页数大小", required = false, paramType = "query", dataType = "Integer"),
@ApiImplicitParam(name = "styles", value = "皮肤,例:outsite、insite", required = false, paramType = "query"),
@ApiImplicitParam(name = "typeId", value = "所属栏目(用于搜索指定栏目)", required = false, paramType = "query"),
@ApiImplicitParam(name = "parentIds", value = "父栏目ID(用于搜索所有子栏目)", required = false, paramType = "query"),
@ApiImplicitParam(name = "fields", value = "搜索关键字字段,值输入ES索引字段值,多个用逗号隔开 例:content,title", required = false, paramType = "query"),
@ApiImplicitParam(name = "searchMethod", value = "搜索方式,不传默认分词搜索(传值参考SearchMethodEnum)", required = false, paramType = "query"),
@ApiImplicitParam(name = "rangeField", value = "范围字段,需要传开始范围和结束范围才能生效,可以对时间进行范围筛选,值填写对应es索引的索引字段", required = false, paramType = "query"),
@ApiImplicitParam(name = "start", value = "开始范围 时间格式:yyyy-MM-dd HH:mm:ss 例:2021-08-06 12:25:36", required = false, paramType = "query"),
@ApiImplicitParam(name = "end", value = "结束范围 时间格式:yyyy-MM-dd HH:mm:ss 例:2021-08-06 12:25:36", required = false, paramType = "query"),
@ApiImplicitParam(name = "noflag", value = "不等于的文章类型,多个逗号隔开", required = false, paramType = "query"),
})
@PostMapping("/highlightSearch")
@ResponseBody
public ResultData highlightSearch(String keyword) {
ESSearchBean esSearchBean = new ESSearchBean();
String noflag = BasicUtil.getString("noflag");
Map<String, Object> notEquals = new HashMap<>();
if (StringUtils.isNotBlank(noflag)) {
List<String> collect = Arrays.stream(noflag.split(",")).collect(Collectors.toList());
// es flag字段
notEquals.put("flag", collect);
}
// 过滤条件
String filterStr = BasicUtil.getString("filter");
Map<Object,Object> filter = new HashMap<>();
if (StringUtils.isNotBlank(filterStr)) {
try {
filter = JSONUtil.toBean(filterStr, Map.class);
} catch (Exception e) {
LOG.debug("过滤条件转json失败");
e.printStackTrace();
}
}
//如果有站群插件,需要根据站群插件过滤
if (BasicUtil.getWebsiteApp() != null) {
// 站点过滤
LambdaQueryWrapper<AppEntity> wrapper = new QueryWrapper<AppEntity>().lambda();
wrapper.like(AppEntity::getAppUrl, BasicUtil.getDomain());
AppEntity appEntity = appBiz.getOne(wrapper, false);
filter.put("net", appEntity.getId());
}
// 设置基本过滤字段
String styles = BasicUtil.getString("styles");
if (StringUtils.isNotBlank(styles)) {
filter.put("styles", styles);
}
//审核过滤
filter.put("progressStatus", "终审通过");
esSearchBean.setFilterWhere(filter);
esSearchBean.setKeyword(keyword);
// 设置排序
String order = BasicUtil.getString("order", "desc");
String orderBy = BasicUtil.getString("orderBy", "sort");
esSearchBean.setOrder(order);
esSearchBean.setOrderBy(orderBy);
//设置分页
Integer pageNo = BasicUtil.getInt("pageNo", 1);
Integer pageSize = BasicUtil.getInt("pageSize", 10);
esSearchBean.setPageNo(pageNo);
esSearchBean.setPageSize(pageSize);
//设置高亮搜索配置
Map<String, Object> highlightConfig = new HashMap<>();
//设置高亮样式
highlightConfig.put("preTags", "<span style='color:red'>");
highlightConfig.put("postTags", "</span>");
//设置搜索字段
String author = BasicUtil.getString("author");
String content = BasicUtil.getString("content");
String title = BasicUtil.getString("title");
LinkedHashMap<String, Float> searchFields = new LinkedHashMap<>();
//设置搜索字段,数值f标识用于权重排序,一般多字段搜索使用,数值越大该字段的权重越大,当searchMethod等于geo_function_search生效
if (StringUtils.isNotBlank(author)) {
searchFields.put("author", 5f);
}
if (StringUtils.isNotBlank(title)) {
searchFields.put("title", 10f);
}
if (StringUtils.isNotBlank(content)) {
searchFields.put("content", 5f);
}
// 默认设置搜索标题
if (CollUtil.isEmpty(searchFields)) {
searchFields.put("title", 10f);
}
// 设置搜索方式,默认使用分词搜索
String searchMethod = BasicUtil.getString("searchMethod", "");
return esService.search(ESContentBean.class, searchFields, highlightConfig,
notEquals, esSearchBean, searchMethod);
}
[!tip] 注意代码中的
filter.put
与searchFields.put
根据实际业务字段调整,searchMethod
=should_search
可以匹配完整标题注意:fields参数里可以填写es库中已有的字段,如果传参为 title,content 表示搜索标题、文章中带有关键字的数据;styles参数为outsite或者insite
返回格式参考
{
"result": true,
"code": 200,
"data": {
"total": 1,
"rows": [ //记录列表
{
"contentKeyword": "<span style='color:red'>国</span><span style='color:red'>内</span>ms",
"sort": 0,
"id": "1346299650146922497",
"title": "[【网站】<span style='color:red'>国</span><span style='color:red'>内</span> 前6名 Java开源CMS建站系统]",
"content": "[下面我们开始分享一下开源中<span style='color:red'>国</span>中最火的Java开源CMS建站系统]",
"typeId": "1392359380113481730",
"parentIds": "1382233650262241282",
"date": "2017-08-29 20:04:31",
"author" : "",
"net" : "1",
"typeId" : "1458331507951800321",
"litPic" : """[{"url":"blob:http://192.168.0.118:8080/5e548893-1b5f-46cd-8193-fc7c48b2cc7f","name":"1637824298771.jpg","path":"/upload/1/cms/content/1637906304084.jpg","uid":1637906304036,"status":"success"}]""",
"typeTitle" : "早间新闻",
"flag" : "c",
"type" : "content",
"descrip": "-",
"url" : """/xinwen/zaojianxinwen\c1458332611057946626.html"""
}
]
}
}
1.8. 联想搜索\热词搜索
/es/suggestSearch.do 根据输入的关键字显示相关的关键词
/es/hotSearch.do 搜索指定时间访问的热词搜索及搜索量
[!tip] 根据搜索的结果,通过前端技术处理方式进行跳转
1.9. 搜索页面
可以通过swagger接口快速调试,前端页面通过异步请求处理。
代码参考:
1.9.1. 页面跳转(通用组件)
这里的代码只是用于封装参数,做页面跳转,不是es搜索
<!--注意script中id与下面定义component要一致-->
<script type="text/x-template" id="ms-search">
<el-form :model="esSearchForm" ref="esSearchForm" label-width="120px" size="mini">
<el-row>
<el-col :span='6'>
<el-form-item label="文章标题" prop="esSearchForm.contentTitle">
<el-input v-model="esSearchForm.contentTitle" clearable placeholder="请输入文章标题(支持模糊查询)"></el-input>
</el-form-item>
</el-col>
<el-col :span='6'>
<!--下拉选择框-->
<el-form-item label="栏目" prop="esSearchForm.categoryId">
<el-select v-model="esSearchForm.categoryId"
:style="{width: '100%'}"
:filterable="false"
:disabled="false"
:multiple="false" :clearable="true"
placeholder="请选择栏目">
<el-option v-for='item in categoryList' :key="item.categoryTitle" :value="item.id"
:label="item.categoryTitle"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span='12'>
<el-form-item label="评价时间" prop="esSearchForm.contentTime">
<el-date-picker
class="ms-datetimerange"
size="mini"
v-model="esSearchForm.contentTimes"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
align="right"
format="yyyy-MM-dd HH:mm:ss"
value-format="yyyy-MM-dd HH:mm:ss"
>
</el-date-picker>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col style="text-align: right;padding: 8px 0">
<el-button type="primary" icon="el-icon-search" size="mini" @click="search()">查询</el-button>
</el-col>
</el-row>
</el-form>
</script>
<script>
Vue.component('ms-search',{
template: "#ms-search",
name: "ms-search",
props:{},
data: function (){
return {
esSearchForm:{
contentTitle: null,
contentTimes:null,
categoryId:null,
},
categoryList: [],// 栏目集合
}
},
methods: {
queryCategory:function () {
var that = this;
ms.http.post(ms.base+"/cms/category/list.do",{
leaf: true,
pageSize: 20,
}).then(function (res) {
if (res.result){
that.categoryList = res.data.rows
}
})
},
search:function () {
var form = document.createElement("form");
form.setAttribute("method", "post");
var input = document.createElement('input');
input.setAttribute('type', 'hidden');
input.setAttribute('name', 'content_title');
input.setAttribute('value', this.esSearchForm.contentTitle);
form.append(input);
if (this.esSearchForm.categoryId){
input = document.createElement('input');
input.setAttribute('type', 'hidden');
input.setAttribute('name', 'categoryIds');
input.setAttribute('value', this.esSearchForm.categoryId);
form.append(input);
}
input = document.createElement('input');
input.setAttribute('type', 'hidden');
input.setAttribute('name', 'style');
input.setAttribute('value', '{ms:global.template/}');
form.append(input);
if (this.esSearchForm.contentTimes){
input = document.createElement('input');
input.setAttribute('type', 'hidden');
input.setAttribute('name', 'startTime');
input.setAttribute('value', this.esSearchForm.contentTimes[0]);
form.append(input);
input = document.createElement('input');
input.setAttribute('type', 'hidden');
input.setAttribute('name', 'endTime');
input.setAttribute('value', this.esSearchForm.contentTimes[1]);
form.append(input);
}
form.setAttribute("action","/mcms/search.do");
document.body.appendChild(form);
form.submit();
form.remove();
},
},
created() {
var that = this;
/*不需要es搜索将下面代码注释即可*/
<!--es的热词-->
ms.http.post(ms.base+"/es/hotSearch.do", {
field: 'title'
}).then(function(res){
if(res.data && res.data.length>0){
that.hotSearch = res.data;
}
}).catch(function (err) {
console.log(err)
})
that.queryCategory();
}
})
</script>
1.9.2. 在head中引入
注意需要include标签引入才能使用ms-search标签渲染
<!--这里根据文件位置 相对路径引用-->
<#include "ms-search.htm" />
...
<ms-search></ms-search>
...
1.9.3. 搜索模板代码 search.htm
在这个模板中处理es搜索逻辑,包括数据渲染
...
<div class="w-search-keyword-warp">
<span class="w-search-label"> 搜索关键词:</span>
<span class="w-search-keyword"> {ms:search.content_title/}</span>
</div>
...
... 搜索列表展示 ...
<!--分页 注意page-size必须和script中的分页数pageSize对应-->
<div class="search-limit-div">
<el-pagination background
@current-change="handleCurrentChange"
page-size="5"
pager-count="3"
:current-page.sync="pageCur"
layout="prev, pager, next,jumper,total"
:total="contentCount">
</el-pagination>
</div>
<script>
var app = new Vue({
el: '#app',
component(){
},
data: {
searchForm: {
docName:'文章',// 索引名称
fields: 'title,content',// 匹配哪些字段,逗号分隔
keyword: "{ms:search.content_title/}",// 匹配关键字
// 范围查询 不传参数 默认给空串 导致查不到
<#if search.categoryIds?has_content>
filter: {// 过滤条件
typeId: '{ms:search.categoryIds/}',// typeId只支持单个栏目id
},
</#if>
<#if search.startTime?has_content && search.endTime?has_content>
rangeFields: [ // 范围查询条件,支持多个范围条件
{
type: 'date',
field: 'date',
start: '{ms:search.startTime/}',// 必须是yyyy-MM-dd HH:mm:ss的格式
end: '{ms:search.endTime/}',// 必须是yyyy-MM-dd HH:mm:ss的格式
},
],
</#if>
orderBy: 'date',// 按文章时间排序
order: 'desc',// 倒序
pageSize: 5,// 一页显示数
pageNo: 1// 页码(页面初始化默认第一页)
},
hotSearchKeywords: [],// 热词
pageCur: ${(page.cur)!1},// 当前页数
pageSize: ${(page.size)!20},// 每页文章条数
pageTotal: ${(page.total)!0},// 页数总数
contentCount: ${(page.rcount)!0},// 内容总数
contentList: [],// 搜索数据
},
watch: {
},
methods: {
handleCurrentChange:function(val) {
var that = this;
// create函数中已经JSON化filter和rangeFiled为字符串,此处无需再转
if (val) {
that.searchForm.pageNo = val;
}
<!--es通用搜索-->
ms.http.post(ms.base+"/es/search.do",that.searchForm).then(function (res){
that.contentCount = res.data.total;
var content;
// 由于在es环境下无法用标签获取文章相关值,在这里预先对文章图片做处理
for (var i = 0;i<res.data.rows.length;i++){
content = res.data.rows[i];
if(content.litPic){
content.litPic = JSON.parse(content.litPic);
if(content.litPic.length > 0 ){
res.data.rows[i].litPic = content.litPic[0].url;
}
}
}
that.contentList = res.data.rows
}).catch(function (err){
console.log(err)
})
},
switchShow:function(arr){
var that = this
arr.forEach(function(x){
let e = that.$el.querySelector("#key_"+x)
if(e){
e.style.display=getComputedStyle(e,null).display=='none'?'flex':'none'
}
})
},
show:function(arr){
var that = this
arr.forEach(function(x){
let e = that.$el.querySelector("#key_"+x)
if(e){
e.style.display='flex'
}
})
},
hide:function(arr){
var that = this
arr.forEach(function(x){
let e = that.$el.querySelector("#key_"+x)
if(e){
e.style.display='none'
}
})
}
},
created(){
var that = this;
that.searchForm.rangeFields = JSON.stringify(that.searchForm.rangeFields);
that.searchForm.filter = JSON.stringify(that.searchForm.filter);
<!--es通用搜索,支持高亮搜索,不使用es的情况下将下面代码全部注释即可-->
//ms.http.post(ms.base+"/cms/es/search/highlightSearch.do",{
ms.http.post(ms.base+"/es/search.do",that.searchForm).then(function(res){
that.contentCount = res.data.total;
var content;
// 由于在es环境下无法用标签获取文章相关值,在这里预先对文章图片做处理
for (var i = 0;i<res.data.rows.length;i++){
content = res.data.rows[i];
if(content.litPic){
content.litPic = JSON.parse(content.litPic);
if(content.litPic.length > 0 ){
res.data.rows[i].litPic = content.litPic[0].url;
}
}
}
that.contentList = res.data.rows
}).catch(function (err){
console.log(err)
})
}
})
</script>
[!tip]
可以根据本页面代码来实现其他数据的全文搜索