ppgjx 发表于 2022-5-21 23:08

java回调请教

本帖最后由 ppgjx 于 2022-5-21 23:09 编辑

我现在在做一个用户系统,基于token认证的,现在想建立一个websocket服务所有登录的用户都链接这个websocket服务器 ,但是websocket如何实时踢人下线这个问题困扰了我很久

这是我的登录校验代码,可以到看到每次请求都去检测用户带来的uid和token是否和redis里面的匹配
package com.ppgjx.app.interceptor;

import com.ppgjx.app.annotation.PxCheckLogin;
import com.ppgjx.app.annotation.PxCheckRole;
import com.ppgjx.app.common.user.ans.common.UserInfo;
import com.ppgjx.app.common.user.ans.common.UserRoleInfo;
import com.ppgjx.app.common.user.ans.common.UserRolePermissionInfo;
import com.ppgjx.app.constant.RedisKey;
import com.ppgjx.app.constant.ResultCode;
import com.ppgjx.app.execption.ResRunException;
import com.ppgjx.app.util.MyUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
*
* 用户登录拦截器
*
*/
@Slf4j
public class UserLoginInterceptor extends HandlerInterceptorAdapter {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    //过滤未登录用户
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
      this.hasPermission(handler,request);
      returntrue;
    }

    //判断是否登录
    private void isLogin(HttpServletRequest request){
      String uid =request.getHeader("uid");
      String token =request.getHeader("token");
      if(null != uid && null != token){
            String redisUid = stringRedisTemplate.opsForValue().get(String.format(RedisKey.LOGIN_USER_TOKEN,uid ));
            if(!token.equals(redisUid)){
                throw new ResRunException(ResultCode.OTHER_LOGIN_ERR);
            }
      }else {
            throw new ResRunException(ResultCode.NOT_LOGIN_ERR);
      }
    }


    /**
   * 是否有权限
   */
    private boolean hasPermission(Object handler,HttpServletRequest request) {
      if (handler instanceof HandlerMethod) {


            HandlerMethod handlerMethod = (HandlerMethod) handler;
            //获取类上的注解
            PxCheckLogin pxCheckLoginClass =handlerMethod.getMethod().getDeclaringClass().getAnnotation(PxCheckLogin.class);
            // 获取方法上的注解
            PxCheckLogin pxCheckLogin = handlerMethod.getMethod().getAnnotation(PxCheckLogin.class);
            //如果类上加了注解进行拦截
            if(null != pxCheckLoginClass){
                //如果这个方法有注解 且 设置了为不登录则通过 否则检验
                if(null != pxCheckLogin && !pxCheckLogin.value()){
                  return true;
                }else {
                  this.isLogin(request);
                }
            }else {
                //如果类上没注册则检查方法
                if(null != pxCheckLogin && pxCheckLogin.value()){
                  this.isLogin(request);
                }
            }
      }
      return true;
    }
}


这是我的websockert服务器代码 只是做了简单的逻辑 没有做登录 我现在想的是 怎么才能让用户校验类 如果判断用户下线了 会给websocket一个回调 这样就完美的解决及时下线的问题 但是我实在不知道这个回调改怎么写 希望有大佬帮帮我

package com.ppgjx.app.netty.user;


import com.ppgjx.app.service.PxUserService;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Component
@Slf4j
public class UserChannelHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {


    private static StringRedisTemplate redisTemplate;

    private static PxUserService pxUserService;


    @Resource
    public void setStringRedisTemplate(StringRedisTemplate redisTemplate) {
      UserChannelHandler.redisTemplate = redisTemplate;
    }



    @Resource
    public void setPxUserService(PxUserService pxUserService) {
      UserChannelHandler.pxUserService = pxUserService;
    }


    //用户id=>channel示例
    //可以通过用户的唯一标识保存用户的channel
    //这样就可以发送给指定的用户
    public static ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);


    //客户端断开链接
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
      System.out.println("客户端断开连接 --- " + ctx.channel().id() );
      clients.remove(ctx.channel());
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
      System.out.println("channelRead");
      super.channelRead(ctx, msg);
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
      //获取客户端消息
      String context = msg.text();
      log.info(ctx.channel().id().asShortText() + " 测试数据 ---" + context + " -- 当前客户数量 --- " + clients.size());

      pushAllUser( "用户: " + ctx.channel().id().asShortText() + " 消息: " + context + " 当前客户数量: " + clients.size());
    }

    /**
   * 推送所有
   * @Param text
   */
    public void pushAllUser(String text){
      clients.writeAndFlush(new TextWebSocketFrame(text));
    }


    /**
   * 推送所有除了自己
   * @param text
   * @param ctx
   */
    public void pushOtherUser(String text,ChannelHandlerContext ctx){
      clients.forEach(ch ->{
            if(ctx.channel() != ch){
                ch.writeAndFlush(new TextWebSocketFrame(text));
            }
      });
    }

    //客户端建立连接
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throwsException{

      System.out.println("客户端建立连接 --- " + ctx.channel().id() );
      //添加channels
      clients.add(ctx.channel());
    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
      System.out.println("异常 --- " + ctx.channel().id());
      ctx.channel().close();
      clients.remove(ctx.channel());
    }



}

Kuronoks 发表于 2022-5-22 02:47

保存Session,open的时候保存对应用户的Session,close的时候删除

unmask 发表于 2022-5-22 09:13

用户下线,netty不是会触发handlerRemoved的吗?我还是不太懂你的具体需求...

cmbslgn 发表于 2022-5-22 09:27

xiadongming 发表于 2022-5-22 15:20

页: [1]
查看完整版本: java回调请教