Bootstrap

websocket注解实现

 第一步:利用HandshakeRequest获取session(web端为session,App端为token)

//使用WebListener,监听前端请求,解决直接利用HandshakeRequest获取session为空的问题
@javax.servlet.annotation.WebListener()
public class GetHttpSessionConfigurator extends ServerEndpointConfig.Configurator implements ServletRequestListener {
	
	private static HttpSession session;
	private static HttpServletRequest req;
	
    /***
     * 本函数在连接转为WebSocket时调用,可从请求中获取所需要的用户信息
     */
	@SuppressWarnings("unchecked")
	@Override
    public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) {
		RedisService redisService = Global.getIoc().get(RedisService.class);
        String token = null;
        //首先如果有SessionID的情况,先取出SessionID
        if(null != session && null != session.getId()){
      		//根据SessionID去redis里查询token
        	token = redisService.get(session.getId());
      	}
        if(req.getHeader("token") != null){
			//将header中的token取出
			token = req.getHeader("token");
		}
        if(request.getParameterMap().get("token") != null){
        	token = request.getParameterMap().get("token").get(0);
        }
        
       //判断token是否为空,若是则为非法请求
       if(null != token && token.length() > 0){
    	   System.out.println("token : "   +  token);
    	   //利用token从redis中获取用户信息
    	   String userInfoJson = redisService.get(token);
    	   //该用户的信息在redis中不存在
    	   if(null == userInfoJson || userInfoJson.length() <= 0){
    		   config.getUserProperties().put("deviceId", "3");
    		   return;
    	   }
    	   //将用户信息解析成一个Map
    	   Map<String, Object> userInfo = (Map<String, Object>) JSON.parse(userInfoJson);
    	   //如果该Map为空,则属于登录验证失败
    	   if(userInfo.isEmpty()){
    		   config.getUserProperties().put("deviceId", "2");
    		   return;
    	   }
    	   //利用ioc获取一个dao
    	   Dao dao = Global.getIoc().get(Dao.class);
    	   //判断该用户是否绑定设备
    	   if(dao.count(Device.class, Cnd.where("uid", "=" , userInfo.get("uId"))) == 0){
    		   config.getUserProperties().put("deviceId", "1");
    		   return;
    	   }
    	   //将设备id存储在config中
    	   Device device = dao.query(Device.class, Cnd.where("uid", "=" , userInfo.get("uId"))).get(0);
		   config.getUserProperties().put("deviceId", device.getTID());
		   //判断该deviceid是否已经建立了连接
		   
       }else{
    	   config.getUserProperties().put("deviceId", "4"); 
    	   return;
       }
    }

	@Override
	public void requestDestroyed(ServletRequestEvent arg0) {
	}
	
	@Override
	public void requestInitialized(ServletRequestEvent arg0) {
		req = (HttpServletRequest) (arg0.getServletRequest());
		if(req.getServletPath().endsWith("/w/location/trace")){
		    session = req.getSession(false);
		}
	}
 
}

  第二步:从远程服务器接收数据,通过redis做数据处理进行返回,websocket发送给前端

/**
 * 这里采用的是Tomcat8的注解模式,不需要在web.xml里面配置
 */
@ServerEndpoint(value = "/w/location/trace", configurator = GetHttpSessionConfigurator.class)
public final class WsLocationModule {

	private static final Log log = Logs.get();

	private static final Map<String, Session> sessionMap = new ConcurrentHashMap<String, Session>();

	private final RedisService redisService = Global.getRedisService();

	/**
	 * 连接建立成功调用的方法
	 * 
	 * @param session
	 *            可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
	 * @throws EncodeException
	 */
	@OnOpen
	public void onOpen(Session session, EndpointConfig conf) throws EncodeException {
		// 从config中取出设备ID
		String deviceId = (String) conf.getUserProperties().get("deviceId");
		// 对在GetHttpSessionConfigurator中对用户的验证进行具体的处理
		if (deviceId.equals("1")) {
			sendMessage(session, JSON.toJSONString(Result.doError("该用户未绑定设备")));
		} else if (deviceId.equals("2")) {
			sendMessage(session, Json.toJson(Result.doError("获取用户数据失败")));
		} else if (deviceId.equals("3")) {
			sendMessage(session, Json.toJson(Result.doError("用户登录过期")));
		} else if (deviceId.equals("4")) {
			sendMessage(session, Json.toJson(Result.doError("请先登录")));
		} else if (deviceId.length() > 0) {
			System.out.println("设备id:" + deviceId);
			// 将session放置在sessionMap中保存,以deviceId作为键
			sessionMap.put(deviceId, session);
			if (null != redisService && null != redisService.get("last_location_" + deviceId)) {
				// 从redis中取出该终端最近的位置消息
				String lastLocation = redisService.get("last_location_" + deviceId);
				DeviceMessage deviceMessage = Json.fromJson(DeviceMessage.class, lastLocation);
				// 判断位置信息是否存在
				if (null != deviceMessage) {
					// 取出经纬度,封装成一个map,并发送给前端,当有redis中该终端的数据有更新时,在RedisPubSub中推送给前端
					/*Map<String, Object> coordinate = new TreeMap<>();
					coordinate.put("long", deviceMessage.getLongitude());
					coordinate.put("lat", deviceMessage.getLatitude());*/
					deviceMessage.setType(Type.Send);
					sendMessage(session, JSON.toJSONString(Result.doSuccess("连接成功", deviceMessage)));
				}
			}
		} else {
			sendMessage(session, "连接失败");
		}
	}

	@OnMessage
	public void process(Session session, String message) {
		// 目前预期不会受到任何传入的信息。
		// throw new NoSuchElementException();
	}

	@OnClose
	public void end(Session session) {
		System.out.println("断开设备" + session.getUserProperties().get("deviceId"));
		sessionMap.remove(session.getUserProperties().get("deviceId"), session);
		if (session.isOpen()) {
			try {
				session.close();
			} catch (IOException e) {
				log.error(e);
				e.printStackTrace();
			}
		}
		System.out.println("session " + session.getId() + " close.");
	}

	@OnError
	public void error(Session session, java.lang.Throwable throwable) {
		// FIXME 记录错误并关闭会话。
		if (throwable.getMessage() != null) {
			sessionMap.put(throwable.getMessage(), session);
			try {
				session.close();
			} catch (IOException e) {
				log.error(e);
				e.printStackTrace();
			}
		}

		System.err.println("session " + session.getId() + " error:" + throwable);
	}

	public static boolean sendMessage(String user, String message) {
		// TODO 从map中取得相关的session
		Session session = sessionMap.get(user);
		// TODO 通过session将message传出去
		if (session == null) {
			System.out.println("session不存在");
			return false;
		}
		System.out.println("session存在");
		sendMessage(session, message);
		return true;
	}

	public static void sendMessage(Session session, String message) {
		// 处于效率考虑,将该方法切换到异步实现。
		session.getAsyncRemote().sendText(message, new SendHandler() {
			@Override
			public void onResult(SendResult result) {
				if (!result.isOK()) { // 或考虑result.getException()!=null
					log.debug("发送消息失败:" + message);
					sessionMap.remove(session);
					try {
						session.close();
					} catch (IOException e) {
						// 无理由关闭
					}
				}
			}
		});
	}

 

转载于:https://my.oschina.net/u/3146886/blog/838397

;