org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
eureka:
client:
service-url: # eureka的地址信息
defaultZone: http://127.0.0.1:10086/eureka
@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
server:
port: 10086 # 服务端口
spring:
application:
name: eurekaserver # eureka的服务名称
eureka:
client:
service-url: # eureka的地址信息
defaultZone: http://127.0.0.1:10086/eureka
order_uservice中
1.在application.yml中
eureka:
client:
service-url: # eureka的地址信息
defaultZone: http://127.0.0.1:10086/eureka
2…在启动类
/**
* 创建RestTemplate并注入Spring容器
*/
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
3.在orderService中url可以用别的服务名称替换
@Autowired
private RestTemplate restTemplate;
public Order queryOrderById(Long orderId) {
// 1.查询订单
Order order = orderMapper.findById(orderId);
// 2.利用RestTemplate发起http请求,查询用户
// 2.1.url路径
String url = "http://userService/user/" + order.getUserId();
// 2.2.发送http请求,实现远程调用
User user = restTemplate.getForObject(url, User.class);
// 3.封装user到Order
order.setUser(user);
// 4.返回
return order;
}
默认为ZoneAvoidanceRule
在order-service中配置user-service负载均衡规则
userservice:
ribbon:
NFLoadBalancerRuleClassName:com.netflix.loadbalancer.RandomRule # 负载均衡规则
com.alibaba.cloud
spring-cloud-alibaba-dependencies
2.2.5.RELEASE
pom
import
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
cloud:
nacos:
server-addr: http://47.120.0.38:8848
discovery:
cluster-name: BJ
userService:
ribbon:
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 负载均衡规则
ribbon:
eager-load:
enabled: true # 开启饥饿加载
clients: # 指定饥饿加载的服务名称
- userservice
application:
name: orderService
cloud:
nacos:
server-addr: http://47.120.0.38:8848
discovery:
cluster-name: BJ
application:
name: userService
cloud:
nacos:
server-addr: http://47.120.0.38:8848
discovery:
cluster-name: SH
会采用我,因为我也是BJ
application:
name: userService
cloud:
nacos:
server-addr: http://47.120.0.38:8848
discovery:
cluster-name: BJ
userService:
ribbon:
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 负载均衡规则
ribbon:
eager-load:
enabled: true # 开启饥饿加载
clients: # 指定饥饿加载的服务名称
- userservice
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-config
名字为userservice.yaml这个文件一定会被读取
那个dev只能在开发环境被读取到
org.springframework.cloud
spring-cloud-starter-openfeign
在启动类orderServer上添加如下注解
@EnableFeignClients
新建包及其接口文件
按照springmvc的方式书写远程调用方法
io.github.openfeign
feign-httpclient
feign:
client:
config:
userService:
loggerLevel: basic
httpclient:
enabled: true #支持httpClient开关
max-connections: 200 #最大连接数
max-connections-per-route: 50 #单个路径的最大连接数
方式二
抽取一个模块
在orderService中,加入相关依赖。
cn.itcast.demo
feign-api
1.0
在orderService启动类中,加入相关注解参数
@EnableFeignClients(clients = UserClient.class,defaultConfiguration = DefaultFeignConfiguration.class)
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
org.springframework.cloud
spring-cloud-starter-gateway
server:
port: 10010
spring:
application:
name: gateway
cloud:
nacos:
server-addr: http://47.120.0.38:8848 #nacos地址
gateway:
routes:
- id: userService #路由标识,必须唯一
uri: lb://userService #路由目标地址
predicates: #路由断言,判断请求是否符合规则
- Path=/user/** #路由断言,判断路径是否以/user/开头,如果符合规则 P要大写
- id: order-service
uri: lb://orderservice
predicates:
- Path=/order/**
server:
port: 10010
spring:
application:
name: gateway
cloud:
nacos:
server-addr: http://47.120.0.38:8848 #nacos地址
gateway:
routes:
- id: userService #路由标识,必须唯一
uri: lb://userService #路由目标地址
predicates: #路由断言,判断请求是否符合规则
- Path=/user/** #路由断言,判断路径是否以/user/开头,如果符合规则 P要大写
# filters:
# - AddRequestHeader=Truth, blue
- id: order-service
uri: lb://orderservice
predicates:
- Path=/order/**
filters:
- AddRequestHeader=Truth, blue
default-filters:
- AddRequestHeader=Truth,Itcast is freaking awesome!
@Order(-1) //值越小,优先级越高
@Component
public class AuthorizeFilter implements GlobalFilter {
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1.获取请求参数
// exchange.getRequest().getQueryParams().getFirst("authorization")
ServerHttpRequest request = exchange.getRequest();
MultiValueMap params = request.getQueryParams();
// 2.获取参数中的 authorization 参数
String auth = params.getFirst("authorization");
// 3.判断参数值是否等于 admin
if ("admin".equals(auth)) {
// 4.是,放行
return chain.filter(exchange);
}
// 5.否,拦截
// 5.1.设置状态码
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
// 5.2.拦截请求
return exchange.getResponse().setComplete();
}
server:
port: 10010
spring:
application:
name: gateway
cloud:
nacos:
server-addr: http://47.120.0.38:8848 #nacos地址
gateway:
routes:
- id: userService #路由标识,必须唯一
uri: lb://userService #路由目标地址
predicates: #路由断言,判断请求是否符合规则
- Path=/user/** #路由断言,判断路径是否以/user/开头,如果符合规则 P要大写
# filters:
# - AddRequestHeader=Truth, blue
- id: order-service
uri: lb://orderservice
predicates:
- Path=/order/**
filters:
- AddRequestHeader=Truth, blue
globalcors:
add-to-simple-url-handler-mapping: true
cors-configurations:
'[/**]':
allowedOrigins: #允许哪些网站
- "http://localhost:8090"
- "http://localhost:8090"
allowedMethods:
- "GET"
- "POST"
- "DELETE"
allowedHeaders: "*" #允许携带请求头信息
allowedCredentials: true #是否允许携带cookie
maxAge: 360000 #这次跨域的有效期1,预检请求的允许时间
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
安装yum工具
yum install -y yum-utils device-mapper-persistent-data 1vm2 --skip-broken
设置docker镜像源加速器
去阿里云服务器上看镜像加速器
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://omgw7ydy.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
安装docker-ce
因为ce版为免费版本
yum install -y docker-ce
查看防火墙状态
systemctl status firewalld
关闭防火墙
systemcctl stop firewalld
开启防火墙
systemctl start firewalld
启动docker
systemctl start docker
重启
systemctl restart docker
可以通过 docker --help查看docker命令帮助
1.首先去dockerHub中搜索镜像
docker save -o 文件名 镜像名
删除本地镜像需要添加版本信息
docker rmi nginx:latest
如果有在运行的容器要删除再删除镜像
加载本地镜像文件
docker load -i 本地文件名
在dockerHUb官网中可以查看docker镜像的具体使用方法
docker容器的参数的具体解析
1.创建容器,并运行容器
成功之后返回容器id
然后就可以访问nginx了,云服务器记得开安全组
2.进入容器
因为容器内部没有vim指令,如果想要修改容器内文件的内容,需要使用相关操作,不建议修改,如果必须修改,去下面数据卷处找答案。
删除容器指令区别于删除镜像指令,没有i
docker run --name myRedis -p 6379:6379 -d redis redis-server --save 60 1 --loglevel warning
进入容器
docker exec -it myRedis bash
退出容器
exit
这个映射,相当于热更新操作,只要容器挂载到数据卷上,就能够实现资源共享
查看操作数据卷命令
docker volume --help
创建数据卷
docker volume create html
显示数据卷
docker volume inspect html
列出数据卷
docker volume ls
docker run --name myNginx -v html:/usr/share/nginx/html -d nginx
docker run --name mysql \
-e MYSQL_ROOT_PASSWORD=0071hanxiaolei \
-p 3306:3306 \
-v /temp/mysql/conf/hmy.cnf:/etc/mysql/conf.d/hmy.cnf \
-v /tmp/mysql/data:/var/lib/mysql \
-d mysql:5.7.42
现在java:8已经不存在了,使用openjdk:8作为基础镜像
在终端中导航到包含Dockerfile的项目目录,并运行以下命令来构建Docker镜像:
docker build -t javaweb .
docker run --name web -p 8999:8999 -d javaweb:latest
https://github.com/docker/compose/releases
配置域名解析
echo "192.232.68.133 raw.githubusercontent.com" >>/etc/hosts
下载docker-compose
curl -L https://github.com/docker/compose/releases/download/2.20.1/docker-compose-`uname -s` \
-`uname -m` -o /usr/local/bin/docker-compose
查看下载路径
whereis docker-compose
chmod +x docker-compose
2.其他userService与orderService都与网关相同
我们的私服采用的是http协议,默认不被Docker信任,所以需要做一个配置:
# 打开要修改的文件
vi /etc/docker/daemon.json
# 添加内容:
"insecure-registries":["http://47.120.0.38:8080"]
# 重加载
systemctl daemon-reload
# 重启docker
systemctl restart docker
查看docker-compose是否安装成功
docker-compose -v
然后在tmp目录下创建registry-ui文件
mkdir registry-ui
然后在registry-ui中新建文件docker-compose.yml
touch docker-compose.yml
docker-compose.yml里面添加内容为
version: '3.0'
services:
registry:
image: registry
volumes:
- ./registry-data:/var/lib/registry
ui:
image: joxit/docker-registry-ui:static
ports:
- 8080:80
environment:
- REGISTRY_TITLE=某某某的私有仓库
- REGISTRY_URL=http://registry:5000
depends_on:
- registry
docker tag nginx:latest 47.120.0.38:8080/nginx:1.0
推送镜像
docker push 47.120.0.38:8080/nginx:1.0
拉取镜像
docker pull 47.120.0.38/nginx:1.0
docker run -d --hostname my-rabbit --name rabbit \
-p 5672:5672 -p 15672:15672 -e \
RABBITMQ_DEFAULT_USER=root \
-e RABBITMQ_DEFAULT_PASS=0071hanxiaolei \
rabbitmq:3-management
若访问不了控制台
进入rabbitmq容器内部,然后执行
rabbitmq-plugins enable rabbitmq_management
cd /etc/rabbitmq/conf.d/
echo management_agent.disable_metrics_collector = false > management_agent.disable_metrics_collector.conf
public class PublisherTest {
@Test
public void testSendMessage() throws IOException, TimeoutException {
// 1.建立连接
ConnectionFactory factory = new ConnectionFactory();
// 1.1.设置连接参数,分别是:主机名、端口号、vhost、用户名、密码
factory.setHost("47.120.0.38");
factory.setPort(5672);
factory.setVirtualHost("/");
factory.setUsername("root");
factory.setPassword("0071hanxiaolei");
// 1.2.建立连接
Connection connection = factory.newConnection();
// 2.创建通道Channel
Channel channel = connection.createChannel();
// 3.创建队列
String queueName = "simple.queue";
channel.queueDeclare(queueName, false, false, false, null);
// 4.发送消息
String message = "hello, rabbitmq!";
channel.basicPublish("", queueName, null, message.getBytes());
System.out.println("发送消息成功:【" + message + "】");
// 5.关闭通道和连接
channel.close();
connection.close();
}
}
public class ConsumerTest {
public static void main(String[] args) throws IOException, TimeoutException {
// 1.建立连接
ConnectionFactory factory = new ConnectionFactory();
// 1.1.设置连接参数,分别是:主机名、端口号、vhost、用户名、密码
factory.setHost("47.120.0.38");
factory.setPort(5672);
factory.setVirtualHost("/");
factory.setUsername("root");
factory.setPassword("0071hanxiaolei");
// 1.2.建立连接
Connection connection = factory.newConnection();
// 2.创建通道Channel
Channel channel = connection.createChannel();
// 3.创建队列
String queueName = "simple.queue";
channel.queueDeclare(queueName, false, false, false, null);
// 4.订阅消息
channel.basicConsume(queueName, true, new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope,
AMQP.BasicProperties properties, byte[] body) throws IOException {
// 5.处理消息
String message = new String(body);
System.out.println("接收到消息:【" + message + "】");
}
});
System.out.println("等待接收消息。。。。");
}
}
org.springframework.boot
spring-boot-starter-amqp
spring:
rabbitmq:
host: 47.120.0.38
port: 5672
username: root
password: 0071hanxiaolei
virtual-host: /
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringAmqpTest {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void testSendMessageSimpleQueue(){
String queueName="simple.queue";
String message="hello word";
rabbitTemplate.convertAndSend(queueName,message);
}
}
spring:
rabbitmq:
host: 47.120.0.38
port: 5672
username: root
password: 0071hanxiaolei
virtual-host: /
@Component
public class SpringAmqpListener {
@RabbitListener(queues = "simple.queue")
public void listenerSimpleQueue(String arg){
System.out.println("消费者接受到simple.queue的消息:"+arg);
}
}
多个消费者,会进行消息队列的预取,但是预取完之后做不完,会产生消息的堆积
spring:
rabbitmq:
host: 47.120.0.38
port: 5672
username: root
password: 0071hanxiaolei
virtual-host: /
listener:
direct:
prefetch: 1
@Configuration
public class FanoutConfig {
//声明一个交换机
@Bean
public FanoutExchange fanoutExchange(){
return new FanoutExchange("itcast.fanout");
}
//声明一个队列
@Bean
public Queue fanoutQueue1(){
return new Queue("fanout.queue1");
}
//声明一个队列
@Bean
public Queue fanoutQueue2(){
return new Queue("fanout.queue2");
}
//绑定队列1到交换机
@Bean
public Binding fanoutBinding1(Queue fanoutQueue1,FanoutExchange fanoutExchange){
return BindingBuilder.bind(fanoutQueue1).to(fanoutExchange);
}
//绑定队列2到交换机
@Bean
public Binding fanoutBinding2(Queue fanoutQueue2,FanoutExchange fanoutExchange){
return BindingBuilder.bind(fanoutQueue2).to(fanoutExchange);
}
}
@RabbitListener(queues = "fanout.queue1")
public void listenerFanoutQueue1(String arg) throws InterruptedException {
System.err.println("消费者1.....接受到fanout.queue1的消息:"+arg+"*******"+ LocalTime.now());
}
@RabbitListener(queues = "fanout.queue2")
public void listenerFanoutQueue2(String arg) throws InterruptedException {
System.err.println("消费者2.....接受到fanout.queue2的消息:"+arg+"*******"+ LocalTime.now());
}
public void testSendFanoutExchange(){
//交换机名称
String exchangeName="itcast.fanout";
//消息
String message="hello one";
//发送消息
rabbitTemplate.convertAndSend(exchangeName,"",message);
}
/**
* direct
* @param arg
*/
@RabbitListener(bindings = @QueueBinding(
value = @Queue(name = "direct.queue1"),
exchange = @Exchange(name = "itcast.direct",type = ExchangeTypes.DIRECT),
key = {"red","blue"}
))
public void listenerDirectQueue(String arg){
System.out.println("消费者red与blue.....接受到direct.queue1的消息:"+arg);
}
@RabbitListener(bindings = @QueueBinding(
value = @Queue(name = "direct.queue2"),
exchange = @Exchange(name = "itcast.direct",type = ExchangeTypes.DIRECT),
key = {"red","yellow"}
))
public void listenerDirectQueue2(String arg){
System.out.println("消费者red与yellow.....接受到direct.queue2的消息:"+arg);
}
@Test
public void testSendDirectExchange(){
//交换机名称
String exchangeName="itcast.direct";
//消息
String message="hello yellow";
//发送消息
rabbitTemplate.convertAndSend(exchangeName,"yellow",message);
}
/**
* topic
*/
@RabbitListener(bindings = @QueueBinding(
value = @Queue(name = "topic.queue1"),
exchange = @Exchange(name = "itcast.topic",type = ExchangeTypes.TOPIC),
key = "china.#"
))
public void listenerTopicQueue(String arg){
System.out.println("china的所有消息"+arg);
}
@RabbitListener(bindings = @QueueBinding(
value = @Queue(name = "topic.queue1"),
exchange = @Exchange(name = "itcast.topic",type = ExchangeTypes.TOPIC),
key = "china.sjz"
))
public void listenerTopic2Queue(String arg){
System.out.println("china.sjz的消息"+arg);
}
@Test
public void testSendTopicExchange(){
//交换机名称
String exchangeName="itcast.topic";
//消息
String message="我在石家庄学习springCloud";
//发送消息
rabbitTemplate.convertAndSend(exchangeName,"china.sjz",message);
}
@Test
public void testSendTopic2Exchange(){
//交换机名称
String exchangeName="itcast.topic";
//消息
String message="我在中国学习springCloud";
//发送消息
rabbitTemplate.convertAndSend(exchangeName,"china",message);
}
com.fasterxml.jackson.core
jackson-databind
@Bean
public MessageConverter messageConverter(){
return new Jackson2JsonMessageConverter();
}
@Test
public void testSendObjectQueue(){
Map stringObjectHashMap = new HashMap<>();
stringObjectHashMap.put("柳岩","柳岩");
stringObjectHashMap.put("age",18);
rabbitTemplate.convertAndSend("object.queue",stringObjectHashMap);
}
@Bean
public Queue objectQueue(){
return new Queue("object.queue");
}
@RabbitListener(queues = "object.queue")
public void listenerObjectQueue(Map msg){
System.out.println(msg);
}
部署单点es
因为我们还需要部署kibana,因此我们需要让es和kibana容器互联。这里先创建一个网路
docker network create es-net
加载镜像
docker load -i es.tar
docker pull elasticsearch
启动elasticsearch
docker run -d \
--name es \
-e "ES_JAVA_OPTS=-Xms512m -Xmx512m" \
-e "discovery.type=single-node" \
-v es-data:/usr/share/elasticsearch/data \
-v es-plugins:/usr/share/elasticsearch/plugins \
--privileged \
--network es-net \
-p 9200:9200 \
-p 9300:9300 \
elasticsearch:latest
docker run -d --name kibana \
-e ELASTICSEARCH_URL=http://es:9200 \
--network=es-net -p 5601:5601 kibana:latest
处理这种中文分词器我们使用IK分词器
离线安装ik分词器
安装插件需要知道elasticsearch的plugins目录位置,而我们使用了数据卷挂载,因此需要查看elasticsearch的数据卷目录,通过以下命令查看
docker volume inspect es-plugins
docker restart es
ik_smart
:最少切分
ik_max_word
:最细切分
GET /_analyze
{
"analyzer": "ik_max_word",
"text": "黑马程序员学习java太棒了"
}
显示结果
{
"tokens" : [
{
"token" : "黑马",
"start_offset" : 0,
"end_offset" : 2,
"type" : "CN_WORD",
"position" : 0
},
{
"token" : "程序员",
"start_offset" : 2,
"end_offset" : 5,
"type" : "CN_WORD",
"position" : 1
},
{
"token" : "程序",
"start_offset" : 2,
"end_offset" : 4,
"type" : "CN_WORD",
"position" : 2
},
{
"token" : "员",
"start_offset" : 4,
"end_offset" : 5,
"type" : "CN_CHAR",
"position" : 3
},
{
"token" : "学习",
"start_offset" : 5,
"end_offset" : 7,
"type" : "CN_WORD",
"position" : 4
},
{
"token" : "java",
"start_offset" : 7,
"end_offset" : 11,
"type" : "ENGLISH",
"position" : 5
},
{
"token" : "太棒了",
"start_offset" : 11,
"end_offset" : 14,
"type" : "CN_WORD",
"position" : 6
},
{
"token" : "太棒",
"start_offset" : 11,
"end_offset" : 13,
"type" : "CN_WORD",
"position" : 7
},
{
"token" : "了",
"start_offset" : 13,
"end_offset" : 14,
"type" : "CN_CHAR",
"position" : 8
}
]
}
GET /_analyze
{
"analyzer": "ik_smart",
"text": "学习java太棒了"
}
{
"tokens": [
{
"token": "学习",
"start_offset": 0,
"end_offset": 2,
"type": "CN_WORD",
"position": 0
},
{
"token": "java",
"start_offset": 2,
"end_offset": 6,
"type": "ENGLISH",
"position": 1
},
{
"token": "太棒了",
"start_offset": 6,
"end_offset": 9,
"type": "CN_WORD",
"position": 2
},
{
"token": "eeee",
"start_offset": 9,
"end_offset": 13,
"type": "ENGLISH",
"position": 3
}
]
}
/var/lib/docker/volumes/es-plugins/_data/ik/config/IKAnalyzer.cfg.xml
其中ext.dic是添加扩展词,同级目录下没有该文件,新建一个
其中stopword.dic是忽略的词,同级目录下存在,往里面加相应的词语即可
IK Analyzer 扩展配置
ext.dic
stopword.dic
每个版本的创建方式不同,添加方式也不同,这里版本是5.6.8
PUT heima3
{
"mappings": {
"person": {
"properties": {
"info": {
"type": "text",
"analyzer": "ik_smart"
},
"email": {
"type": "keyword",
"index": false
},
"name": {
"type": "object",
"properties": {
"firstName": {
"type": "keyword"
},
"lastName": {
"type": "keyword"
}
}
}
}
}
}
}
PUT /heima/person/_mapping
{
"properties": {
"age1": {
"type": "long"
}
}
}
POST /hiema/person/1
{
"info":"黑马此程序黑马此程序黑马",
"email":"9100",
"name":{
"lastNAme":"wg",
"firstName":"bbb"
}
}