Websocket+前端传参+定时任务(避免数据乱的问题)

我们在使用Websocket的时候,有时候会用到定时任务+参数传递的问题

 在项目中遇到了要使用Websocket服务,其中需求就是,我拿到前端传递某个企业的id并使用websockt建立连接后,再查询该企业的实时信息做一个每5min查询的定时任务,并将查询的值返回给前端。其实听起来不难,但是实际上在使用的时候,遇到了一些大伙可能都会遇到的问题,所以今天将我在websockt上遇到的问题写出来,有更好的方式的大伙可以一起讨论啊。

1,Websocket的配置:

主要目的是为了获取前端传递来的参数,同时要使用ws的服务,必须配置的。例如,我想从Websocket的链接中拿到前端传递的corp_id和equipids的参数,那么此时,我应该在 userProperties这个map集合里放入我想得到的参数,同时,定义FzjkConfigurator 这个类也是为了在后续的配置文件上使用该类,具体配置代码如下:

import org.springframework.context.annotation.Configuration;

import javax.servlet.http.HttpServletRequest;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;
import java.util.List;
import java.util.Map;

@Configuration
public class FzjkConfigurator extends ServerEndpointConfig.Configurator {


    @Override
    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
        // 可获取request中的请求参数的集合
        Map<String, List<String>> queryParam = request.getParameterMap();
        Map<String, Object> userProperties = sec.getUserProperties();
        // 以获取get请求中的id参数为例
        userProperties.put("corp_id", queryParam.get("corp_id").get(0));
        userProperties.put("equipids", queryParam.get("equipids").get(0));
     //   System.out.println("此时接收到的企业id为:"+queryParam.get("corp_id").get(0));
        super.modifyHandshake(sec, request, response);
    }

}

1,Websocket的配置:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.sthj.gkjk.wap.config.websocket.FzjkConfigurator;
import com.sthj.gkjk.wap.feign.TdService;
import lombok.SneakyThrows;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;

@ServerEndpoint(value = "/api/websocket/wap/fzjk", configurator = FzjkConfigurator.class)
@Component
public class FzjkSocket extends Endpoint {

   private static ConcurrentHashMap<String, String> hashMap = new ConcurrentHashMap<>();
    // concurrent包的线程安全Set,用来存放每个客户端对应的Session对象。
    private static CopyOnWriteArraySet<Session> sessionSet = new CopyOnWriteArraySet<Session>();
    private static final AtomicInteger onlineCount = new AtomicInteger(0);
    
   @PostConstruct
    public void init() {
        System.out.println("websocket 加载");
    }
    //最关键的一步,确保可以拿到参数做定时任务
   @SneakyThrows
    @Override
    public void onOpen(Session session, EndpointConfig config) {
      sessionSet.add(session);
        String corp_id = config.getUserProperties().get("corp_id").toString();
        String equipids = config.getUserProperties().get("equipids").toString();
        remote = session.getBasicRemote();
        //此处我将  session.getId()为了唯一的key值。将 corp_id + "_" + equipids作为value放到hashMap里,这样,我在
        //定时任务拿到hashMap的时候,用key值做唯一键处理,这样可以拿到我想要的corp_id和equipids,
        //之前,我在这块的时候犯过错, 用的是 hashMap.put(“corp_id”, corp_id + "_" + equipids);
        //上述这样会导致,其实corp_id这个key值一直在被刷新,这样会导致定任务里拿到的参数不是我们想要的参数
        hashMap.put(session.getId(), corp_id + "_" + equipids);
        int cnt = onlineCount.incrementAndGet(); // 在线数加1


}

     public static void sendMessage(String json, Session session) throws Exception {
        //推送  根据具体的明确业务写
        System.out.println(session.getId());
        session.getBasicRemote().sendText(json);
    }
        @OnMessage
     public void onMessage(String message) {
        /* 从前端接收message消息 */
    }
      public static ConcurrentHashMap<String, String> getHashMap() {
        return hashMap;
    }
        /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session) {
        sessionSet.add(session);
        int cnt = onlineCount.incrementAndGet(); // 在线数加1
        System.out.println("有人已建立连接,当前连接总数=" + cnt);
    }
    //在定时任务里会调用改方法去给前端传递结果
    public static void sendBatchInfo(Map<String, String> jsonMap) throws Exception {
        for (Session session : sessionSet) {
            if (session.isOpen()) {
                String json = jsonMap.get(session.getId());
                sendMessage(json, session);
            }
        }
    }
        @OnClose
    public void onClose(Session session) {
        sessionSet.remove(session);
        hashMap.remove(session.getId());
        int cnt = onlineCount.incrementAndGet(); // 在线数加1
        System.out.println("有人已断开连接,当前连接数为=" + cnt);
    }
     @OnError
    public void onError(Session session, Throwable error) {
        System.out.println("socket连接异常!");
        error.printStackTrace();
    }
    }
    

定时任务怎么写

我这次写的定时任务是用@Scheduled注解的方式

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class FzjkTask {
   
    @Scheduled(cron = "0 1/5 * * * ?") // 从第1分钟开始,每5分钟一次
    public void FzjkTask1() throws Exception {
      Map<String, String> resultMap = new HashMap<>();
    //     
    ConcurrentHashMap<String, String> hashMap = FzjkSocket.getHashMap();
        for (String s : hashMap.keySet()) {
        //这个datas就是对于的session.getId()对于的value值corp_id + "_" + equipids
      String[] datas = hashMap.get(s).split("_");
      String corp_id=datas[0];
      String equids=datas[1]
      //接下来就可以用拿到的corp_id和equipids做对应的业务处理

          
        //为了保证我们传递出去的值是我们想要的结果
        //我们还是用key和value唯一对应传递   
      resultMap.put(s, JSON.toJSONString("此处为我们做业务处理的结果"));


      }
    //最后利用webscoket进行传值
    FzjkSocket.sendBatchInfo(resultMap);
    }
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值