パッケージcom.sankuai.qcs.regulation.nanjing.util。 輸入com.dianping.squirrel.client.StoreKey。 輸入com.dianping.squirrel.client.impl.redis.RedisStoreClient。 輸入com.dianping.zebra.util.StringUtils。 輸入com.google.common.collect.Maps。 輸入com.sankuai.meituan.config.MtConfigClient。 輸入com.sankuai.qcs.regulation.nanjing.Conf。 輸入org.apache.http.HttpException。 輸入org.slf4j.Logger。 輸入org.slf4j.LoggerFactory; 輸入org.springframework.stereotype.Component。 輸入javax.annotation.Resource。 輸入java.util.Map; / * * *説明: * tanxiaoleiのによって作成 *発売日:2018年4月20日午前11時50分 * / @Component パブリック クラスTokenUtils { プライベート 静的最終ロガーロガー= LoggerFactory.getLogger(TokenUtils。クラス)。 @Resource プライベートRedisStoreClient redisStoreClientを。 @Resource プライベートMtConfigClient mtConfigClientを。 プライベート 静的な最終文字列KEY_CATEGORY = 「regulation_traffic 」。 プライベート 静的 =最終文字列TOKEN_KEY_PARAMS 「nanjing_token_key 」。 // 缓存失效时间11个小时 プライベート 静的最終int型TOKEN_EXPIRE_SECONDS = 39600 ; プライベート 静的 =最終文字列LOCK_KEY_PARAMS 「nanjing_lock_key 」。 // 分布式锁失效时间2秒 プライベート 静的最終int型 LOCK_EXPIRE_SECONDS = 2 ; プライベート 静的な最終文字列NJ_TOKEN_USERID = 「NJ_TOKEN_USERID 」。 プライベート 静的最終地図<文字列、文字列>ヘッダ= Maps.newHashMap(); 静的{ headers.put(「接続」、「キープアライブ" ); headers.put(" -文字セット受け入れ"Conf.DEFAULT_CHARSET); headers.put(" コンテンツタイプ」、Conf.ContentType.JSON.getMimeTypeを()); } / * * *判断トークン是否在Redisの存在 * * @return * / パブリックブールtokenExists(){ StoreKeyキー = 新しいStoreKey(KEY_CATEGORY、TOKEN_KEY_PARAMS); 返す(キー)redisStoreClient.exists; } / * * *删除指定トークン * * @return * / 公共 ボイドdelToken(){ StoreKeyキー = 新しいStoreKey(KEY_CATEGORY、TOKEN_KEY_PARAMS)。 LOGGER.infoは(" キー:{}} {削除" 、キー、redisStoreClient.delete(キー))。 } / * * *获取トークン * * @return * / パブリック文字列入手トークン(){ StoreKeyキー = 新しいStoreKey(KEY_CATEGORY、TOKEN_KEY_PARAMS)。 トークン文字列 = redisStoreClient。取得(キー); LOGGER.info(" トークン得る:{}のRedisから" 、トークン)。 IF(トークン== nullの){ storekeyのロック = 新しい新storekey(KEY_CATEGORY、LOCK_KEY_PARAMS); // 分散ロックあなたがロックを取得しない場合は、直接それによって消費MQ影響し、サービスの問題南京側を防ぐために、放棄する IF(redisStoreClient.setnxを(ロック、" ロック" 、LOCK_EXPIRE_SECONDS)){ // 重複を防ぐために、ダブルチェック、トークンを取得 トークン= redisStoreClientを。GET )(キー; IF(トークン== nullの){ 試み{ 文字列のuserId =mtConfigClient.getValue(NJ_TOKEN_USERID)。 LOGGER.info(" mtConfigClientはUSERIDは得る:{} " 、USERID)。 トークン = HttpClientUtils.post(" のhttp:// " + Conf.GET_TOKEN_URL +はuserId、" 320100 " 、ヘッダ); LOGGER.info(" トークン得る:{} HTTPから" 、トークン)。 もし(StringUtils.isNotBlank(トークン)){ redisStoreClient。セット(キー、トークン、TOKEN_EXPIRE_SECONDS)。 } } キャッチ(HttpException E){ LOGGER.error(" errerトークンGET " 、E); } } // 分散を直接ロックして期限切れに redisStoreClient.expire(ロック、0 ); } } 戻りトークンを、 } }
パッケージcom.sankuai.qcs.regulation.nanjing.util。 輸入com.sankuai.qcs.regulation.nanjing.Conf。 輸入org.slf4j.Logger。 輸入org.slf4j.LoggerFactory; 輸入org.springframework.context.ApplicationContext; 輸入org.springframework.stereotype.Component。 輸入javax.websocket.ClientEndpoint。 輸入javax.websocket.CloseReason。 輸入javax.websocket.OnClose。 輸入javax.websocket.OnError。 輸入javax.websocket.OnMessage。 輸入javax.websocket.OnOpen。 輸入javax.websocket.Session。 / * * *説明: * tanxiaoleiのによって作成 *発売日:2018年4月18日14時26分 * / @ClientEndpoint @Component パブリック クラスWebSocketClientUtils { // @Autowired // プライベートTokenUtilsのtokenUtils。 プライベート 静的最終ロガーLOGGER = LoggerFactory.getLogger(WebSocketClientUtils。クラス); プライベート 静的のApplicationContextのApplicationContext。 パブリック 静的ApplicationContextのgetApplicationContext(){ 戻りのApplicationContextと、 } パブリック 静的 ボイドsetApplicationContext(ApplicationContextのApplicationContextの){ WebSocketClientUtils.applicationContext =ApplicationContextの; } @OnOpen 公共 ボイド開く時(セッションsession){ // 经过试验、客户端设置バッファサイズ时并不生效 session.setMaxBinaryMessageBufferSize(Conf.BINARY_MESSAGE_BUFFER_SIZE)。 session.setMaxTextMessageBufferSize(Conf.BINARY_MESSAGE_BUFFER_SIZE)。 LOGGER.info(" セッション{}、{}接続" 、session.getId()、session.getRequestParameterMap())。 } @OnMessage 公共 ボイドのonMessage(文字列メッセージ、セッションsession){ LOGGER.info(" セッションメッセージを受け取る:{} " 、メッセージ)。 //失效如果是403、表示トークン であれば(" 403 " .equals(メッセージ)){ delAndGetNewToken()。 } } @OnClose 公共 ボイド{(セッションセッション、CloseReason closeReason)OnCloseの (LOGGER.info " なぜなら} {セッションの最大バッファサイズ{} {}近い" session.getMaxBinaryMessageBufferSize()、session.getRequestParameterMap()、closeReason)。 } @OnError 公共 のボイドのonError(セッションsession、Throwableをスロー可能){ 場合(セッション!= nullの){ LOGGER.error(" セッション{}エラー"、スロー可能session.getRequestParameterMap())。 } 他{ LOGGER.error(" エラー" 、スロー可能)。 } } プライベート ボイドdelAndGetNewToken(){ TokenUtils tokenUtils =(TokenUtils)applicationContext.getBean(TokenUtils。クラス)。 LOGGER.info(" toeknUtils:{} " 、tokenUtils)。 tokenUtils.delToken(); LOGGER.info(" 再びトークンを取得:{} " 、tokenUtils.getToken())。 } }
/ * * キーが既に既存の値を変更することなく、存在する場合、キーが存在しない場合にのみ追加した場合*キー、値の加算値に対応 *#{@link RedisStoreClient追加(Storekey、オブジェクト、INT)} * @paramキーを追加するには、キー 値を追加する* @param値を * @paramのexpireInSecondsの有効期限の キーが存在し、正常trueに<BR>リターンを追加していない場合は*の@returnの キーがすでに存在する場合*は、falseを返します * @throws StoreException例外はあります必要に応じてStoreExceptionサブクラスとのRuntimeExceptionでは、対応する例外をキャプチャすることができます。 *として:あなたはタイムアウト例外をキャプチャする必要がある場合は、StoreTimeoutExceptionキャプチャすることができます * / パブリックブールSETNX(Storekeyキー、オブジェクトの値を、int型 expireInSecondsを)。
質問です:方法:
入手トークン
ロックメソッドを使用します。
(redisStoreClient.setnx(ロック、「ロック場合 」、LOCK_EXPIRE_SECONDS)){
このメソッドは存在しないとキーがすでに存在する場合のキーは、正常に追加された場合、falseを返す
と言って:追加する唯一の鍵は、そうでない場合は破棄され、唯一のトークンを取得成功し、防止します南京のサーバーの問題。