• Spring Boot 6.3 两个SpringBoot项目之间的如何通信?(重点)


    总结:重点是两个Springboot如何通信。
    1.backendmatchingsystem发信息:backend使用 restTemplate发送,matchingsystem使用controller层接收(重点)—>matchingsystemSecurity要放行
    2.匹配成功后,matcingsystembackend发送信息:matcingsystem使用RestTemplate发送,backend使用Controller接收(重点)—>backendSecurity要放行

    概念

    微服务详细解释
    微服务概念:
    (1)微服务就是一种架构风格
    (2)微服务就是把一个项目拆分成独立的多个服务,并且多个服务是可以独立运行的,而每个服务都会占用线程。

    目前微服务的开发框架
    最常用的有以下四个:

    Spring Cloud:http://projects.spring.io/spring-cloud(现在非常流行的微服务架构

    Dubbo:http://dubbo.io

    Dropwizard:http://www.dropwizard.io (关注单个微服务的开发)

    Consul、etcd&etc.(微服务的模块)

    创建流程

    项目流程:(红色-微服务)
    在这里插入图片描述
    创建backendcloud
    在这里插入图片描述
    软件包名称:作用是下图
    在这里插入图片描述
    父级项目没有逻辑:删除src文件
    修改pom文件:添加spring-cloud-dependencies依赖

    <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>2021.0.3</version>
        <type>pom</type>
        <scope>import</scope>
    </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    新建模块
    创建模块–>maven选项
    在这里插入图片描述

    将父级中pom文件中的所有依赖复制粘贴到matchingsystem下的pom文件

    <dependencies>
            <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>2021.0.3</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
    
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
                <exclusions>
                    <exclusion>
                        <groupId>org.junit.vintage</groupId>
                        <artifactId>junit-vintage-engine</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
        </dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    改变端口
    创建resources/application.properties

    server.port=3001
    
    • 1

    逻辑实现

    0.matchingsystem的接口(三种)+ 放行

    创建matchingsystem下的controller,service等文件夹
    创建接口MatchingService

    package com.kob.matchingsystem.service;
    
    public interface MatchingService {
        public String addPlayer(Integer userId,Integer rating);
        public String removePlayer(Integer userId);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    实现接口MatchingService

    package com.kob.matchingsystem.service.impl;
    
    import com.kob.matchingsystem.service.MatchingService;
    import org.springframework.stereotype.Service;
    
    @Service
    public class MatchingServiceImpl implements MatchingService {
    
        @Override
        public String addPlayer(Integer userId, Integer rating) {
            System.out.println("add player: "+userId+" "+rating);
            return "add player success";
        }
    
        @Override
        public String removePlayer(Integer userId) {
            System.out.println("remove player: "+userId);
            return "remove player success";
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    实现Controller控制

    package com.kob.matchingsystem.controller;
    
    import com.kob.matchingsystem.service.MatchingService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.util.MultiValueMap;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.Objects;
    
    @RestController
    public class MatchingController {
        @Autowired
        private MatchingService matchingService;
    
        @PostMapping("/player/add/")
        public String addPlayer(@RequestParam MultiValueMap<String,String> data){
            Integer userId = Integer.parseInt(Objects.requireNonNull(data.getFirst("user_id")));
            Integer rating = Integer.parseInt(Objects.requireNonNull(data.getFirst("rating")));
            return matchingService.addPlayer(userId,rating);
        }
    
        @PostMapping("/player/remove/")
        public String removePlayer(@RequestParam MultiValueMap<String,String> data){
            Integer userId = Integer.parseInt(Objects.requireNonNull(data.getFirst("user_id")));
            return matchingService.removePlayer(userId);
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    matchingsystem添加依赖spring-boot-starter-security

    由于Spring Cloudhttp请求,所以可能会接收到用户的伪请求,matchingsystem只能对于后端请求,因此需要防止外部请求,通过Spring Security来实现权限控制。

    <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-security -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
        <version>2.7.1</version>
    </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    添加配置类SecurityConfig
    只能接受后端访问

    package com.kob.matchingsystem.config;
    
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.HttpMethod;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.config.http.SessionCreationPolicy;
    
    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().disable()
                    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and()
                    .authorizeRequests()
                    .antMatchers("/player/add/").hasIpAddress("127.0.0.1")
                    .antMatchers(HttpMethod.OPTIONS).permitAll()
                    .anyRequest().authenticated();
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    建立matchingsystem的入口文件,点击文件左边绿色按钮

    package com.kob.matchingsystem;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class MatchingSystemApplication {
        public static void main(String[] args) {
            SpringApplication.run(MatchingSystemApplication.class, args);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    目前只放行了/player/add/

    测试:
    add:405–>只是post类型不对
    remove:403–>拒绝访问

    然后将remove放行

    .antMatchers("/player/add/","/player/remove/").hasIpAddress("127.0.0.1")
    
    • 1

    在这里插入图片描述
    在这里插入图片描述
    此处发现问题:

    此处:无论127.0.0.1还是localhost,
    访问都要用127.0.0.1-->405
    如果localhost访问---->403
    .antMatchers("/player/add/","/player/remove/").hasIpAddress("127.0.0.1")
    
    访问链接一定要写
    //正确访问 出现405
    127.0.0.13001/player/add/127.0.0.13001/player/remove/
    //错误访问 出现403
    localhost:3001/player/add/
    或localhost:3001/player/remove/
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    创建backend模块,删除src,导入源项目的src
    修改新的pom,将源项目的pom中的依赖复制粘贴过来

    1.先封装向前端发送地图,操作等信息的函数startGame

    //封装向前端传地图,操作等信息
    private void startGame(Integer aId,Integer bId){
    
        User a =userMapper.selectById(aId),b = userMapper.selectById(bId);
    
        //一局游戏的线程
        Game game =new Game(13,14,20,a.getId(),b.getId());
        game.createMap();
        //a,b共同的地图==>将地图赋给a,b对应的连接
        users.get(a.getId()).game = game ;
        users.get(b.getId()).game = game ;//b连接的地图
        game.start();
    
        JSONObject respGame  = new JSONObject();
        respGame.put("a_id",game.getPlayerA().getId());
        respGame.put("a_sx",game.getPlayerA().getSx());
        respGame.put("a_sy",game.getPlayerA().getSy());
        respGame.put("b_id",game.getPlayerB().getId());
        respGame.put("b_sx",game.getPlayerB().getSx());
        respGame.put("b_sy",game.getPlayerB().getSy());
        respGame.put("map",game.getG());
    
    
        JSONObject respA = new JSONObject();//返回给a
        respA.put("event", "start-matching");
        respA.put("opponent_username", b.getUsername());
        respA.put("opponent_photo", b.getPhoto());
        respA.put("game", respGame);
        users.get(a.getId()).sendMessage(respA.toJSONString());//获取a对应的连接,向前端传递信息(String)
    
        JSONObject respB = new JSONObject();//返回给b
        respB.put("event", "start-matching");
        respB.put("opponent_username", a.getUsername());
        respB.put("opponent_photo", a.getPhoto());
        respB.put("game", respGame);
        users.get(b.getId()).sendMessage(respB.toJSONString());//获取b对应的连接,向前端传递信息(String)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    2.配置RestTemplateConfig

    RestTemplate用于两个Spring boot的通信

    package com.kob.backend.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.client.RestTemplate;
    
    @Configuration
    public class RestTemplateConfig {
        @Bean
        public RestTemplate getRestTemplate(){
            return new RestTemplate();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    WebSocketServer中引用

    private static RestTemplate restTemplate;
    @Autowired
    public void setRestTemplate(RestTemplate restTemplate){ WebSocketServer.restTemplate = restTemplate ;}
    
    
    • 1
    • 2
    • 3
    • 4

    3.设计问题:修改数据库

    把rating放到user表,bot表删除Rating
    修改代码:
    1.pojo层:User添加属性rating,Bot删除属性rating
    2.所有构造修改
    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

    4.backendmatchingsystem发信息:backend使用 restTemplate发送,matchingsystem使用controller层接收(重点)

    修改startMatching,stopMatching函数
    如何给另一个SpringBoot发信息呢?

     restTemplate.postForObject(addPlayerUrl,data,String.class);
    
    • 1
    //前端点击  开始匹配 触发--》加入一个用户进行匹配--->发送请求给matchingsystem
    private void startMatching(){
        System.out.println("start matching!");
        //向另一个Spring Boot发送的数据
        MultiValueMap<String,String>  data = new LinkedMultiValueMap<>();
        data.add("user_id",this.user.getId().toString());
        data.add("rating",this.user.getRating().toString());
        restTemplate.postForObject(addPlayerUrl,data,String.class);
    }
    //前端点击  取消 触发 ---》取消一个用户的匹配--->发送请求给matchingsystem
    private void stopMatching(){
        System.out.println("stop matching!");
        MultiValueMap<String,String> data = new LinkedMultiValueMap<>();
        data.add("user_id",this.user.getId().toString());
        restTemplate.postForObject(removePlayerUrl,data,String.class);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    启动backend这个SpringBoot
    启动时,报错,3000被占用,使用win+r杀死进程
    目前实现的是红色路线
    在这里插入图片描述

    5.创建Player,MatchingPool类,简单编写逻辑(逻辑)

    创建utils工具包
    在这里插入图片描述

    utils下创建Player,MatchingPool

    package com.kob.matchingsystem.service.impl.utils;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Player {
        private Integer userId;
        private Integer rating;
        private Integer waitingTime;//等待时间
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    package com.kob.matchingsystem.service.impl.utils;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class MatchingPool extends Thread {
        private static List<Player> players = new ArrayList<>();
        private ReentrantLock lock = new ReentrantLock();
    
        //两个线程访问:1.匹配线程 2.传入参数的线程,开始匹配
        public void addPlayer(Integer userId,Integer rating){
            lock.lock();
            try {
                players.add(new Player(userId,rating,0));
            } finally {
                lock.unlock();
            }
        }
    
        public void removePlayer(Integer userId){
            lock.lock();
            try {
                List<Player> newPlayers = new ArrayList<>();
                for(Player player:players){
                    if(!player.getUserId().equals(userId)){
                        newPlayers.add(player);
                    }
                }
                players = newPlayers ;
            } finally {
                lock.lock();
            }
        }
    
        @Override
        public void run() {
            while(true){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    调用函数 addPlayer,removePlayer
    调用处:MatchingServiceImpl

    package com.kob.matchingsystem.service.impl;
    
    import com.kob.matchingsystem.service.MatchingService;
    import com.kob.matchingsystem.service.impl.utils.MatchingPool;
    import org.springframework.stereotype.Service;
    
    @Service
    public class MatchingServiceImpl implements MatchingService {
        //就一个线程
        public static final MatchingPool matchingPool = new MatchingPool();
    
        @Override
        public String addPlayer(Integer userId, Integer rating) {
            System.out.println("add player: "+userId+" "+rating);
            matchingPool.addPlayer(userId,rating);
            return "add player success";
        }
    
        @Override
        public String removePlayer(Integer userId) {
            System.out.println("remove player: "+userId);
            matchingPool.removePlayer(userId);
            return "remove player success";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    6.MatchingPool的逻辑,具体逻辑(逻辑)

    package com.kob.matchingsystem.service.impl.utils;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class MatchingPool extends Thread {
        private static List<Player> players = new ArrayList<>();
        private ReentrantLock lock = new ReentrantLock();
    
        //两个线程访问:1.匹配线程 2.传入参数的线程,开始匹配
        public void addPlayer(Integer userId,Integer rating){
            lock.lock();
            try {
                players.add(new Player(userId,rating,0));
            } finally {
                lock.unlock();
            }
        }
    
        public void removePlayer(Integer userId){
            lock.lock();
            try {
                List<Player> newPlayers = new ArrayList<>();
                for(Player player:players){
                    if(!player.getUserId().equals(userId)){
                        newPlayers.add(player);
                    }
                }
                players = newPlayers ;
            } finally {
                lock.lock();
            }
        }
    
        private void increaseWaitingTime(){//所有玩家的等待加时间1
            for(Player player:players){
                player.setWaitingTime(player.getWaitingTime()+1);
            }
        }
    
        private void matcingPlayers(){//匹配所有玩家
            boolean[] used = new boolean[players.size()];
            for(int i = 0 ; i < players.size() ; i++){
                if(used[i])continue;
                for(int j = i+1 ;j < players.size() ;j++){
                    if(used[j])continue;
                    Player a = players.get(i),b = players.get(j);
                    if(checkMatched(a,b)){
                        used[i] = used[j] = true;
                        sendResult(a,b);
                        break;
                    }
                }
            }
            //将匹配成功的删除
            List<Player> newPlayers =  new ArrayList<>();
            for(int i= 0;i<players.size();i++){
                if(!used[i]){
                    newPlayers.add(players.get(i));
                }
            }
            players =  newPlayers;
    
        }
    
        private boolean checkMatched(Player a,Player b){//判断两个玩家是否匹配
            int ratingDelta = Math.abs(a.getRating() - b.getRating());
            int waitingTime = Math.min(a.getWaitingTime(),b.getWaitingTime());
            return ratingDelta <= 10*waitingTime  ;
        }
    
        private void sendResult(Player a,Player b){
    
        }
    
        @Override
        public void run() {
            while(true){
                try {
                    Thread.sleep(1000);
                    lock.lock();
                    try {
                        increaseWaitingTime();
                        matcingPlayers();
                    } finally {
                        lock.unlock();
                    }
    
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96

    7.匹配成功后,matcingsystembackend发送信息,matcingsystem使用RestTemplate发送,backend使用Controller接收(重点)

    为了让backend端接受信息,创建接口,实现接口,实现控制器
    在这里插入图片描述

    backend放行:

    .antMatchers("/pk/start/game/").hasIpAddress("127.0.0.1")
    
    • 1

    创建接口

    package com.kob.backend.service.pk;
    
    public interface StartGameService {
        public String startGame(Integer aId,Integer bId);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    实现接口

    package com.kob.backend.service.impl.pk;
    
    import com.kob.backend.consumer.WebSocketServer;
    import com.kob.backend.service.pk.StartGameService;
    import org.springframework.stereotype.Service;
    
    @Service
    public class StartGameServiceImpl implements StartGameService {
        @Override
        public String startGame(Integer aId, Integer bId) {
            System.out.println("start game: "+ aId+" "+bId);
            WebSocketServer.startGame(aId,bId);
            return "start game success";
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    实现控制器

    package com.kob.backend.controller.pk;
    
    import com.kob.backend.service.pk.StartGameService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.util.MultiValueMap;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.Objects;
    
    @RestController
    public class StartGameController {
        @Autowired
        private StartGameService startGameService;
    
        @PostMapping("/pk/start/game/")
        public String StartGame(@RequestParam MultiValueMap<String,String> data){
            Integer aId = Integer.parseInt(Objects.requireNonNull(data.getFirst("a_id")));
            Integer bId = Integer.parseInt(Objects.requireNonNull(data.getFirst("b_id")));
            return startGameService.startGame(aId,bId);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    给backend发信息需要RestTemplate

    package com.kob.matchingsystem.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.client.RestTemplate;
    
    @Configuration
    public class RestTemplateConfig {
        @Bean
        public RestTemplate getRestTemplate(){
            return new RestTemplate();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在matchingsys的MatchingPool类下添加

     private final static String startGameUrl =  "http://127.0.0.1:3000/pk/start/game/";
    //因为是Bean
    private  static RestTemplate restTemplate ;
    @Autowired
    public void setRestTemplate(RestTemplate restTemplate) { MatchingPool.restTemplate = restTemplate ;}
    
    ......
    
    private void sendResult(Player a,Player b){
       System.out.println("send result: " + a + " " + b);
       MultiValueMap<String,String> data = new LinkedMultiValueMap<>();
       data.put("a_id", Collections.singletonList(a.getUserId().toString()));
       data.put("b_id", Collections.singletonList(b.getUserId().toString()));
       restTemplate.postForObject(startGameUrl,data,String.class);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    测试结果
    在这里插入图片描述
    在这里插入图片描述

    8.优化

    若玩家在匹配中突然停电,则会爆异常,需要特判
    情况描述:当user1突然关闭页面,此时user1还在匹配池中,可能会与其他玩家匹配成功,成功后,sendResult(),然后startGame()函数,但startGame函数中的users里早已经没有user1,因此users.get(a.getId()).game = game ;就会报错,因为是null.
    解决:将所有获取用户的语句,加一个判空操纵

    在这里插入图片描述
    总共修改六处,eg:

    if(users.get(a.getId()) != null)
        users.get(a.getId()).game = game ;
    if(users.get(b.getId()) != null)
        users.get(b.getId()).game = game ;
    
    • 1
    • 2
    • 3
    • 4
  • 相关阅读:
    L83.linux命令每日一练 -- 第11章 Linux系统管理命令 -- ipcs和ipcrm
    linux sh脚本各种数值进制转换(比如10进制转16)若干例子
    Vue源码系列6:模拟实现vue3.x中的toRef、toRefs
    undefined /swagger/v1/swagger.json错误解决
    如何做好软件测试管理的工作呢?
    运维工程师面试总结(含答案)
    tensorflow 1.13 cpu win10 安装 + object_detection 环境搭建 + paddle OCR
    20+ 波卡生态项目齐聚 TOKEN2049,参会指南请收好
    在云服务器上搭建Jupyter Notebook服务
    Linux PCIe驱动框架分析(第一章)
  • 原文地址:https://blog.csdn.net/qq_52384627/article/details/126512131