Websocket点对点通信
- 在进行简单架构后我们开始进行代码编写
- 配置pom文件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.webjars/sockjs-client -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>sockjs-client</artifactId>
<version>1.1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.webjars/stomp-websocket -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>stomp-websocket</artifactId>
<version>2.3.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.webjars/jquery -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.5.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.webjars/webjars-locator-core -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>webjars-locator-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
- WebsocketConfig 注册断点
implements WebSocketMessageBrokerConfigurer
- WebsocketConfig 开启 socketjs 支持
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat").setAllowedOriginPatterns("http://localhost:8080").withSockJS();
}
- WebsocketConfig 前缀如果是 /topic ,就会把消息转发给消息代理
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic","/queue");
}
- SecurityConfig写入账户密码
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin")
.password("{noop}admin123")
.roles("admin")
.and()
.withUser("root")
.password("{noop}123")
.roles("admin")
.and()
.withUser("test")
.password("{noop}admin123")
.roles("admin");
}
- GreetingController
@MessageMapping("/hello") // 消息地址
@SendTo("/topic/greeting") // 转发广播地址,前端监听收到消息
- GreetingController chat
principal 用户信息
param chat 发过来的具体消息
public void chat(Principal principal, Chat chat) {
String name = principal.getName();
chat.setFrom(name);
messagingTemplate.convertAndSendToUser(chat.getTo(),"/queue/chat",chat);
}
- entity Chat
private String to; // 接收方
private String from; // 发送方
private String content; // 消息内容
// 展开 getter,setter 方法即可
- HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="/webjars/jquery/jquery.min.js"></script>
<script src="/webjars/sockjs-client/sockjs.min.js"></script>
<script src="/webjars/stomp-websocket/stomp.min.js"></script>
</head>
<body>
<div>
<input id="username" type="text" placeholder="目标用户名">
</div>
<div>
<input type="text" id="content">
<button id="send" type="button">发送</button>
</div>
<div id="chat" style="border:5px solid #000"></div>
<script>
var stompClient;
$(function () {
connect(); // 建立连接
$('#send').click(function () { // 点击发送
stompClient.send('/online_chat',{},JSON.stringify({
'to':$('#username').val(),
'content':$('#content').val()
}))
})
})
function connect() { // 建立连接
var socketjs = new SockJS("/chat"); // 指定端点
stompClient = Stomp.over(socketjs); // 操作 websocket
stompClient.connect({},function (frame) { // 建立连接
stompClient.subscribe('/user/queue/chat',function (greeting) {
var msgBody = JSON.parse(greeting.body);
$('#chat').append('<div>'+msgBody.from+' : '+ msgBody.content +'</div>')
})
})
}
</script>
</body>
</html>
- 效果图:
Websocket 一对多通信
- 消息代理前缀,发送消息的前缀如果是 /topic ,就会把消息转发给消息代理,再把消息广播给所有客户端
private String name; // 消息来源
private String content; // 消息内容
- 重写HTML
<script>
var stompClient;
$(function () { // 点击连接按钮
$('#connect').click(function () {
connect();
}) // 点击断开连接按钮
$('#disconnect').click(function () {
stompClient.disconnect();
setConnect(false);
}) // 点击发送内容按钮
$('#send').click(function () {
stompClient.send('/hello',{},JSON.stringify({
'name':$('#username').val(),
'content':$('#content').val()
}))
})
})
function connect() {
if (!$('#username').val()) {// 判断是否添加用户名
return;
}
var socketjs = new SockJS("/chat");
stompClient = Stomp.over(socketjs);
stompClient.connect({},function (frame) {
setConnect(true);
stompClient.subscribe('/topic/greeting',function (greeting) {
var msgBody = JSON.parse(greeting.body);
$('#chat').append('<div>'+msgBody.name+' : '+ msgBody.content +'</div>')
})
})
}
function setConnect(connected) { // 按钮状态设置
$('#connect').prop('disabled',connected);
$('#disconnect').prop('disabled',!connected);
$('#send').prop('disabled',!connected);
}
</script>
- 效果图:
服务区远程调用
- 1.创建serviceprovider&consumer (Spring Boot DevTools & Spring Web)
2.entity 创建 MsgBean
public class MsgBean implements Serializable
private Integer id;
private String content;
private String statusId;//特征ID
- 3.controller
@GetMapping("getMsgInfo")
public MsgBean getMsgInfo(){
MsgBean msgBean =new MsgBean();
msgBean.setId(1001);
msgBean.setContent("这里是服务提供方1 创建的msgbean *****从9090端口发出");
msgBean.setStatusId(UUID.randomUUID().toString()); //随机UUID
return msgBean;
}
- 4.application:9090
5.consumer MsgService
//远程调用 9090端口的服务器
// 需要用到RestTemplate
// 1.核心配置文件中配置RestTemplate
// 2. 使用RestTemplate
- config SpringConfig
//配置restTemplate
@Autowired
RestTemplate restTemplate;
@Autowired
DiscoveryClient discoveryClient;
- 调用9090,返回即可
restTemplate.getForObject("http://127.0.0.1:9090/getMsgInfo",MsgBean.class);
- controller
@GetMapping("getRemoteMsgByService")
public MsgBean getRemoteMsgByService(){
MsgBean msg=msgService.getRemoteService();
return msg;
}
- 效果图:
Serviceprovider cluster
-
1.pom & maven
2.application Spring名称统一 -
provider
server.port=9090
#spring 应用名称
spring.application.name=serviceprovider-server
#注册eureka客户端
eureka.client.service-url.instance.prefer-ip-address=true
#指定客户端的ip地址
eureka.client.service-url.instance.ip-address=127.0.0.1
eureka.instance.instance-id=serviceprovider-server1-9090
#作为客户端指定注册中心的位置
#eureka.client.service-url.defaultZone=http://127.0.0.1:8891/eureka/
eureka.client.service-url.defaultZone=http://127.0.0.1:8891/eureka/,http://127.0.0.1:8892/eureka/,http://127.0.0.1:8893/eureka/
- provider2
server.port=9091
#spring 应用名称
spring.application.name=serviceprovider-server
#注册eureka客户端
eureka.client.service-url.instance.prefer-ip-address=true
#指定客户端的ip地址
eureka.client.service-url.instance.ip-address=127.0.0.1
eureka.instance.instance-id=serviceprovider-server1-9091
#作为客户端指定注册中心的位置
#eureka.client.service-url.defaultZone=http://127.0.0.1:8891/eureka/
eureka.client.service-url.defaultZone=http://127.0.0.1:8891/eureka/,http://127.0.0.1:8892/eureka/,http://127.0.0.1:8893/eureka/
- provider3
server.port=9092
#spring 应用名称
spring.application.name=serviceprovider-server
#注册eureka客户端
eureka.client.service-url.instance.prefer-ip-address=true
#指定客户端的ip地址
eureka.client.service-url.instance.ip-address=127.0.0.1
eureka.instance.instance-id=serviceprovider-server1-9092
#作为客户端指定注册中心的位置
#eureka.client.service-url.defaultZone=http://127.0.0.1:8891/eureka/
eureka.client.service-url.defaultZone=http://127.0.0.1:8891/eureka/,http://127.0.0.1:8892/eureka/,http://127.0.0.1:8893/eureka/
-
同步controller & entity
-
CTRL C & CTRL V
@RestController
public class HelloController {
@GetMapping("getMsgInfo")
public MsgBean getMsgInfo(){
MsgBean msgBean =new MsgBean();
msgBean.setId(181203616);
msgBean.setContent("这里是服务提供方1 创建的msgbean *****从9090端口发出");
msgBean.setStatusId(UUID.randomUUID().toString());
return msgBean;
}
}
public class MsgBean implements Serializable {
private Integer id;
private String content;
private String statusId;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getStatusId() {
return statusId;
}
public void setStatusId(String statusId) {
this.statusId = statusId;
}
@Override
public String toString() {
return "MsgBean{" +
"id=" + id +
", content='" + content + '\'' +
", statusId='" + statusId + '\'' +
'}';
}
}
云端注册中心 SpringCloud-Eureka
- 1.Spring Boot DevTools & Spring Web & Eureka Server
- 2.pom & maven
- 3.port :8891
- 4.Eureka application
server.port=8891
#spring 名称
spring.application.name = eureka-server-8891
#注册中心配置
# 注册中心主机 ip
eureka.instance.hostname = 127.0.0.1
# 注册自己
eureka.client.register-with-eureka=true
# 检索服务
eureka.client.fetch-registry=true
# 指定当前作为客户端 指定注册中心位置(单机)
#eureka.client.service-url.defaultZone = http://${eureka.instance.hostname}:${server.port}/eureka
eureka.client.service-url.defaultZone =http://127.0.0.1:8892/eureka/,http://127.0.0.1:8893/eureka/
# 是否关闭自我保护模式(手动关闭)
#eureka.server.enable-self-preservation=false
eureka.instance.instance-id=eureka-server-8891
server.port=8892
spring.application.name=eureka-server:8892
#注册中心配置
# 注册中心主机 ip
eureka.instance.hostname = 127.0.0.1
# 注册自己
eureka.client.register-with-eureka=true
# 检索服务
eureka.client.fetch-registry=true
# 指定当前作为客户端 指定注册中心位置(单机)
#eureka.client.service-url.defaultZone = http://${eureka.instance.hostname}:${server.port}/eureka
eureka.client.service-url.defaultZone =http://127.0.0.1:8891/eureka/,http://127.0.0.1:8893/eureka/
# 是否关闭自我保护模式(手动关闭)
#eureka.server.enable-self-preservation=false
eureka.instance.instance-id=eureka-server-8892
server.port=8893
spring.application.name=eureka-server:8893
#注册中心配置
# 注册中心主机 ip
eureka.instance.hostname = 127.0.0.1
# 注册自己
eureka.client.register-with-eureka=true
# 检索服务
eureka.client.fetch-registry=true
# 指定当前作为客户端 指定注册中心位置(单机)
#eureka.client.service-url.defaultZone = http://${eureka.instance.hostname}:${server.port}/eureka
eureka.client.service-url.defaultZone =http://127.0.0.1:8891/eureka/,http://127.0.0.1:8892/eureka/
# 是否关闭自我保护模式(手动关闭)
#eureka.server.enable-self-preservation=false
eureka.instance.instance-id=eureka-server-8893
- Discovery Client获得服务实例对象,获得其名字
@Autowired
DiscoveryClient discoveryClient; //获得注册中心实例对象
discoveryClient.getInstances("serviceprovider-server");
MsgBean msgBean = restTemplate.getForObject("http://"+serviceInstance.getHost()+":"+serviceInstance.getPort()+"/getMsgInfo",MsgBean.class);
-
consumer
-
MsgService
public MsgBean getRemoteService(){
// MsgBean msgBean=
// http://127.0.0.1:9090/getMsgInfo
// http://127.0.0.1:9091/getMsgInfo
// http://127.0.0.1:9092/getMsgInfo
//
// restTemplate.getForObject("http://127.0.0.1:9090/getMsgInfo",MsgBean.class);
//使用DiscoveryClient获得注册中心中 注册的 实例对象
//根据 spring.application.name 去获得实例spring.application.name=serviceprovider-server
List<ServiceInstance> list = discoveryClient.getInstances("serviceprovider-server");
//自实现轮询
//ServiceInstance serviceInstance=list.get((instanceNum++)%3);
//LoadBalancerClient 自动轮询访问
ServiceInstance serviceInstance = loadBalancerClient.choose("serviceprovider-server");
MsgBean msgBean = restTemplate.getForObject("http://"+serviceInstance.getHost()+":"+serviceInstance.getPort()+"/getMsgInfo",MsgBean.class);
return msgBean;
- 效果图:
Ribbon实现均衡负载
类
- Consumer MsgService中
- 可获得所有在注册中心的 对应名称的实例数组集合
- LoadBalancerClient 自动获取对应实例对象
@Autowired
LoadBalancerClient client;
LoadBalanLcerClient loadBalancerClient;
loadBalancerClient.choose("serviceprovider-server");
注解
- 1.放入configuration配置文件中
- SpringConfig
// 配置restTemplate
@Bean
@LoadBalanLcer
public RestTemplate restTemplate(){
return new RestTemplate();
}
- MsgService
String url = "http://serviceprovider-server/getMsgInfo";
MsgBean msgBean = restTemplate.getForObject(url,MsgBean.class);
核心配置文件更改均衡算法
- application
//随机策略
springcloudMovie-Service.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
//轮训策略
springcloudMovie-Service.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RoundRobinRule
//重试策略
springcloudMovie-Service.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RetryRule
//最低并发策略
springcloudMovie-Service.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.BestAvailableRule
//可用过滤策略
springcloudMovie-Service.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.AvailabilityFilteringRule
//响应时间加权策略
springcloudMovie-Service.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.ResponseTimeWeightedRule
- 效果图: