赞
踩
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.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.5.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
Nacos服务注册发现客户端依赖:
<!-- nacos客户端依赖包 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</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安装文件
这里去掉image
docker logs -f mn #查看docker中的mn容器的日志,不间断的方式
shell命令是bash命令的一部分
# 修改nginx容器中的静态文件
sed -i 's#Welcome to nginx#Nginx欢迎您!--by TSW#g' index.html
sed -i 's#<head>#<head><meta charset="utf-8">#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 } } } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。