效果:
一:将数据库数据同步到es
1.首先在数据库选择需要的资源条件,将sql语句执行出来
2.将sql语句放入es的sync_tanle.cfg配置文件执行
3.修改index名称
sync_tanle.cfg文件完成版
input {
jdbc {
# mysql相关jdbc配置
jdbc_connection_string => "jdbc:mysql://192.168.230.1:3306/ddd?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8"
jdbc_user => "root"
jdbc_password => "123123"
# jdbc连接mysql驱动的文件, 此处路径一定要正确 否则会报com.mysql.cj.jdbc.Driver could not be loaded
jdbc_driver_library => "/opt/logstash-7.7.0/config/sync/mysql-connector-java-8.0.13.jar"
jdbc_driver_class => "com.mysql.cj.jdbc.Driver"
jdbc_paging_enabled => true
jdbc_page_size => "50000"
jdbc_default_timezone =>"Asia/Shanghai"
# mysql文件, 也可以直接写SQL语句在此处,如下:
statement => "SELECT
p.id,
p.`name`,
p.brand_name,
p.product_category_name,
p.publish_status,
p.new_status,
p.sub_title,
ps.sku_code,
ps.price,
p.pic,
ps.sale,
ps.sp_data
FROM
pms_product p
LEFT JOIN pms_sku_stock ps
ON p.id = ps.product_id
GROUP BY p.`name`"
# 这里类似crontab,可以定制定时操作,比如每分钟执行一次同步(分 时 天 月 年)
schedule => "* * * * *"
# 是否需要记录某个column 的值,如果record_last_run为真,可以自定义我们需要 track 的 column 名称,此时该参数就要为 true. 否则默认 track 的是 timestamp 的值.
use_column_value => true
# 如果 use_column_value 为真,需配置此参数. track 的数据库 column 名,该 column 必须是递增的. 一般是mysql主键
tracking_column => "create_time"
tracking_column_type => "timestamp"
last_run_metadata_path => "area_logstash_capital_bill_last_id"
# 是否清除 last_run_metadata_path 的记录,如果为真那么每次都相当于从头开始查询所有的数据库记录
clean_run => false
#是否将 字段(column) 名称转小写
#lowercase_column_names => false
}
}
filter {
date {
match => [ "create_time", "yyyy-MM-dd HH:mm:ss" ]
timezone => "Asia/Shanghai"
}
}
output {
elasticsearch {
#虚拟机id
hosts => ["192.168.230.134:9200"]
# index名 自定义 相当于数据库 对于实体类上@Document(indexName = "jq_product")indexName
index => "jq_product"
#需要关联的数据库中有有一个id字段,对应索引的id号
document_id => "%{id}"
template_overwrite => true
}
stdout {
codec => json_lines
}
}
4.开始同步 在/opt/logstash-7.7.0/bin/目录里
[root@localhost bin]# ./logstash -f /opt/logstash-7.7.0/config/sync/sync_tanle.cfg
注意: 如果重新执行同步先查询进程,杀死之前的进程
[root@localhost bin]# ps -ef | grep logstash
[root@localhost bin]# kill -9 5388
5.效果:
二:创建springboot项目开始完成代码:
1.配置文件
application.yml
spring:
application:
#项目名称
name: jq-search
elasticsearch:
rest:
#连接es
uris: http://192.168.230.134:9200
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#端口号
server:
port: 5053
#连接服务中心
eureka:
client:
service-url:
defaultZone: http://localhost:5051/eureka
创建实体类
package com.jq.model;
import lombok.Data;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
@Data
@Document(indexName = "j_product")//连接es
public class SerchModel {
private Long id;
@Field(type = FieldType.Text,analyzer = "ik_max_word")
private String name;
@Field(type = FieldType.Text)
private String brand_name;
@Field(type = FieldType.Text)
private String product_category_name;
@Field(type = FieldType.Text)
private String publish_status;
@Field(type = FieldType.Text)
private String new_status;
@Field(type = FieldType.Text,analyzer = "ik_max_word")
private String sub_title;
@Field(type = FieldType.Text)
private String sku_code;
@Field(type = FieldType.Text)
private String price;
@Field(type = FieldType.Text)
private String pic;
@Field(type = FieldType.Text)
private String sale;
@Field(type = FieldType.Text)
private String sp_dat;
}
创建分页PageBean类
package com.jq.page;
import lombok.Data;
import java.util.List;
@Data
public class PageBean<T> {
private Integer page;
private Integer size;
private Long total;
private List<T> data;
}
创建ProductSearch类,相当于vo
package com.jq.search;
import com.jq.page.PageBean;
import lombok.Data;
@Data
public class ProductSearch extends PageBean {
private String key;
}
创建统一返回值类
package com.jq.result;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ResultObj {
// 状态码
private Integer code;
// 信息
private String msg;
// 数据
private Object data;
public ResultObj(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public static ResultObj success(){
return new ResultObj(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg());
}
public static ResultObj success(Object data){
return new ResultObj(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), data);
}
public static ResultObj error(ResultCode resultCode){
return new ResultObj(resultCode.getCode(), resultCode.getMsg(),null);
}
}
创建code码枚举类
package com.jq.result;
public enum ResultCode {
SUCCESS(200,"操作成功"),
ERROR(500,"操作失败"),
USERNAME_PASSWORD_ISNULL(1001,"用户名或密码为空"),
USER_NOEXIST(1002,"用户不存在"),
PASSWORD_ERROR(1003,"密码错误"),
TOKEN_ERROR(1004,"身份过期,请重新登录"),
NO_PERMISSION(403,"没有权限访问该方法"),
PHONE_NULL(1005,"手机号为空"),
GET_CODE_ERROR(1006,"获取验证码失败"),
PHONE_CODE_ISBULL(1007,"手机号码或验证码不能为空"),
CODE_ERROR(1008,"验证码错误"),
PHONE_CODE_TIMEOUT(1009,"手机号码不正确或验证码过期")
;
private Integer code;
private String msg;
ResultCode(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
开始实现代码:
controller控制器
package com.jq.controller;
import com.jq.result.ResultObj;
import com.jq.search.ProductSearch;
import com.jq.service.SearchProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@CrossOrigin//跨域
@RequestMapping("search")
public class SearchController {
@Autowired
private SearchProductService searchProductService;
@GetMapping
public ResultObj getSearchProduct(ProductSearch productSearch){
ProductSearch search= searchProductService.searchProduct(productSearch);
return ResultObj.success(search);
}
}
SearchProductServiceImpl 实现类代码:
package com.jq.service.impl;
import com.jq.model.SerchModel;
import com.jq.search.ProductSearch;
import com.jq.service.SearchProductService;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
@Service
public class SearchProductServiceImpl implements SearchProductService {
@Autowired
private ElasticsearchRestTemplate elasticsearchRestTemplate;
@Override
public ProductSearch searchProduct(ProductSearch productSearch) {
if(StringUtils.isBlank(productSearch.getKey())){
//用户不选择查询数据,设置查询的默认值
productSearch.setKey("手机");
}
//构建分页
Pageable pageable= PageRequest.of(productSearch.getPage(),productSearch.getSize());
NativeSearchQueryBuilder builder=new NativeSearchQueryBuilder();
NativeSearchQuery query=builder.withQuery(QueryBuilders.queryStringQuery(productSearch.getKey()))
.withPageable(pageable)
.build();
SearchHits<SerchModel> search = elasticsearchRestTemplate.search(query, SerchModel.class);
Stream<SearchHit<SerchModel>> searchHitStream = search.get();
List<SerchModel>list=new ArrayList<>();
searchHitStream.forEach(searchHit->{
list.add(searchHit.getContent());
});
productSearch.setData(list);
productSearch.setTotal(search.getTotalHits());
return productSearch;
}
}
三:前端代码:
<template>
<div>
<div class="house-header">
<div class="layui-container">
<div class="house-nav">
<span class="layui-breadcrumb" lay-separator="|">
<a href="login.html">登录</a>
<a href="">我的订单</a>
<a href="">在线客服</a>
</span>
<span class="layui-breadcrumb house-breadcrumb-icon" lay-separator=" ">
<a id="search"><i class="layui-icon layui-icon-house-find"></i></a>
<a href="login.html"><i class="layui-icon layui-icon-username"></i></a>
<a href="usershop.html"><i class="layui-icon layui-icon-house-shop"></i></a>
</span>
</div>
<div class="house-banner layui-form">
<a class="banner" href="index.html">
<img src="../../../static/static/img/banner.png" alt="家居商城">
</a>
<div class="layui-input-inline">
<input type="text" placeholder="搜索好物" class="layui-input"><i class="layui-icon layui-icon-house-find"></i>
</div>
<a class="shop" href="usershop.html"><i class="layui-icon layui-icon-house-shop"></i><span class="layui-badge">1</span></a>
</div>
<ul class="layui-nav close">
<li class="layui-nav-item layui-this"><a href="index.html">首页</a></li>
<li class="layui-nav-item"><a href="list.html">居家用品</a></li>
<li class="layui-nav-item"><a href="list.html">小家电</a></li>
<li class="layui-nav-item"><a href="list.html">洗护</a></li>
<li class="layui-nav-item"><a href="list.html">厨具</a></li>
<li class="layui-nav-item"><a href="list.html">日用品</a></li>
</ul>
<button id="switch">
<span></span><span class="second"></span><span class="third"></span>
</button>
</div>
</div>
<div class="layui-container house-list">
<p class="classify"><a href="index.html">首页</a> > <span>家居用品</span></p>
<div class="list-banner"></div>
<div class="filter">
<div><span>分类:</span><ul><li class="active">全部</li><li>床品</li><li>灯具</li><li>布艺</li><li>收纳</li><li>小家具</li></ul></div>
<div><span>季节:</span><ul><li class="active">全部</li><li>春</li><li>夏</li><li>秋</li><li>冬</li></ul></div>
<div><span>排序:</span><ul><li class="active">默认</li><li>价格<i class="layui-icon layui-icon-house-up"></i><i class="layui-icon layui-icon-triangle-d"></i></li><li>上架时间</li></ul></div>
</div>
<div class="layui-row layui-col-space25">
<div class="layui-col-xs6 layui-col-sm3" v-for="product in dataList">
<div class="list-detail" >
<div class="img"><img :src="product.pic"></div>
<p class="title"><a href="detail.html">{{product.sub_title}}</a></p>
<p><span class="price">¥{{product.price}}</span><span>1266</span>人付款</p>
</div>
</div>
</div>
<div style="text-align: center">
<el-pagination
background
layout="total, prev, pager, next,jumper"
:current-page="query.page+1"
:page-size="query.size"
:total="total"
@current-change="handleCurrentChange"
></el-pagination>
</div>
</div>
<div class="house-footer">
<div class="layui-container">
<div class="intro">
<span class="first"><i class="layui-icon layui-icon-house-shield"></i>7天无理由退换货</span>
<span class="second"><i class="layui-icon layui-icon-house-car"></i>满99元全场包邮</span>
<span class="third"><i class="layui-icon layui-icon-house-diamond"></i>100%品质保证</span>
<span class="last"><i class="layui-icon layui-icon-house-tel"></i>客服400-2888-966</span>
</div>
<div class="about">
<span class="layui-breadcrumb" lay-separator="|">
<a href="about.html">关于我们</a>
<a href="about.html">帮助中心</a>
<a href="about.html">售后服务</a>
<a href="about.html">配送服务</a>
<a href="about.html">关于货源</a>
</span>
<p>家居商城版权所有 © 2012-2020</p>
</div>
</div>
</div>
</div>
</template>
<script>
import {getSearchProduct} from "../../api/Product/product";
export default {
name: "ProductList",
data(){
return{
dataList:[],
total:null,
query:{
page:0,
size:10,
key:""
}
}
},
methods:{
//从es查询数据
getList(){
getSearchProduct(this.query).then(result =>{
this.dataList=result.data.data.data;
this.total=result.data.data.total;
})
},
// 分页导航
handleCurrentChange(val) {
this.$set(this.query, 'page', val-1);
this.getList();
},
},
created() {
//初始化
this.getList(),
layui.config({
base: '../../../../static/static/js/'
}).use('house');
},
}
</script>
<style scoped>
</style>
product.js发起请求
import request from '../../utils/request';
//从es取数据商品
export const getSearchProduct = query => {
return request({
url: 'http://localhost:5053/search/',
method: 'get',
params: query
});
};