From 4017fe347792c7e28695c455a40874f0c647cc9b Mon Sep 17 00:00:00 2001
From: Helius <wangdoubleone@gmail.com>
Date: Fri, 26 Nov 2021 16:46:45 +0800
Subject: [PATCH] add fish hit websocket
---
src/main/java/com/xcong/excoin/modules/fish/dao/MemberAccountGoldDao.java | 2
src/main/java/com/xcong/excoin/configurations/WebSocketConfig.java | 26 ++
src/main/resources/mapper/fish/MemberAccountGoldDao.xml | 3
src/main/java/com/xcong/excoin/common/initialization/InitJob.java | 62 +++++
src/main/java/com/xcong/excoin/configurations/RabbitMqConfig.java | 22 ++
src/main/java/com/xcong/excoin/websocket/fish/HitFishWebSocket.java | 119 ++++++++++
src/main/java/com/xcong/excoin/configurations/interceptor/WebCommonInterceptor.java | 34 +++
src/main/java/com/xcong/excoin/modules/fish/controller/MemberCannonController.java | 1
src/main/resources/application-test.yml | 1
src/main/java/com/xcong/excoin/configurations/security/WebSecurityConfig.java | 1
src/main/java/com/xcong/excoin/rabbit/consumer/FishHitConsumer.java | 46 ++++
src/main/java/com/xcong/excoin/websocket/fish/model/MsgModel.java | 34 +++
src/main/java/com/xcong/excoin/websocket/handler/FishHitWebSocketHandler.java | 118 ++++++++++
src/main/java/com/xcong/excoin/common/contants/AppContants.java | 3
src/main/java/com/xcong/excoin/common/system/entity/DataDictionaryCustom.java | 22 ++
src/main/resources/mapper/fish/CannonOwnRecordDao.xml | 9
src/main/java/com/xcong/excoin/ExcoinApplication.java | 4
src/main/java/com/xcong/excoin/modules/fish/vo/OwnCannonVo.java | 12
src/main/java/com/xcong/excoin/websocket/handler/FishHitWebSocketHandshakeInterceptor.java | 41 +++
src/main/resources/mapper/common/DataDictionaryCustomMapper.xml | 13 +
src/main/java/com/xcong/excoin/common/system/dao/DataDictionaryCustomDao.java | 14 +
src/main/resources/application.yml | 7
src/main/java/com/xcong/excoin/rabbit/producer/FishHitProducer.java | 37 +++
23 files changed, 614 insertions(+), 17 deletions(-)
diff --git a/src/main/java/com/xcong/excoin/ExcoinApplication.java b/src/main/java/com/xcong/excoin/ExcoinApplication.java
index a2a7e2b..9987fca 100644
--- a/src/main/java/com/xcong/excoin/ExcoinApplication.java
+++ b/src/main/java/com/xcong/excoin/ExcoinApplication.java
@@ -4,6 +4,7 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.web.socket.config.annotation.EnableWebSocket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
@@ -11,8 +12,9 @@
*/
@EnableScheduling
@EnableSwagger2
+@EnableWebSocket
@SpringBootApplication
-@MapperScan("com.xcong.excoin.modules.*.dao")
+@MapperScan({"com.xcong.excoin.modules.*.dao", "com.xcong.excoin.common.*.dao"})
public class ExcoinApplication {
public static void main(String[] args) {
diff --git a/src/main/java/com/xcong/excoin/common/contants/AppContants.java b/src/main/java/com/xcong/excoin/common/contants/AppContants.java
index 7fde51c..69899c5 100644
--- a/src/main/java/com/xcong/excoin/common/contants/AppContants.java
+++ b/src/main/java/com/xcong/excoin/common/contants/AppContants.java
@@ -83,4 +83,7 @@
public static final BigDecimal DEFAULT_PRICE = BigDecimal.valueOf(1.28);
+ public static final String DICTIONARY_TYPE_FISH = "FISH_TYPE";
+
+ public static final String CANNON_TYPE = "CANNON_TYPE";
}
diff --git a/src/main/java/com/xcong/excoin/common/initialization/InitJob.java b/src/main/java/com/xcong/excoin/common/initialization/InitJob.java
new file mode 100644
index 0000000..9d696a8
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/common/initialization/InitJob.java
@@ -0,0 +1,62 @@
+package com.xcong.excoin.common.initialization;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
+import com.xcong.excoin.common.contants.AppContants;
+import com.xcong.excoin.common.system.dao.DataDictionaryCustomDao;
+import com.xcong.excoin.common.system.entity.DataDictionaryCustom;
+import com.xcong.excoin.modules.fish.dao.CannonSettingDao;
+import com.xcong.excoin.modules.fish.entity.CannonSetting;
+import com.xcong.excoin.utils.RedisUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author wzy
+ * @date 2021-11-26
+ **/
+@Slf4j
+@Component
+public class InitJob {
+
+ @Autowired
+ private RedisUtils redisUtils;
+ @Autowired
+ private DataDictionaryCustomDao dictionaryCustomDao;
+ @Autowired
+ private CannonSettingDao cannonSettingDao;
+
+ @PostConstruct
+ public void init() {
+ log.info("####项目初始化数据####");
+
+ // 初始化鱼类数据到redis缓存
+ List<DataDictionaryCustom> fishTypes = dictionaryCustomDao.selectDicByType(AppContants.DICTIONARY_TYPE_FISH);
+ if (CollUtil.isNotEmpty(fishTypes)) {
+ Map<String, Object> map = new HashMap<>();
+ for (DataDictionaryCustom fishType : fishTypes) {
+ Integer cnt = StrUtil.isEmpty(fishType.getValue()) ? 0 : Integer.parseInt(fishType.getValue());
+ map.put(fishType.getCode(), cnt);
+
+ redisUtils.hmset(AppContants.DICTIONARY_TYPE_FISH, map);
+ }
+ }
+
+ // 初始化大炮数据到redis缓存
+ List<CannonSetting> settings = cannonSettingDao.selectByMap(null);
+ if (CollUtil.isNotEmpty(settings)) {
+ Map<String, Object> map = new HashMap<>();
+ for (CannonSetting setting : settings) {
+ map.put(setting.getCode(), setting.getGoldConsume());
+
+ redisUtils.hmset(AppContants.CANNON_TYPE, map);
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/common/system/dao/DataDictionaryCustomDao.java b/src/main/java/com/xcong/excoin/common/system/dao/DataDictionaryCustomDao.java
new file mode 100644
index 0000000..c30bec4
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/common/system/dao/DataDictionaryCustomDao.java
@@ -0,0 +1,14 @@
+package com.xcong.excoin.common.system.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.xcong.excoin.common.system.entity.DataDictionaryCustom;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+public interface DataDictionaryCustomDao extends BaseMapper<DataDictionaryCustom> {
+
+ List<DataDictionaryCustom> selectDicByType(String type);
+
+ DataDictionaryCustom selectDicDataByTypeAndCode(@Param("type") String type, @Param("code") String code);
+}
diff --git a/src/main/java/com/xcong/excoin/common/system/entity/DataDictionaryCustom.java b/src/main/java/com/xcong/excoin/common/system/entity/DataDictionaryCustom.java
new file mode 100644
index 0000000..a7f7c6f
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/common/system/entity/DataDictionaryCustom.java
@@ -0,0 +1,22 @@
+package com.xcong.excoin.common.system.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.xcong.excoin.common.system.base.BaseEntity;
+import lombok.Data;
+
+/**
+ * @author wzy
+ * @date 2021-09-25
+ **/
+@Data
+@TableName("data_dictionary_custom")
+public class DataDictionaryCustom extends BaseEntity {
+
+ private String type;
+
+ private String code;
+
+ private String value;
+
+ private String description;
+}
diff --git a/src/main/java/com/xcong/excoin/configurations/RabbitMqConfig.java b/src/main/java/com/xcong/excoin/configurations/RabbitMqConfig.java
index 3cddbe2..ab4d61b 100644
--- a/src/main/java/com/xcong/excoin/configurations/RabbitMqConfig.java
+++ b/src/main/java/com/xcong/excoin/configurations/RabbitMqConfig.java
@@ -43,6 +43,12 @@
public static final String ROUTING_KEY_USDT_ADDRESS = "routing_key_usdt_address";
+ public static final String EXCHANGE_FISH_HIT = "EXCHANGE_FISH_HIT";
+
+ public static final String QUEUE_FISH_HIT = "QUEUE_FISH_HIT";
+
+ public static final String ROUTING_KEY_FISH_HIT = "ROUTING_KEY_FISH_HIT";
+
/**
* 撮合交易
*/
@@ -232,6 +238,22 @@
}
@Bean
+ public DirectExchange fishHitExchange() {
+ return new DirectExchange(EXCHANGE_FISH_HIT);
+ }
+
+
+ @Bean
+ public Queue fishHitQueue() {
+ return new Queue(QUEUE_FISH_HIT, true);
+ }
+
+ @Bean
+ public Binding fishHitbinding() {
+ return BindingBuilder.bind(fishHitQueue()).to(fishHitExchange()).with(ROUTING_KEY_FISH_HIT);
+ }
+
+ @Bean
public DirectExchange usdtAddressExchange() {
return new DirectExchange(EXCHANGE_USDT_ADDRESS);
}
diff --git a/src/main/java/com/xcong/excoin/configurations/WebSocketConfig.java b/src/main/java/com/xcong/excoin/configurations/WebSocketConfig.java
index 51711c3..3ba5508 100644
--- a/src/main/java/com/xcong/excoin/configurations/WebSocketConfig.java
+++ b/src/main/java/com/xcong/excoin/configurations/WebSocketConfig.java
@@ -1,11 +1,26 @@
package com.xcong.excoin.configurations;
+import com.xcong.excoin.websocket.handler.FishHitWebSocketHandler;
+import com.xcong.excoin.websocket.handler.FishHitWebSocketHandshakeInterceptor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.stereotype.Component;
+import org.springframework.web.socket.config.annotation.EnableWebSocket;
+import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
+import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
-//@Configuration
-public class WebSocketConfig {
+@Slf4j
+@Configuration
+public class WebSocketConfig implements WebSocketConfigurer {
+
+ @Autowired
+ private FishHitWebSocketHandler fishHitWebSocketHandler;
+ @Autowired
+ private FishHitWebSocketHandshakeInterceptor fishHitWebSocketHandshakeInterceptor;
+
/**
* 注入一个ServerEndpointExporter,该Bean会自动注册使用@ServerEndpoint注解申明的websocket endpoint
*/
@@ -13,4 +28,11 @@
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
+
+ @Override
+ public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
+ registry.addHandler(fishHitWebSocketHandler, "websocket/fish/hit")
+ .setAllowedOrigins("*")
+ .addInterceptors(fishHitWebSocketHandshakeInterceptor);
+ }
}
diff --git a/src/main/java/com/xcong/excoin/configurations/interceptor/WebCommonInterceptor.java b/src/main/java/com/xcong/excoin/configurations/interceptor/WebCommonInterceptor.java
new file mode 100644
index 0000000..b636002
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/configurations/interceptor/WebCommonInterceptor.java
@@ -0,0 +1,34 @@
+package com.xcong.excoin.configurations.interceptor;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.HandlerInterceptor;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@Slf4j
+@Component
+public class WebCommonInterceptor implements HandlerInterceptor {
+
+
+ private String getUrl(HttpServletRequest request) {
+ return request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getRequestURI();
+ }
+
+ @Override
+ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+ log.info("#Begin Request# - [{}]", getUrl(request));
+ return true;
+ }
+
+ @Override
+ public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
+ }
+
+ @Override
+ public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
+ log.info("#End Request# - [{}]", getUrl(request));
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/configurations/security/WebSecurityConfig.java b/src/main/java/com/xcong/excoin/configurations/security/WebSecurityConfig.java
index 004f851..751ca5b 100644
--- a/src/main/java/com/xcong/excoin/configurations/security/WebSecurityConfig.java
+++ b/src/main/java/com/xcong/excoin/configurations/security/WebSecurityConfig.java
@@ -56,6 +56,7 @@
.antMatchers("/api/orderCoin/deal/list").permitAll()
.antMatchers("/api/helpCenter/**").permitAll()
.antMatchers("/trade/**").permitAll()
+ .antMatchers("/websocket/**").permitAll()
.anyRequest().authenticated()
.and().apply(securityConfiguereAdapter());
}
diff --git a/src/main/java/com/xcong/excoin/modules/fish/controller/MemberCannonController.java b/src/main/java/com/xcong/excoin/modules/fish/controller/MemberCannonController.java
index a19ba8c..63fcbd0 100644
--- a/src/main/java/com/xcong/excoin/modules/fish/controller/MemberCannonController.java
+++ b/src/main/java/com/xcong/excoin/modules/fish/controller/MemberCannonController.java
@@ -54,7 +54,6 @@
@ApiOperation(value = "代币金币互转")
@PostMapping(value = "/coinGoldExchange")
public Result coinGoldExchange(@RequestBody @Valid CoinGoldExchangeDto coinGoldExchangeDto) {
- log.info("请求coinGoldExchange方法");
return memberCannonService.coinGoldExchange(coinGoldExchangeDto);
}
diff --git a/src/main/java/com/xcong/excoin/modules/fish/dao/MemberAccountGoldDao.java b/src/main/java/com/xcong/excoin/modules/fish/dao/MemberAccountGoldDao.java
index 5bc26ca..46a7e51 100644
--- a/src/main/java/com/xcong/excoin/modules/fish/dao/MemberAccountGoldDao.java
+++ b/src/main/java/com/xcong/excoin/modules/fish/dao/MemberAccountGoldDao.java
@@ -14,4 +14,6 @@
int updateTotalBalanceAndAvailableBalance(@Param("id") Long id, @Param("availableBalance") BigDecimal availableBalance, @Param("totalBalance") BigDecimal totalBalance, @Param("frozenBalance") BigDecimal frozenBalance);
GoldAccountVo selectAccountGoldVoByMemberId(Long memberId);
+
+ MemberAccountGold selectByMemberIdForLock(@Param("memberId") Long memberId);
}
diff --git a/src/main/java/com/xcong/excoin/modules/fish/vo/OwnCannonVo.java b/src/main/java/com/xcong/excoin/modules/fish/vo/OwnCannonVo.java
index c4889c2..bea558f 100644
--- a/src/main/java/com/xcong/excoin/modules/fish/vo/OwnCannonVo.java
+++ b/src/main/java/com/xcong/excoin/modules/fish/vo/OwnCannonVo.java
@@ -10,21 +10,21 @@
public class OwnCannonVo {
private Long id;
- private Long memberId;
@ApiModelProperty(value = "炮台图片")//炮台图片
private String cannonImg;
@ApiModelProperty(value = "炮弹图片")//炮弹图片
private String bulletImg;
- @ApiModelProperty(value = "炮台UUID")//炮台UUID
- private String cannonUuid;
@ApiModelProperty(value = "炮台名称")//炮台名称
- private String cannonName;
+ private String name;
@ApiModelProperty(value = "炮台编码")//炮台编码
- private String cannonCode;
+ private String code;
@ApiModelProperty(value = "炮台兑换价格")//炮台兑换价格
- private BigDecimal cannonPrice;
+ private BigDecimal exchangePrice;
@ApiModelProperty(value = "每发炮弹消耗金币数")//消耗金币
private BigDecimal goldConsume;
@ApiModelProperty(value = "1:主动购买 2:系统赠送")//1:主动购买 2:系统赠送
private Integer type;
+
+ @ApiModelProperty(value = "是否拥有 1-是 2-否")
+ private int isHas;
}
diff --git a/src/main/java/com/xcong/excoin/rabbit/consumer/FishHitConsumer.java b/src/main/java/com/xcong/excoin/rabbit/consumer/FishHitConsumer.java
new file mode 100644
index 0000000..2bab670
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/rabbit/consumer/FishHitConsumer.java
@@ -0,0 +1,46 @@
+package com.xcong.excoin.rabbit.consumer;
+
+import com.alibaba.fastjson.JSONObject;
+import com.xcong.excoin.configurations.RabbitMqConfig;
+import com.xcong.excoin.modules.fish.dao.MemberAccountGoldDao;
+import com.xcong.excoin.modules.fish.entity.MemberAccountGold;
+import com.xcong.excoin.websocket.fish.model.MsgModel;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.stereotype.Component;
+
+import java.math.BigDecimal;
+
+/**
+ * @author wzy
+ * @date 2021-11-26
+ **/
+@Slf4j
+@Component
+@ConditionalOnProperty(prefix = "app", name = "fish-hit", havingValue = "true")
+public class FishHitConsumer {
+
+ @Autowired
+ private MemberAccountGoldDao memberAccountGoldDao;
+
+ @RabbitListener(queues = RabbitMqConfig.QUEUE_FISH_HIT)
+ public void fishHit(String content) {
+ log.info("收到打渔消息:{}", content);
+ MsgModel msg = JSONObject.parseObject(content, MsgModel.class);
+
+ synchronized (this) {
+ MemberAccountGold accountGold = memberAccountGoldDao.selectByMemberIdForLock(msg.getMemberId());
+ BigDecimal available = accountGold.getAvailableBalance();
+
+ BigDecimal gold = BigDecimal.valueOf(msg.getObtain()).subtract(msg.getConsume());
+
+ if (gold.compareTo(BigDecimal.ZERO) < 0 && gold.abs().compareTo(available) > 0) {
+ log.info("余额不足");
+ return;
+ }
+ memberAccountGoldDao.updateTotalBalanceAndAvailableBalance(accountGold.getId(), gold, gold, BigDecimal.ZERO);
+ }
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/rabbit/producer/FishHitProducer.java b/src/main/java/com/xcong/excoin/rabbit/producer/FishHitProducer.java
new file mode 100644
index 0000000..2f44d43
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/rabbit/producer/FishHitProducer.java
@@ -0,0 +1,37 @@
+package com.xcong.excoin.rabbit.producer;
+
+import cn.hutool.core.util.IdUtil;
+import com.xcong.excoin.configurations.RabbitMqConfig;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.amqp.rabbit.connection.CorrelationData;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author wzy
+ * @date 2021-11-26
+ **/
+@Slf4j
+@Component
+public class FishHitProducer implements RabbitTemplate.ConfirmCallback {
+
+ private RabbitTemplate rabbitTemplate;
+
+ @Autowired
+ public FishHitProducer(RabbitTemplate rabbitTemplate) {
+ this.rabbitTemplate = rabbitTemplate;
+ rabbitTemplate.setConfirmCallback(this);
+ }
+
+ public void sendFishHitMsg(String content) {
+ log.info("打渔发送消息:{}", content);
+ CorrelationData correlationData = new CorrelationData(IdUtil.simpleUUID());
+ rabbitTemplate.convertAndSend(RabbitMqConfig.EXCHANGE_FISH_HIT, RabbitMqConfig.ROUTING_KEY_FISH_HIT, content, correlationData);
+ }
+
+ @Override
+ public void confirm(CorrelationData correlationData, boolean ack, String cause) {
+
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/websocket/fish/HitFishWebSocket.java b/src/main/java/com/xcong/excoin/websocket/fish/HitFishWebSocket.java
new file mode 100644
index 0000000..f0d7342
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/websocket/fish/HitFishWebSocket.java
@@ -0,0 +1,119 @@
+package com.xcong.excoin.websocket.fish;
+
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.xcong.excoin.common.contants.AppContants;
+import com.xcong.excoin.modules.member.dao.MemberDao;
+import com.xcong.excoin.rabbit.producer.FishHitProducer;
+import com.xcong.excoin.utils.RedisUtils;
+import com.xcong.excoin.websocket.fish.model.MsgModel;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.websocket.*;
+import javax.websocket.server.ServerEndpoint;
+import java.math.BigDecimal;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * @author wzy
+ * @date 2021-11-26
+ **/
+@Slf4j
+@Component
+//@ServerEndpoint(value = "/websocket/fish/hit")
+public class HitFishWebSocket {
+
+ @Autowired
+ private RedisUtils redisUtils;
+ @Autowired
+ private FishHitProducer fishHitProducer;
+
+ private final Map<Long, Session> MEMBER_SESSIONS = new ConcurrentHashMap<>();
+ private final Map<String, Long> SID_MID = new ConcurrentHashMap<>();
+
+ @OnOpen
+ public void onOpen(Session session) {
+ }
+
+ @OnClose
+ public void onClose(Session session) {}
+
+ /**
+ *
+ * @param message { type : "hit", fortId : 1, fishType : "fish1" }
+ *
+ * @param session
+ */
+ @OnMessage
+ public void onMessage(String message, Session session) {
+ JSONObject reqParam = JSONObject.parseObject(message);
+ if (!reqParam.containsKey("hit") && !reqParam.containsKey("login")) {
+ session.getAsyncRemote().sendText("{code:-1}");
+ return;
+ }
+
+ // 登录逻辑
+ if (reqParam.containsKey("login")) {
+ String token = reqParam.getString("token");
+ if (StrUtil.isBlank(token)) {
+ session.getAsyncRemote().sendText("{ code:-1, msg: \"token error\" }");
+ return;
+ }
+
+ String redisStr = AppContants.APP_LOGIN_PREFIX + token;
+ String memberStr = redisUtils.getString(redisStr);
+ if (StrUtil.isBlank(memberStr)) {
+ session.getAsyncRemote().sendText("{ code:-1, msg: \"Unauthorized\"}");
+ return;
+ }
+
+ JSONObject memberObject = JSONObject.parseObject(memberStr);
+ Long memberId = memberObject.getLong("memberId");
+ MEMBER_SESSIONS.put(memberId, session);
+ SID_MID.put(session.getId(), memberId);
+ session.getAsyncRemote().sendText("{ code:0, msg: \"login succes\" }");
+ return;
+ }
+
+ // 打中鱼奖励金币
+ int fishGold = 0;
+ String fishType = reqParam.getString("fishType");
+
+ // 如果请求参数中包含鱼类型,且类型不为空,则说明打中
+ if (reqParam.containsKey("fishType") && StrUtil.isNotBlank(fishType)) {
+ Object fishTypeObj = redisUtils.hget(AppContants.DICTIONARY_TYPE_FISH, fishType);
+ if (fishTypeObj == null) {
+ session.getAsyncRemote().sendText("{code : -1, msg : \"fish error\"}");
+ return;
+ }
+
+ fishGold = (int) fishTypeObj;
+ }
+
+ String fortId = reqParam.getString("fortId");
+ if (!reqParam.containsKey("fortId") || fortId == null) {
+ return;
+ }
+
+ Object fortObj = redisUtils.hget(AppContants.CANNON_TYPE, fortId);
+ if (fortObj == null) {
+ session.getAsyncRemote().sendText("{code : -1, msg : \"fort error\"}");
+ return;
+ }
+
+ // 消耗金币
+ BigDecimal consume = (BigDecimal) fortObj;
+
+ MsgModel msg = new MsgModel(consume, fishGold, SID_MID.get(session.getId()));
+ // 发送打渔消息
+ fishHitProducer.sendFishHitMsg(JSONObject.toJSONString(msg));
+ }
+
+ @OnError
+ public void onError(Session session, Throwable error) {
+ log.error("捕鱼异常", error);
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/websocket/fish/model/MsgModel.java b/src/main/java/com/xcong/excoin/websocket/fish/model/MsgModel.java
new file mode 100644
index 0000000..7282176
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/websocket/fish/model/MsgModel.java
@@ -0,0 +1,34 @@
+package com.xcong.excoin.websocket.fish.model;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * @author wzy
+ * @date 2021-11-26
+ **/
+@Data
+public class MsgModel {
+
+ /**
+ * 消耗金币
+ */
+ private BigDecimal consume;
+
+ /**
+ * 获得金币
+ */
+ private int obtain;
+
+ /**
+ * 用户ID
+ */
+ private Long memberId;
+
+ public MsgModel(BigDecimal consume, int obtain, Long memberId) {
+ this.consume = consume;
+ this.obtain = obtain;
+ this.memberId = memberId;
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/websocket/handler/FishHitWebSocketHandler.java b/src/main/java/com/xcong/excoin/websocket/handler/FishHitWebSocketHandler.java
new file mode 100644
index 0000000..767cc63
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/websocket/handler/FishHitWebSocketHandler.java
@@ -0,0 +1,118 @@
+package com.xcong.excoin.websocket.handler;
+
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.xcong.excoin.common.contants.AppContants;
+import com.xcong.excoin.netty.handler.WebSocketServerHandler;
+import com.xcong.excoin.rabbit.producer.FishHitProducer;
+import com.xcong.excoin.utils.RedisUtils;
+import com.xcong.excoin.websocket.fish.model.MsgModel;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.web.socket.*;
+import org.springframework.web.socket.handler.TextWebSocketHandler;
+
+import javax.websocket.Session;
+import java.math.BigDecimal;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * @author wzy
+ * @date 2021-11-26
+ **/
+@Slf4j
+@Component
+public class FishHitWebSocketHandler extends TextWebSocketHandler {
+
+ @Autowired
+ private RedisUtils redisUtils;
+ @Autowired
+ private FishHitProducer fishHitProducer;
+
+ private final Map<Long, WebSocketSession> MEMBER_SESSIONS = new ConcurrentHashMap<>();
+ private final Map<String, Long> SID_MID = new ConcurrentHashMap<>();
+
+
+ @Override
+ public void afterConnectionEstablished(WebSocketSession session) throws Exception {
+ Object token = session.getAttributes().get("token");
+ if (token != null) {
+ String redisStr = AppContants.APP_LOGIN_PREFIX + token;
+ String memberStr = redisUtils.getString(redisStr);
+ if (StrUtil.isBlank(memberStr)) {
+ session.sendMessage(new TextMessage("{ code:-1, msg: \"Unauthorized\"}"));
+ return;
+ }
+
+ JSONObject memberObject = JSONObject.parseObject(memberStr);
+ Long memberId = memberObject.getLong("id");
+ MEMBER_SESSIONS.put(memberId, session);
+ SID_MID.put(session.getId(), memberId);
+ session.sendMessage(new TextMessage("{ code:0, msg: \"login succes\" }"));
+ }
+ }
+
+ /**
+ *
+ * @param content { type : "hit", fortId : 1, fishType : "fish1" }
+ * @param session
+ */
+ @Override
+ public void handleTextMessage(WebSocketSession session, TextMessage content) throws Exception {
+ String message = content.getPayload();
+
+ JSONObject reqParam = JSONObject.parseObject(message);
+ String type = reqParam.getString("type");
+ if (!("hit").equals(type)) {
+ session.sendMessage(new TextMessage("{code:-1}"));
+ return;
+ }
+
+ // 打中鱼奖励金币
+ int fishGold = 0;
+ String fishType = reqParam.getString("fishType");
+
+ // 如果请求参数中包含鱼类型,且类型不为空,则说明打中
+ if (reqParam.containsKey("fishType") && StrUtil.isNotBlank(fishType)) {
+ Object fishTypeObj = redisUtils.hget(AppContants.DICTIONARY_TYPE_FISH, fishType);
+ if (fishTypeObj == null) {
+ session.sendMessage(new TextMessage("{code : -1, msg : \"fish error\"}"));
+ return;
+ }
+
+ fishGold = (int) fishTypeObj;
+ }
+
+ String fortId = reqParam.getString("fortId");
+ if (!reqParam.containsKey("fortId") || fortId == null) {
+ return;
+ }
+
+ Object fortObj = redisUtils.hget(AppContants.CANNON_TYPE, fortId);
+ if (fortObj == null) {
+ session.sendMessage(new TextMessage("{code : -1, msg : \"fort error\"}"));
+ return;
+ }
+
+ // 消耗金币
+ BigDecimal consume = (BigDecimal) fortObj;
+
+ MsgModel msg = new MsgModel(consume, fishGold, SID_MID.get(session.getId()));
+ // 发送打渔消息
+ fishHitProducer.sendFishHitMsg(JSONObject.toJSONString(msg));
+ }
+
+ @Override
+ public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
+ }
+
+ @Override
+ public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
+ Long memberId = SID_MID.get(session.getId());
+
+ SID_MID.remove(session.getId());
+ MEMBER_SESSIONS.remove(memberId);
+ }
+}
diff --git a/src/main/java/com/xcong/excoin/websocket/handler/FishHitWebSocketHandshakeInterceptor.java b/src/main/java/com/xcong/excoin/websocket/handler/FishHitWebSocketHandshakeInterceptor.java
new file mode 100644
index 0000000..faeddc8
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/websocket/handler/FishHitWebSocketHandshakeInterceptor.java
@@ -0,0 +1,41 @@
+package com.xcong.excoin.websocket.handler;
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.HttpUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.server.ServerHttpRequest;
+import org.springframework.http.server.ServerHttpResponse;
+import org.springframework.stereotype.Component;
+import org.springframework.web.socket.WebSocketHandler;
+import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
+
+import java.nio.charset.Charset;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author wzy
+ * @date 2021-11-26
+ **/
+@Slf4j
+@Component
+public class FishHitWebSocketHandshakeInterceptor extends HttpSessionHandshakeInterceptor {
+
+
+ @Override
+ public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
+ String query = request.getURI().getQuery();
+ if (StrUtil.isBlank(query)) {
+ return false;
+ }
+
+ HashMap<String, String> paramMap = (HashMap<String, String>) HttpUtil.decodeParamMap(query, Charset.defaultCharset());
+ String token = paramMap.get("token");
+ if (StrUtil.isBlank(token)) {
+ return false;
+ }
+
+ attributes.put("token", token);
+ return true;
+ }
+}
diff --git a/src/main/resources/application-test.yml b/src/main/resources/application-test.yml
index a7c46c7..df9b63b 100644
--- a/src/main/resources/application-test.yml
+++ b/src/main/resources/application-test.yml
@@ -101,6 +101,7 @@
loop-job: false
rabbit-consumer: false
block-job: true
+ fish-hit: false
aliyun:
oss:
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index 1cb4126..be2fd02 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -48,13 +48,13 @@
## redis配置
redis:
## Redis数据库索引(默认为0)
- database: 0
+ database: 5
## Redis服务器地址
- host: 154.91.195.155
+ host: 120.27.238.55
## Redis服务器连接端口
port: 6379
## Redis服务器连接密码(默认为空)
- password: ann123!@#
+ password: xcong123
jedis:
pool:
## 连接池最大连接数(使用负值表示没有限制)
@@ -101,6 +101,7 @@
loop-job: false
rabbit-consumer: false
block-job: false
+ fish-hit: true
aliyun:
oss:
diff --git a/src/main/resources/mapper/common/DataDictionaryCustomMapper.xml b/src/main/resources/mapper/common/DataDictionaryCustomMapper.xml
new file mode 100644
index 0000000..f19484a
--- /dev/null
+++ b/src/main/resources/mapper/common/DataDictionaryCustomMapper.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.xcong.excoin.common.system.dao.DataDictionaryCustomDao">
+
+ <select id="selectDicByType" resultType="com.xcong.excoin.common.system.entity.DataDictionaryCustom">
+ select * from data_dictionary_custom where type=#{type}
+ </select>
+
+ <select id="selectDicDataByTypeAndCode" resultType="com.xcong.excoin.common.system.entity.DataDictionaryCustom">
+ select * from data_dictionary_custom a
+ where a.type=#{type} and a.code=#{code}
+ </select>
+</mapper>
\ No newline at end of file
diff --git a/src/main/resources/mapper/fish/CannonOwnRecordDao.xml b/src/main/resources/mapper/fish/CannonOwnRecordDao.xml
index b461582..b3a9c32 100644
--- a/src/main/resources/mapper/fish/CannonOwnRecordDao.xml
+++ b/src/main/resources/mapper/fish/CannonOwnRecordDao.xml
@@ -7,10 +7,11 @@
</select>
<select id="selectCannonOwnRecordsByMemberId" resultType="com.xcong.excoin.modules.fish.vo.OwnCannonVo">
- select a.*,b.gold_consume goldConsume,b.cannon_img cannonImg,b.bullet_img bulletImg
- from cannon_own_record a
- left join cannon_setting b on a.cannon_code = b.code
- where a.member_id = #{memberId}
+ select
+ a.*,
+ case when b.id is null then 0 else 1 end isHas
+ from cannon_setting a
+ left join cannon_own_record b on a.code=b.cannon_code and b.member_id=#{memberId}
</select>
<select id="selectCannonOwnRecordsByIdAndMemberId" resultType="com.xcong.excoin.modules.fish.entity.CannonOwnRecord">
diff --git a/src/main/resources/mapper/fish/MemberAccountGoldDao.xml b/src/main/resources/mapper/fish/MemberAccountGoldDao.xml
index e9ceec9..73b4b31 100644
--- a/src/main/resources/mapper/fish/MemberAccountGoldDao.xml
+++ b/src/main/resources/mapper/fish/MemberAccountGoldDao.xml
@@ -32,4 +32,7 @@
select a.* from member_account_gold a where a.member_id = #{memberId}
</select>
+ <select id="selectByMemberIdForLock" resultType="com.xcong.excoin.modules.fish.entity.MemberAccountGold">
+ select a.* from member_account_gold a where a.member_id = #{memberId} for update
+ </select>
</mapper>
\ No newline at end of file
--
Gitblit v1.9.1