当前位置:   article > 正文

使用WebSocket实现的一个小Demo_websocket客户端demo

websocket客户端demo

添加链接描述开发一个多人聊天室的 demo,包含以下功能
​ 1.用户注册功能:注册成功后持久化用户信息到数据库
​ 2.用户登录功能:校验用户信息成功后,成功登录并且返回 token 信息和缓存至 Redis
​ 3.多人聊天功能 :携带 token 链接 WebSocet 并且链接时校验 token 是否合法,链接成功后进入聊天室可以正常聊天
​ 4.单客户端登录:一个账号只能一个客户端,后登录的客户端需把前面一个客户端踢下线,效果如下:在客户端 A 中用户 1 登录成功并且携带 token 链接 WebSocket 后继续在客户端 B 登录用户 1 账号拿到 token 也链接 WebSocet,这时客户端 A 需要接收到 WebSocket 发来踢下线消息

UserController

@RestController
@RequestMapping("api/v1/user")
public class UserController {


    @Autowired
    UserService userService;

    /**
     * 注册
     * @param userDto
     * @return
     */
    @PostMapping("/register")
    public JsonData register(@RequestBody UserDto userDto){
        JsonData jsonData = userService.register(userDto);
        return jsonData;
    }

    /**
     * 登录
     * @param userDto
     * @return
     */
    @PostMapping("/login")
    public JsonData login(@RequestBody UserDto userDto){
        User user = userService.login(userDto);
        String token = userService.geneAccountToken(user);

        return JsonData.buildSuccess(token);
    }
}
  • 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

UserServiceImpl

@RestController
@RequestMapping("api/v1/user")
public class UserController {


    @Autowired
    UserService userService;

    /**
     * 注册
     * @param userDto
     * @return
     */
    @PostMapping("/register")
    public JsonData register(@RequestBody UserDto userDto){
        JsonData jsonData = userService.register(userDto);
        return jsonData;
    }

    /**
     * 登录
     * @param userDto
     * @return
     */
    @PostMapping("/login")
    public JsonData login(@RequestBody UserDto userDto){
        User user = userService.login(userDto);
        String token = userService.geneAccountToken(user);

        return JsonData.buildSuccess(token);
    }
}
  • 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

JWTUtil

@Slf4j
public class JWTUtil {
    /**
     * 主题
     */
    private static final String SUBJECT = "luo";

    //客户端加密密钥
    private static final String CLIENT_SECRET = "123abc";

    //用户令牌前缀
    private static final String CLIENT_TOKNE_PREFIX = "abc";

    /**
     * 用户token过期时间,7天
     */
    public static final long CLIENT_EXPIRED = 1000 * 60 * 60 * 24 * 7;

    /**
     * 生成token
     * @param loginAccount
     * @return
     */
    public static String geneClientJsonWebToken(LoginAccount loginAccount) {

        if (loginAccount == null) {
            throw new NullPointerException("对象参数为空");
        }
        log.info("loginAccount:{}",loginAccount);

        String token = Jwts.builder().setSubject(SUBJECT)
                //配置payload
                .claim("id",loginAccount.getId())
                .claim("username", loginAccount.getUsername())
                .claim("password", loginAccount.getPassword())
                .claim("loginDateTime", new Date())
                .signWith(SignatureAlgorithm.HS256, CLIENT_SECRET).compact();
        //生成token
        token = CLIENT_TOKNE_PREFIX + token;
        return token;
    }

    /**
     * 解密token
     * @param token
     * @return
     */
    public static Claims checkClientJWT(String token){
        try {
            final Claims claims =Jwts.parser().setSigningKey(CLIENT_SECRET)
                    .parseClaimsJws(token.replace(CLIENT_TOKNE_PREFIX,"")).getBody();
            return claims;
        }catch (Exception e){
            log.error("解密失败");
            return null;
        }
    }
  • 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

WebSocketService

/**
 * @author :lwj
 * @date : 2023/3/23
 */
@Slf4j
@Component
@ServerEndpoint("/websocket/{token}")
public class WebSocketServer {

    /**concurrent包的线程安全集合,也可以map改成set,用来存放每个客户端对应的MyWebSocket对象。*/
    public static  ConcurrentHashMap<String, Session> webSocketMap = new ConcurrentHashMap<>();

    /**
     * 连接建立时
     */
    @OnOpen
    public void onOpen(@PathParam("token") String token, Session session) {
        //检验token是否合法
        try {
            //校验token是否合法
            Claims claims = JWTUtil.checkClientJWT(token);
            //获取用户id
            String id =  claims.get("id").toString();
            //判断用户是否登录
            if (webSocketMap.containsKey(id)){
                //向断开连接的客户端发送消息
                sendMessage(webSocketMap.get(id),"您已经被下线");
                webSocketMap.get(id).close();
                webSocketMap.remove(id);
                //再次连接
                webSocketMap.put(id,session);
                log.info("用户登录:{}", id);
            }else {
                log.info("用户登录:{}", id);
                //将自己的信息添加到map集合中
                webSocketMap.put(id, session);


            }

        } catch (Exception e) {
            log.error("解析token失败");
        }
    }
    /**
     * 客户端接收服务端发来的数据时
     */
    @OnMessage
    public void onMessage (@PathParam("token") String token, String message) throws IOException {
        //校验token是否合法
        Claims claims = JWTUtil.checkClientJWT(token);
        //获取用户id
        String id =  claims.get("id").toString();
        log.info("【websocket消息】收到客户端用户{}发来的消息:{}", id,message);
        sendMessage(webSocketMap.get(id),message);
        log.info("发送消息:{}, {}", id, message);
    }

    /**
     * 连接关闭
     */
    @OnClose
    public void onClose (@PathParam("token") String token, Session session){
        //校验token是否合法
        Claims claims = JWTUtil.checkClientJWT(token);
        //获取用户id
        String id =  claims.get("id").toString();
        //从当前的map集合中移除该用户
        webSocketMap.remove(id);

        try {
            session.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 聊天发生错误
     */
    @OnError
    public void onError (Session session, Throwable error){
        try {
            //关闭WebSocket下的该Seesion会话
            session.close();
        } catch (IOException e) {
            log.error("错误原因:"+error.getMessage());
            e.printStackTrace();
        }
    }


        /**
         * 使用连接发送消息
         * @param session 用户的session
         * @param message 发送的消息内容
         */
        public  void sendMessage(Session session,String message)   throws IOException {
                session.getBasicRemote().sendText(message);
    }
}
  • 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
  • 97
  • 98
  • 99
  • 100
  • 101

源码

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/44338
推荐阅读
相关标签
  

闽ICP备14008679号