okHttpApi也可以进行远程调用
RestTemplate:是Spring提供的用于访问Rest服务的客户端
服务者与消费者的角色是相对的。一个服务可以同时是服务提供者和服务消费者。
第一种:是全局配置,orderservice这个消费者访问任何服务的时候均会按照配置的这个随机选择策略。
第二种:是局部配置,先指定服务名再配置用户希望的负载均衡策略。
Nacos是阿里巴巴的产品,现在是SpringCloud中的一个组件 。相比Eureka功能更为丰富,在国内受欢迎程度较高。
下载地址:https://github.com/alibaba/nacos/releases/tag/1.4.1
启动方式:
D:\nacos\bin>startup.cmd -m standalone
SpringCloud-common定义了统一的接口规范,所以只需要修改依赖即可。
首先:还得在父工程pom文件中,引入:
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-alibaba-dependenciesartifactId>
<version>2.2.5.RELEASEversion>
<type>pomtype>
<scope>importscope>
dependency>
Nacos服务注册发现客户端依赖:
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
注意:一种服务有多个集群时,先通过启动一个项目的多个实例,再分别通过修改yml文件配置并指定要启动的一个服务启动!
配置负载均衡规则:消费者优先选择本地集群的服务者。
作用:也可以用于服务器升级,将需要升级的服务器访问权重调小。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ziru2uvn-1688347828537)(C:\Users\25817\AppData
方式一:
方式二:
开发、测试、生产环境相同的配置共享。
修改环境:
Nacos的单例模式不推荐用在生产环境,所以需要对nacos服务做高可用,所以需要通过nacos集群来解决这个问题。
@EnableFeignClients 注解在启动类上;
@FeignClient 注解在client的配置接口;
默认过滤器配置,会对所有进入网关的请求路由进行配置
在gateway服务的yml进行配置
类似Ubuntu和CentOS都是基于Linux内核,只是系统应用不同,提供的函数库有差异。
Hypervisor可以模拟出计算机的硬件,cpu,内存等。
镜像只能读,不能写。避免污染镜像。
解决方案:原因是华为服务器内核的问题,云服务器切换操作系统即可:
解决方案:
systemctl restart docker
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
@RunWith(SpringRunner.class) //是一个JUnit注解,它是用来指定运行测试用例的运行器
@SpringBootTest //加载SpringBoot应用程序的上下文
public class SpringAmqpTest {
@Resource
private RabbitTemplate rabbitTemplate;
@Test
public void testSendMessage2SimpleQueue(){
String queueName="simple.queue";
String message="Hello,SpringAmqp3!";
rabbitTemplate.convertAndSend(queueName,message);
}
}
见docker安装文件
docker logs -f mn #查看docker中的mn容器的日志,不间断的方式
shell命令是bash命令的一部分
# 修改nginx容器中的静态文件
sed -i 's#Welcome to nginx#Nginx欢迎您!--by TSW#g' index.html
sed -i 's###g' index.html
exit #退出容器
docker ps #显示运行中的容器的状态
docker ps -a #显示所有容器的状态
docker rm mn #删除非运行态的容器
docker rm -f mn #强制删除运行的容器
docker stop 容器id # 停止指定容器的运行
docker exec -it mr bash #进入redis(name-mr)容器内部
redis -cli #连接redis客户端
docker ps -a #该命令将显示所有容器的列表,包括正在运行和已停止的容器,并显示相应的状态信息
docker volume rm 数据卷名
远程mysql连接不上的问题,容器在创建的时候,密码输入格式不正确:
docker run \
--name mysql \
-e MYSQL_ROOT_PASSWORD=123 \
-p 3306:3306 \
-v /tmp/mysql/conf/hmy.cnf:/etc/mysql/conf.d/hmy.cnf \
-v /etc/mysql/data:/var/lib/mysql \
-d mysql:5.7.25
具体用法:见文档
RabbitMQ的部署与安装:详见MyCoding笔记文件夹中的RabbitMQ部署指南!
见安装文档
其他的和简单消息队列一致,差别不大
MessageConverter在publisher中的启动类上声明!!!
发送消息,把对象序列化成字节!
详见MyCoding笔记文件夹中的ES安装指南!
详见MyCoding笔记文件夹中的ES安装指南!
其他的扩展词典,停用词等操作见参考资料
注意:mapping的id只能为字符串类型,不能为integer,long。
注意:步骤三里面的第二步需要强制指定ES的版本
上面两种查询功能和结果一样。
# function score 查询
GET /hotel/_search
{
"query": {
"function_score": {
"query": {
"match": {
"all": "外滩"
}
},
"functions": [
{
"filter": {
"term": {
"brand": "如家"
}
},
"weight": 10
}
],
"boost_mode": "sum"
}
}
}
term查询是精确查询。不是模糊查询(match)
DSL语句:
DSL语句:
注意:如果对结果进行排序处理,则不会再进行相关性得分的计算
DSL语句:
Ctrl+Alt+M抽取代码,可提取出来当作一个方法
private void handleResponse(SearchResponse response) {
// 4.解析响应
SearchHits searchHits = response.getHits();
// 4.1查询的总条数
long value = searchHits.getTotalHits().value;
System.out.println("总条数: "+value);
// 4.2查询的结果数组
SearchHit[] hits = searchHits.getHits();
for (SearchHit hit : hits) {
// 4.3得到source
String json = hit.getSourceAsString();
// 反序列化为对象
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
System.out.println(hotelDoc);
}
}
java代码
/**
* 复合查询:bool子查询
* @throws IOException
*/
@Test
void testBoolMatch() throws IOException {
// 1.准备request
SearchRequest request = new SearchRequest("hotel");
// 2.准备DSL
// 2.1准备BooleanQuery
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
// 2.2添加term
boolQueryBuilder.must(QueryBuilders.termQuery("city","上海"));
// 2.3添加range
boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").lte(250));
request.source().query(boolQueryBuilder);
// 3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// System.out.println(response);
handleResponse(response);
}
注意链式编程!
注意:高亮,必须针对带关键字的查询,不能用matchAll查询
/**
* 高亮
* @throws IOException
*/
@Test
void testHighlight() throws IOException {
// 1.准备request
SearchRequest request = new SearchRequest("hotel");
// 全部查询
request.source().query(QueryBuilders.matchQuery("all","如家"));
// 高亮
request.source().highlighter(new HighlightBuilder().field("name").requireFieldMatch(false));
// 3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// System.out.println(response);
// 4.解析响应
SearchHits searchHits = response.getHits();
// 4.1查询的总条数
long value = searchHits.getTotalHits().value;
System.out.println("总条数: "+value);
// 4.2查询的结果数组
SearchHit[] hits = searchHits.getHits();
for (SearchHit hit : hits) {
// 4.3得到source
String json = hit.getSourceAsString();
// 反序列化为对象
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
// 获取高亮结果
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
// 根据字段名获取高亮结果
HighlightField highlightField = highlightFields.get("name");
if(highlightField!=null){
String name = highlightField.getFragments()[0].string();
hotelDoc.setName(name);
}
System.out.println(hotelDoc);
}
}
注意:SpringBoot项目启动会自动访问resource文件夹下的static下的index.html,
快捷键:Ctrl+Alt+T执行surround with
主要代码java:
@MapperScan("cn.itcast.hotel.mapper")
@SpringBootApplication
public class HotelDemoApplication {
public static void main(String[] args) {
SpringApplication.run(HotelDemoApplication.class, args);
}
/**
* 将RestHighLevelClient注册到bean
* @return
*/
@Bean
public RestHighLevelClient client(){
return new RestHighLevelClient(RestClient.builder(HttpHost.create(
"http://123.60.61.97:9200")
));
}
}
@RestController
@RequestMapping("/hotel")
public class HotelController {
@Resource
private IHotelService hotelService;
@PostMapping("/list")
public PageResult search(@RequestBody RequestParams requestParams){
return hotelService.search(requestParams);
}
}
package cn.itcast.hotel.service.impl;
import cn.itcast.hotel.mapper.HotelMapper;
import cn.itcast.hotel.pojo.Hotel;
import cn.itcast.hotel.pojo.HotelDoc;
import cn.itcast.hotel.pojo.PageResult;
import cn.itcast.hotel.pojo.RequestParams;
import cn.itcast.hotel.service.IHotelService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Service
public class HotelService extends ServiceImpl<HotelMapper, Hotel> implements IHotelService {
@Resource
private RestHighLevelClient client;
@Override
public PageResult search(RequestParams requestParams) {
SearchResponse response = null;
try {
// 1.准备request
SearchRequest request = new SearchRequest("hotel");
// 2.准备DSL
// 2.1关键字全文搜索
// 若搜索为空,则执行全文查询
String key = requestParams.getKey();
if (key == null || key.equals("")) {
request.source().query(QueryBuilders.matchAllQuery());
} else {
request.source().query(QueryBuilders.matchQuery("all", key));
}
// 2.2分页
request.source().from((requestParams.getPage() - 1) * requestParams.getSize()).size(requestParams.getSize());
// 3.发送请求
response = client.search(request, RequestOptions.DEFAULT);
// 4.解析响应,返回结果
return handleResponse(response);
} catch (IOException e) {
throw new RuntimeException(e);
}
// System.out.println(response);
}
private PageResult handleResponse(SearchResponse response) {
// 4.解析响应
SearchHits searchHits = response.getHits();
// 4.1查询的总条数
long value = searchHits.getTotalHits().value;
System.out.println("总条数: " + value);
// 4.2查询的结果数组
SearchHit[] hits = searchHits.getHits();
List<HotelDoc> hotelDocs = new ArrayList<>();
for (SearchHit hit : hits) {
// 4.3得到source
String json = hit.getSourceAsString();
// 反序列化为对象
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
hotelDocs.add(hotelDoc);
// System.out.println(hotelDoc);
}
// 4.4封装返回
return new PageResult(value,hotelDocs);
}
}
java代码:
此处:Ctrl+Alt+M抽取了代码块作buildBasicQuery方法
public PageResult search(RequestParams requestParams) {
SearchResponse response = null;
try {
// 1.准备request
SearchRequest request = new SearchRequest("hotel");
// 2.准备DSL
// 2.1关键字全文搜索
// 构建BooleanQuery
buildBasicQuery(requestParams, request);
// 2.2分页
request.source().from((requestParams.getPage() - 1) * requestParams.getSize()).size(requestParams.getSize());
// 3.发送请求
response = client.search(request, RequestOptions.DEFAULT);
// 4.解析响应,返回结果
return handleResponse(response);
} catch (IOException e) {
throw new RuntimeException(e);
}
// System.out.println(response);
}
private void buildBasicQuery(RequestParams requestParams, SearchRequest request) {
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
String key = requestParams.getKey();
// 关键字搜索
// 若搜索为空,则执行全文查询
if (key == null || key.equals("")) {
boolQueryBuilder.must(QueryBuilders.matchAllQuery());
} else {
boolQueryBuilder.must(QueryBuilders.matchQuery("all", key));
}
// 条件过滤:城市条件
if(requestParams.getCity()!=null&&!requestParams.getCity().equals("")){
// filter不参与算分
boolQueryBuilder.filter(QueryBuilders.termQuery("city", requestParams.getCity()));
}
// 条件过滤:品牌条件
if(requestParams.getBrand()!=null&&!requestParams.getBrand().equals("")){
// filter不参与算分
boolQueryBuilder.filter(QueryBuilders.termQuery("brand", requestParams.getBrand()));
}
// 条件过滤:星级条件
if(requestParams.getStarName()!=null&&!requestParams.getStarName().equals("")){
// filter不参与算分
boolQueryBuilder.filter(QueryBuilders.termQuery("starName", requestParams.getStarName()));
}
// 条件过滤:价格条件
if(requestParams.getMinPrice()!=null&& requestParams.getMaxPrice()!=null){
// filter不参与算分
boolQueryBuilder.filter(QueryBuilders.rangeQuery("price")
.gte(requestParams.getMinPrice())
.lte(requestParams.getMaxPrice()));
}
request.source().query(boolQueryBuilder);
}
java代码:
2.3 添加排序
String location = requestParams.getLocation();
if(location!=null&&!location.equals("")){
request.source().sort(SortBuilders
.geoDistanceSort("location",new GeoPoint(location))
.order(SortOrder.ASC)
.unit(DistanceUnit.KILOMETERS));
}
// 解析附近酒店距离值 这块代码在封装的解析响应那块
Object[] sortValues = hit.getSortValues();
if(sortValues.length>0){
Object sortValue = sortValues[0];
hotelDoc.setDistance(sortValue);
}
filter:必须满足条件的文档才参与算分
java代码:
// 2.算分控制
FunctionScoreQueryBuilder functionScoreQuery = QueryBuilders.functionScoreQuery(
// 原始查询
boolQueryBuilder
// function score的数组
, new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
// 其中的一个 function score元素
new FunctionScoreQueryBuilder.FilterFunctionBuilder(
// 过滤条件
QueryBuilders.termQuery("isAD", true),
// 算分函数
//
ScoreFunctionBuilders.weightFactorFunction(10)
)
});
request.source().query(functionScoreQuery);
DSL语句:
返回结果:
DSL语句:
返回结果:
java代码:
请求响应+结果解析,请求三要素:类型,名称,字段
@Test
void Aggregation() throws IOException {
// 1.准备request
SearchRequest request = new SearchRequest("hotel");
// 2.准备dsl
// 2.1设置size
request.source().size(0);
// 2.2聚合
request.source().aggregation(AggregationBuilders
.terms("brandAgg")
.field("brand")
.size(10)
);
// 3.发出请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 4.解析结果
Aggregations aggregations = response.getAggregations();
//4.根据聚合名称获取聚合结果
Terms brandTerms = aggregations.get("brandAgg");
//4.2获取buckets
List<? extends Terms.Bucket> buckets = brandTerms.getBuckets();
//4.3遍历
for (Terms.Bucket bucket : buckets) {
//4.4获取key
System.out.println(bucket.getKey());
}
//System.out.println(response);
}
java代码:
surround with快捷键:Ctrl+Alt+T
/**
*多条件聚合:品牌,城市,星级
* @return
*/
@Override
public Map<String, List<String>> filters() {
try {
// 1.准备request
SearchRequest request = new SearchRequest("hotel");
// 2.准备dsl
// 2.1设置size
request.source().size(0);
// 2.2聚合
buildAggregation(request);
// 3.发出请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 4.解析结果
// 4.1根据聚合名称获取结果
Map<String, List<String>> result = new HashMap<>();
Aggregations aggregations = response.getAggregations();
List<String> brandList = getAggByName(aggregations,"brandAgg");
List<String> cityList = getAggByName(aggregations,"cityAgg");
List<String> starList = getAggByName(aggregations,"starAgg");
//4.4放入map
result.put("品牌",brandList);
result.put("城市",cityList);
result.put("星级",starList);
return result;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private List<String> getAggByName(Aggregations aggregations,String aggName) {
//4.1根据聚合名称获取聚合结果
Terms brandTerms = aggregations.get(aggName);
//4.2获取buckets
List<? extends Terms.Bucket> buckets = brandTerms.getBuckets();
//4.3遍历
List<String> brandList = new ArrayList<>();
for (Terms.Bucket bucket : buckets) {
//4.4获取key
//System.out.println(bucket.getKey());
brandList.add(bucket.getKeyAsString());
}
return brandList;
}
private void buildAggregation(SearchRequest request) {
request.source().aggregation(AggregationBuilders
.terms("brandAgg")
.field("brand")
.size(100)
);
request.source().aggregation(AggregationBuilders
.terms("cityAgg")
.field("city")
.size(100)
);
request.source().aggregation(AggregationBuilders
.terms("starAgg")
.field("starName")
.size(100)
);
}
java代码:
@PostMapping("/filters")
public Map<String, List<String>> getFilters(@RequestBody RequestParams requestParams){
return hotelService.filters(requestParams);
}
案例截图:
es的plugin目录地址:/var/lib/docker/volumes/es-plugins/_data
注意:pinyin分词器得在创建索引库的时候,在setting下面配置好
若用户搜索关键词是中文文字,则不应该使用拼音分词器
DSL代码:
# 自动补全的索引库
PUT test2
{
"mappings": {
"properties": {
"title":{
"type": "completion"
}
}
}
}
# 示例数据
POST test2/_doc
{
"title": ["Sony", "WH-1000XM3"]
}
POST test2/_doc
{
"title": ["SK-II", "PITERA"]
}
POST test2/_doc
{
"title": ["Nintendo", "switch"]
}
# 自动补全查询,字段是completion类型
GET /test2/_search
{
"suggest": {
"titleSuggest": {
"text": "so",
"completion": {
"field": "title",
"skip_duplicates": true,
"size": 10
}
}
}
}