一直在烂尾,对,说的就是你,楼.
上一章简单介绍了 SpringBoot 整合 ES (六), 如果没有看过,请观看上一章
这一章节老蝴蝶做一个简单的 ES 查询项目
一. pom.xml 添加依赖
<!--引入MySql的驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--引入springboot与mybatis-plus整合的依赖。 去掉mybatis的依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
<!--添加 druid-spring-boot-starter的依赖的依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.14</version>
</dependency>
<!--SpringBoot 的aop 模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!--引入 spring-boot-starter-thymeleaf的依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--添加一个webjar jquery-->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.5.1</version>
</dependency>
<!--引入bootstrap-->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>3.4.1</version>
</dependency>
<!--引入 spring-data-elasticsearch-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
二. application.yml 配置文件
server:
port: 8081
servlet:
context-path: /ES
# 引入 数据库的相关配置
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.100.252:3306/springboot?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=UTF-8&useSSL=false&allowMultiQueries=true
username: root
password: 123456
type: com.alibaba.druid.pool.DruidDataSource
# 配置thymeleaf的相关信息
thymeleaf:
# 开启视图解析
enabled: true
#编码格式
encoding: UTF-8
#前缀配置
prefix: classpath:/templates/
# 后缀配置
suffix: .html
#是否使用缓存 开发环境时不设置缓存
cache: false
# 格式为 HTML 格式
mode: HTML5
# 配置类型
servlet:
content-type: text/html
#整合mybatis时使用的
mybatis-plus:
# 配置 mapper文件的位置
mapper-locations: classpath:mybatis/mapper/**/*.xml
# 配置日志
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: true # 配置别名设置
global-config:
db-config:
logic-delete-field: flag # 逻辑删除的字段
logic-not-delete-value: 1 # 正常状态下,该字段的值
logic-delete-value: 0 # 删除后,该字段的值
table-underline: true # 驼峰方式转换
#分页插件
pagehelper:
helperDialect: mysql
reasonable: true
supportMethodsArguments: true
params: count=countSql
elasticsearch:
host: 127.0.0.1
port: 9200
对应Sql 是:
# 临时指定字符集 防中文乱码
/*!40101 SET NAMES utf8 */;
CREATE TABLE `product`
(
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id编号',
`title` varchar(255) DEFAULT NULL COMMENT '书名',
`author` varchar(255) DEFAULT NULL COMMENT '作者',
`category` varchar(255) DEFAULT NULL COMMENT '类别',
`price` decimal(10, 2) DEFAULT NULL COMMENT '价格',
`image` varchar(255) DEFAULT NULL COMMENT '图片地址',
PRIMARY KEY (`id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8 COMMENT ='图书产品';
三. 配置处理
三. 一 ES 配置
@Component
@ConfigurationProperties("elasticsearch")
@Data
public class EsConfig extends AbstractElasticsearchConfiguration {
private String host;
private Integer port;
@Override
public RestHighLevelClient elasticsearchClient() {
RestClientBuilder restClientBuilder = RestClient.builder(new HttpHost(host, port));
return new RestHighLevelClient(restClientBuilder);
}
}
三.二 web 配置
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
/**
* 配置静态的资源信息
*
* @param registry
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
//映射 static 目录
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
//放置其他 业务页面资源
registry.addResourceHandler("/**").addResourceLocations("classpath:/templates/");
}
}
四. 实体配置
四.一 数据库实体 ProductDO
@Data
@TableName("product")
public class ProductDO {
/**
* id编号
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 书名
*/
@TableField
private String title;
/**
* 作者
*/
@TableField
private String author;
/**
* 类别
*/
@TableField
private String category;
/**
* 价格
*/
@TableField
private BigDecimal price;
/**
* 图片地址
*/
@TableField
private String image;
}
四.二 ES 实体
@Data
@Document(indexName = "product")
public class Product {
@Id
private Integer id;
@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String title;
@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String author;
@Field(type = FieldType.Keyword)
private String category;
@Field(type = FieldType.Double)
private Double price;
@Field(type = FieldType.Keyword, index = false)
private String image;
}
五. Mapper 和 Repository
五.一 数据库 Mapper
@Mapper
public interface ProductDOMapper extends BaseMapper<ProductDO> {
}
五.二 ES的 Repository
@Repository
public interface ProductRepository extends ElasticsearchRepository<Product, Integer> {
}
六. Service 处理
public interface ProductDOService extends IService<ProductDO> {
}
@Service
public class ProductDOServiceImpl extends ServiceImpl<ProductDOMapper, ProductDO> implements ProductDOService {
}
七. 请求接收对象
七.一 添加时对象
@Data
public class ProductRequestVO implements Serializable {
/**
* 书名
*/
@Field
private String title;
/**
* 作者
*/
@Field
private String author;
/**
* 类别
*/
@Field
private String category;
/**
* 价格
*/
@Field
private BigDecimal price;
}
七.二 查询时对象
@Data
public class ProductSearchRequestVO implements Serializable {
private String keyword;
}
七.三 响应对象
@Data
public class ProductSearchResponseVO implements Serializable {
private Integer id;
private String title;
private String author;
private String category;
private BigDecimal price;
private String image;
private String showTitle;
}
八. Business
八.一 接口
public interface IProductApplication {
Map<String, Object> add(ProductRequestVO productRequestVO);
Map<String, Object> esSearch(ProductSearchRequestVO productSearchRequestVO);
Map<String, Object> dbSearch(ProductSearchRequestVO productSearchRequestVO);
}
八.二 实现类
八.二.一 依赖注入
@Service
@Slf4j
public class ProductApplicationImpl implements IProductApplication {
@Resource
private ProductDOService productDOService;
@Resource
private ProductRepository productRepository;
@Resource
private ElasticsearchRestTemplate elasticsearchRestTemplate;
}
八.二.二 添加
@Override
public Map<String, Object> add(ProductRequestVO productRequestVO) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ProductDO productDO = new ProductDO();
BeanUtils.copyProperties(productRequestVO, productDO);
productDO.setImage("默认地址");
productDOService.save(productDO);
// 进行保存到 es里面
Product product = new Product();
BeanUtils.copyProperties(productDO, product);
product.setPrice(productDO.getPrice().doubleValue());
productRepository.save(product);
log.info(">>> 保存成功");
stopWatch.stop();
//获取查询时间
long totalTimeMillis = stopWatch.getTotalTimeMillis();
Map<String, Object> result = new HashMap<>(2, 1.0f);
result.put("totalTimeMillis", totalTimeMillis);
return result;
}
八.二.三 ES查询
@Override
public Map<String, Object> esSearch(ProductSearchRequestVO productSearchRequestVO) {
// 进行查询,包括高亮显示。
StopWatch stopWatch = new StopWatch();
stopWatch.start();
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.preTags("<font color='red'>");
highlightBuilder.postTags("</font>");
highlightBuilder.field("title");
FuzzyQueryBuilder fuzzyQueryBuilder = QueryBuilders.fuzzyQuery("title", Optional.ofNullable(productSearchRequestVO.getKeyword()).orElse(""));
fuzzyQueryBuilder.fuzziness(Fuzziness.ONE);
NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(fuzzyQueryBuilder, null, null, highlightBuilder, null);
SearchHits<Product> search = elasticsearchRestTemplate.search(nativeSearchQuery, Product.class);
//{title=[Java <font color='red'>入门</font>到放弃4]}
List<ProductSearchResponseVO> result = new ArrayList<>();
// 获取查询的结果
search.getSearchHits().forEach(
n -> {
Product content = n.getContent();
ProductSearchResponseVO single = new ProductSearchResponseVO();
BeanUtils.copyProperties(content, single);
single.setPrice(BigDecimal.valueOf(content.getPrice()));
List<String> hightFields = n.getHighlightField("title");
if (!CollectionUtils.isEmpty(hightFields)) {
single.setShowTitle(hightFields.get(0));
}
result.add(single);
}
);
stopWatch.stop();
long totalTimeMillis = stopWatch.getTotalTimeMillis();
Map<String, Object> resultMap = new HashMap<>(2, 1.0f);
resultMap.put("totalTimeMillis", totalTimeMillis);
resultMap.put("data", result);
return resultMap;
}
八.二.四 数据库查询
@Override
public Map<String, Object> dbSearch(ProductSearchRequestVO productSearchRequestVO) {
// 进行查询,包括高亮显示。
StopWatch stopWatch = new StopWatch();
stopWatch.start();
List<ProductDO> list = productDOService.lambdaQuery()
.like(StringUtils.hasText(productSearchRequestVO.getKeyword()), ProductDO::getTitle, productSearchRequestVO.getKeyword())
.list();
List<ProductSearchResponseVO> result = list.stream().map(
n -> {
ProductSearchResponseVO single = new ProductSearchResponseVO();
BeanUtils.copyProperties(n, single);
single.setPrice(n.getPrice());
single.setShowTitle(n.getTitle());
return single;
}
).collect(Collectors.toList());
stopWatch.stop();
long totalTimeMillis = stopWatch.getTotalTimeMillis();
Map<String, Object> resultMap = new HashMap<>(2, 1.0f);
resultMap.put("totalTimeMillis", totalTimeMillis);
resultMap.put("data", result);
return resultMap;
}
九. Controller 处理
@RestController
@RequestMapping("/product")
public class ProductController {
@Resource
private IProductApplication iProductApplication;
@RequestMapping("/add")
public Map<String, Object> add(@RequestBody ProductRequestVO productRequestVO) {
return iProductApplication.add(productRequestVO);
}
@RequestMapping("/esSearch")
public Map<String, Object> esSearch(@RequestBody ProductSearchRequestVO productSearchRequestVO) {
return iProductApplication.esSearch(productSearchRequestVO);
}
@RequestMapping("/dbSearch")
public Map<String, Object> dbSearch(@RequestBody ProductSearchRequestVO productSearchRequestVO) {
return iProductApplication.dbSearch(productSearchRequestVO);
}
}
十. 前端页面处理
十.一 前端页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>图书管理</title>
<link rel="StyleSheet" href="webjars/bootstrap/3.4.1/css/bootstrap.css" type="text/css">
</head>
<body class="page-bg">
<div class="mar-hor">
<div style="margin-top: 20px;" class="col-sm-offset-2">
<h2>ElasticSearch 使用</h2>
</div>
<div id="custom-toolbar">
<form class="form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-2 control-label">书名:</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="title"></input>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">作者:</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="author"></input>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">类别:</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="category" value="IT" disabled></input>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">价格:</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="price" value="40.0" disabled></input>
</div>
</div>
<button id="add" type="button" class="btn btn-unified col-sm-offset-4">
增加图书
</button>
</form>
</div>
<div>
<h3 class="col-sm-offset-2">Title 书名查询</h3>
<form class="form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-2 control-label">书名关键字搜索:</label>
<div class="col-sm-4">
<input type="text" class="form-control" id="keyword"></input>
</div>
</div>
<br/>
<div class="col-sm-offset-4">
<button id="esSearch" type="button" class="btn btn-unified">
ES查询
</button>
<button id="dbSearch" type="button" class="btn btn-unified">
数据库查询
</button>
</div>
</form>
<div>
</div>
</div>
<div style="margin-top:40px;" class="col-sm-offset-2">
<label class="col-sm-2 control-label">花费时间:</label>
<div class="col-sm-4">
<input type="text" class="form-control" id="totalTimeMillis"></input>
</div>
<br/>
<br/>
<br/>
<div class="col-sm-offset-1" style="margin-top: 30px;">
<br/>
<br/>
<div id="result" class="form-control">
</div>
</div>
</div>
</div>
<script type="text/javascript" src="webjars/jquery/3.5.1/jquery.js"></script>
<script type="text/javascript" src="webjars/bootstrap/3.4.1/js/bootstrap.js"></script>
<script type="text/javascript" src="index.js"></script>
</body>
</html>
十.二 前端js
const CONTENT_PATH = "/ES/product/";
//新增员工
$("#add").click(function () {
var title = $("#title").val();
var author = $("#author").val();
var category = $("#category").val();
var price = $("#price").val();
$.ajax({
async: false,
type: "post",
url: CONTENT_PATH + "add",
data: JSON.stringify({
title: title,
author: author,
category: category,
price: price
}),
dataType: "json",
contentType: "application/json;charset=utf-8",
success: function (data) {
alert("新增商品成功!");
}
});
});
//es 查询
$("#esSearch").click(function () {
$("#result").empty();
$.ajax({
async: false,
type: "post",
url: CONTENT_PATH + "esSearch",
data: JSON.stringify({
keyword: $("#keyword").val()
}),
dataType: "json",
contentType: "application/json;charset=utf-8",
success: function (data) {
//获取信息
$("#totalTimeMillis").val(data.totalTimeMillis);
//获取信息.
let dataList = data.data;
for (let i = 0; i < dataList.length; i++) {
$("#result").append(
"<div>"
+ "书名:" + dataList[i].showTitle + " "
+ "作者名:" + dataList[i].author + " "
+ "类别:" + dataList[i].category + " "
+ "价格:" + dataList[i].price + "<br/>"
+ "</div>"
)
}
}
});
});
//es 查询
$("#dbSearch").click(function () {
$("#result").empty();
$.ajax({
async: false,
type: "post",
url: CONTENT_PATH + "dbSearch",
data: JSON.stringify({
keyword: $("#keyword").val()
}),
dataType: "json",
contentType: "application/json;charset=utf-8",
success: function (data) {
//获取信息
$("#totalTimeMillis").val(data.totalTimeMillis);
//获取信息.
let dataList = data.data;
for (let i = 0; i < dataList.length; i++) {
$("#result").append(
"<div>"
+ "书名:" + dataList[i].showTitle + " "
+ "作者名:" + dataList[i].author + " "
+ "类别:" + dataList[i].category + " "
+ "价格:" + dataList[i].price + "<br/>"
+ "</div>"
)
}
}
});
});
十一. 测试验证
输入网址: http://localhost:8081/ES/
通过一首 进行查询
ES 查询
数据库查询
一个简单的 ES 项目就算是完成了.
本章节的代码放置在 github 上:
https://github.com/yuejianli/springboot/tree/develop/SpringBoot_ES2
谢谢您的观看,如果喜欢,请关注我,再次感谢 !!!