From 4a4c5623aac08735944e12fb93947808c87631d0 Mon Sep 17 00:00:00 2001
From: wangw <1594593906@qq.com>
Date: Fri, 21 Jun 2024 09:18:56 +0800
Subject: [PATCH] =?UTF-8?q?client=20=E6=A0=87=E7=AD=BE=E6=89=93=E5=8D=B0?=
=?UTF-8?q?=20=E9=95=BF=E9=93=BE=E6=8E=A5=20=E4=BC=9A=E5=91=98=E7=BB=91?=
=?UTF-8?q?=E5=AE=9A?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pom.xml | 12 ++
.../controller/NotifyController.java | 10 +-
.../cashierservice/dao/TbShopUserMapper.java | 1 +
.../cashierservice/entity/TbCashierCart.java | 9 +
.../netty/ConnectionDebouncerHandler.java | 35 ++++
.../netty/HeartbeatHandler.java | 2 +-
.../netty/PushToAppChannelInitializer.java | 6 +-
.../PushToClientChannelHandlerAdapter.java | 187 ++++++++++++++++++
.../netty/PushToClientChannelInitializer.java | 52 +++++
.../netty/config/NettyConfig.java | 7 +
.../cashierservice/service/LoginService.java | 10 +-
.../cashierservice/service/PayService.java | 58 +++++-
.../cashierservice/util/QrCodeUtils.java | 115 +++++++++++
src/main/resources/application.yml | 1 +
.../resources/mapper/TbShopUserMapper.xml | 9 +
15 files changed, 493 insertions(+), 21 deletions(-)
create mode 100644 src/main/java/com/chaozhanggui/system/cashierservice/netty/ConnectionDebouncerHandler.java
create mode 100644 src/main/java/com/chaozhanggui/system/cashierservice/netty/PushToClientChannelHandlerAdapter.java
create mode 100644 src/main/java/com/chaozhanggui/system/cashierservice/netty/PushToClientChannelInitializer.java
create mode 100644 src/main/java/com/chaozhanggui/system/cashierservice/util/QrCodeUtils.java
diff --git a/pom.xml b/pom.xml
index 660455f..2ea4374 100644
--- a/pom.xml
+++ b/pom.xml
@@ -112,6 +112,18 @@
runtime
+
+
+ com.google.zxing
+ core
+ 3.5.3
+
+
+
+ com.google.zxing
+ javase
+ 3.5.3
+
org.apache.commons
diff --git a/src/main/java/com/chaozhanggui/system/cashierservice/controller/NotifyController.java b/src/main/java/com/chaozhanggui/system/cashierservice/controller/NotifyController.java
index 52970dc..4b33f13 100644
--- a/src/main/java/com/chaozhanggui/system/cashierservice/controller/NotifyController.java
+++ b/src/main/java/com/chaozhanggui/system/cashierservice/controller/NotifyController.java
@@ -9,10 +9,7 @@ import com.chaozhanggui.system.cashierservice.service.PayService;
import com.chaozhanggui.system.cashierservice.util.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.CrossOrigin;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
@@ -69,6 +66,11 @@ public class NotifyController {
}
+ @RequestMapping("test")
+ public void test(@RequestParam String payOrderNO){
+ payService.test(payOrderNO);
+ }
+
@RequestMapping("notifyCallBack")
public String notifyCallBack(HttpServletRequest request){
diff --git a/src/main/java/com/chaozhanggui/system/cashierservice/dao/TbShopUserMapper.java b/src/main/java/com/chaozhanggui/system/cashierservice/dao/TbShopUserMapper.java
index 3c46087..ab3069b 100644
--- a/src/main/java/com/chaozhanggui/system/cashierservice/dao/TbShopUserMapper.java
+++ b/src/main/java/com/chaozhanggui/system/cashierservice/dao/TbShopUserMapper.java
@@ -25,6 +25,7 @@ public interface TbShopUserMapper {
int updateByPrimaryKeySelective(TbShopUser record);
int updateByPrimaryKey(TbShopUser record);
+ int upUserBYId(TbShopUser record);
TbShopUser selectByUserIdAndShopId(@Param("userId") String userId,@Param("shopId") String shopId);
diff --git a/src/main/java/com/chaozhanggui/system/cashierservice/entity/TbCashierCart.java b/src/main/java/com/chaozhanggui/system/cashierservice/entity/TbCashierCart.java
index 4e8ab74..0c99e3a 100644
--- a/src/main/java/com/chaozhanggui/system/cashierservice/entity/TbCashierCart.java
+++ b/src/main/java/com/chaozhanggui/system/cashierservice/entity/TbCashierCart.java
@@ -1,6 +1,7 @@
package com.chaozhanggui.system.cashierservice.entity;
import lombok.Data;
+import org.apache.commons.lang3.StringUtils;
import java.io.Serializable;
import java.math.BigDecimal;
@@ -60,4 +61,12 @@ public class TbCashierCart implements Serializable {
private TbProductSpec tbProductSpec;
private static final long serialVersionUID = 1L;
+
+ public String getSkuName() {
+ if(StringUtils.isNotBlank(skuName)){
+ return skuName;
+ }else {
+ return "";
+ }
+ }
}
\ No newline at end of file
diff --git a/src/main/java/com/chaozhanggui/system/cashierservice/netty/ConnectionDebouncerHandler.java b/src/main/java/com/chaozhanggui/system/cashierservice/netty/ConnectionDebouncerHandler.java
new file mode 100644
index 0000000..1a620da
--- /dev/null
+++ b/src/main/java/com/chaozhanggui/system/cashierservice/netty/ConnectionDebouncerHandler.java
@@ -0,0 +1,35 @@
+package com.chaozhanggui.system.cashierservice.netty;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelDuplexHandler;
+import io.netty.channel.ChannelHandlerContext;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Slf4j
+public class ConnectionDebouncerHandler extends ChannelDuplexHandler {
+ private static final Map lastConnectionTimes = new ConcurrentHashMap<>();
+ private static final long debounceIntervalMillis = 5*1000; // 防抖时间间隔,单位:毫秒
+
+ @Override
+ public void channelActive(ChannelHandlerContext ctx) throws Exception {
+ Channel channel = ctx.channel();
+ long currentTimeMillis = System.currentTimeMillis();
+ Long lastConnectionTime = lastConnectionTimes.get(channel);
+ if (lastConnectionTime == null || (currentTimeMillis - lastConnectionTime) > debounceIntervalMillis) {
+ // 允许新连接
+ lastConnectionTimes.put(channel, currentTimeMillis);
+ super.channelActive(ctx); // 将事件传递给下一个处理器
+ } else {
+
+ channel.close();
+ }
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+ ctx.close();
+ }
+}
diff --git a/src/main/java/com/chaozhanggui/system/cashierservice/netty/HeartbeatHandler.java b/src/main/java/com/chaozhanggui/system/cashierservice/netty/HeartbeatHandler.java
index f163b9b..3d2f1ba 100644
--- a/src/main/java/com/chaozhanggui/system/cashierservice/netty/HeartbeatHandler.java
+++ b/src/main/java/com/chaozhanggui/system/cashierservice/netty/HeartbeatHandler.java
@@ -28,7 +28,7 @@ public class HeartbeatHandler extends ChannelDuplexHandler {
super.userEventTriggered(ctx, evt);
} else if (event.state() == IdleState.WRITER_IDLE) {
// log.info("发送心跳");
- ctx.channel().writeAndFlush(new TextWebSocketFrame("Heartbeat")).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
+ ctx.channel().writeAndFlush(new TextWebSocketFrame("{\"type\":\"heartbeat\"}")).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
// ctx.writeAndFlush(HEARTBEAT_SEQUENCE.duplicate()).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
}
} else {
diff --git a/src/main/java/com/chaozhanggui/system/cashierservice/netty/PushToAppChannelInitializer.java b/src/main/java/com/chaozhanggui/system/cashierservice/netty/PushToAppChannelInitializer.java
index 0da7d2c..74d0c25 100644
--- a/src/main/java/com/chaozhanggui/system/cashierservice/netty/PushToAppChannelInitializer.java
+++ b/src/main/java/com/chaozhanggui/system/cashierservice/netty/PushToAppChannelInitializer.java
@@ -11,14 +11,10 @@ import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
import javax.net.ssl.SSLException;
import java.io.*;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
import java.util.concurrent.TimeUnit;
@Component
@@ -35,6 +31,8 @@ public class PushToAppChannelInitializer extends ChannelInitializer> webSocketMap = new HashMap<>();
+
+ /**
+ * [ctx, shopId:clientId]
+ */
+ private static Map clientIdMap = new ConcurrentHashMap<>();
+
+
+ private String clientId = "";
+ private String shopId = "";
+
+ public PushToClientChannelHandlerAdapter() {
+ }
+
+ public static PushToClientChannelHandlerAdapter getInstance() {
+ return new PushToClientChannelHandlerAdapter();
+ }
+
+ @Override
+ public void channelActive(ChannelHandlerContext ctx) throws Exception {
+ log.info("netty连接client 长连接激活");
+ super.channelActive(ctx);
+ }
+
+ @Override
+ public void channelInactive(ChannelHandlerContext ctx) {
+ log.info("netty连接client 长连接关闭:{}, {}",clientId,shopId);
+ ctx.close();
+ removeCtx(ctx);
+ }
+
+ /**
+ * 移除ctx
+ */
+ private void removeCtx(ChannelHandlerContext ctx) {
+ // shopId:clientId
+ String key = clientIdMap.get(ctx);
+ if (StringUtils.isNotBlank(key)) {
+ String[] split = key.split(":");
+ ConcurrentHashMap tableMap = webSocketMap.get(split[0]);
+ if (tableMap != null && !tableMap.isEmpty() && tableMap.size() > 0) {
+ tableMap.remove(split[1]);
+ if (tableMap.isEmpty() || tableMap.size() == 0) {
+ webSocketMap.remove(split[0]);
+ }
+ }
+ }
+ clientIdMap.remove(ctx);
+ }
+
+ @Override
+ public void channelReadComplete(ChannelHandlerContext ctx) {
+ super.channelReadComplete(ctx);
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
+ super.exceptionCaught(ctx, cause);
+ removeCtx(ctx);
+ }
+
+ @Override
+ public void channelRead(ChannelHandlerContext ctx, String msg) {
+ JSONObject jsonObject = new JSONObject();
+ if (StringUtils.isNotEmpty(msg)) {
+ jsonObject = JSONObject.parseObject(msg);
+ }else {
+ log.info("netty连接client 接收到空数据:{}",msg);
+ }
+ String type = jsonObject.getString("type");
+ if(type.equals("heartbeat")){//心跳
+ log.info("netty连接client 接收到心跳数据:shop:{} clientId:{} meg:{}",shopId,clientId,msg);
+ }else {
+ if (type.equals("connect")) {
+ String clientId = jsonObject.getString("clientId");
+ String shopId = jsonObject.getString("shopId");
+ if (StringUtils.isBlank(type) || StringUtils.isBlank(shopId) || StringUtils.isBlank(clientId)) {
+ log.info("netty连接client 建立连接请求失败:{}",jsonObject);
+ channelInactive(ctx);
+ return;
+ }
+
+ log.info("netty连接client 接收到数据 建立连接参数 param:{}",jsonObject);
+ this.clientId=clientId;
+ this.shopId=shopId;
+ if (webSocketMap.containsKey(shopId)) {
+ ConcurrentHashMap clientSocketMap = webSocketMap.get(shopId);
+ clientSocketMap.put(clientId, ctx);
+ } else {
+ ConcurrentHashMap clientSocketMap = new ConcurrentHashMap<>();
+ clientSocketMap.put(clientId, ctx);
+ webSocketMap.put(shopId,clientSocketMap);
+ }
+ clientIdMap.put(ctx, shopId + ":" + clientId);
+ JSONObject jsonObject1 = new JSONObject();
+ jsonObject1.put("status", "success");
+ jsonObject1.put("msg", "连接成功");
+ jsonObject1.put("type", "connect");
+ sendMesToApp(jsonObject1.toString(), ctx);
+ }
+ }
+ //业务逻辑代码处理框架。。。
+ ctx.flush();
+ }
+
+ public void sendMesToApp(String str, ChannelHandlerContext ctx) {
+ sendMessage(ctx, str);
+ }
+
+ /**
+ * @param message 发送的消息内容
+ * @param shopId 店铺Id
+ * @param clientId 客户端Id
+ * @param userFlag
+ * 为true 单发给clientId
+ * 为false 群发 shopId为空 发给所有人
+ */
+ @Async
+ public void AppSendInfo(String message, String shopId,String clientId, boolean userFlag) {
+ log.info("netty连接client 发送消息 shopId:{} clientId:{} userFlag:{} message:{}",shopId,clientId,userFlag, JSONUtil.toJSONString(message));
+ if (userFlag) {
+ if (webSocketMap.containsKey(shopId)) {
+ ConcurrentHashMap webSockets = webSocketMap.get(shopId);
+ if(!webSockets.isEmpty()){
+ if (StringUtils.isNotBlank(clientId)) {
+ ChannelHandlerContext ctx = webSockets.get(clientId);
+ if (ctx != null) {
+ sendMesToApp(message,ctx);
+ }
+ }
+ }
+ }
+ } else {
+ if (StringUtils.isEmpty(shopId)) {
+ // 向所有用户发送信息
+ for (ConcurrentHashMap value : webSocketMap.values()) {
+ for (ChannelHandlerContext ctx : value.values()) {
+ sendMesToApp(message,ctx);
+ }
+ }
+ } else if (webSocketMap.containsKey(shopId)) {
+ ConcurrentHashMap webSockets = webSocketMap.get(shopId);
+ if(!webSockets.isEmpty()) {
+ for (String user : webSockets.keySet()) {
+ ChannelHandlerContext ctx = webSockets.get(user);
+ if (ctx != null) {
+ log.info("netty连接client 发送消息 桌码群发 clientId:{}",user);
+ sendMesToApp(message,ctx);
+ }else {
+ log.info("netty连接client 发送消息 桌码群发 clientId:{} 失败",user);
+ }
+ }
+ }else {
+ log.info("netty连接client 发送消息 桌码群发 clientId:{} 失败",clientId);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/chaozhanggui/system/cashierservice/netty/PushToClientChannelInitializer.java b/src/main/java/com/chaozhanggui/system/cashierservice/netty/PushToClientChannelInitializer.java
new file mode 100644
index 0000000..fd2b305
--- /dev/null
+++ b/src/main/java/com/chaozhanggui/system/cashierservice/netty/PushToClientChannelInitializer.java
@@ -0,0 +1,52 @@
+package com.chaozhanggui.system.cashierservice.netty;
+
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.HttpServerCodec;
+import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
+import io.netty.handler.ssl.SslContext;
+import io.netty.handler.ssl.SslContextBuilder;
+import io.netty.handler.stream.ChunkedWriteHandler;
+import io.netty.handler.timeout.IdleStateHandler;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import javax.net.ssl.SSLException;
+import java.io.InputStream;
+import java.util.concurrent.TimeUnit;
+
+@Component
+@Slf4j
+public class PushToClientChannelInitializer extends ChannelInitializer {
+
+
+
+ @Override
+ protected void initChannel(NioSocketChannel ch) throws SSLException {
+ ChannelPipeline pipeline = ch.pipeline();
+
+ // 添加心跳处理器 多久没收到消息 断开 心跳时间(秒) 读写空闲时间(秒)
+ pipeline.addLast(new IdleStateHandler(30, 10, 120, TimeUnit.SECONDS));
+ pipeline.addLast(new HeartbeatHandler());
+ // 添加连接防抖处理器(没用)
+// pipeline.addLast(new ConnectionDebouncerHandler());
+ //本地试调时使用 wss
+// SslContext sslContext = SslContextBuilder.forServer(loadResourceAsByteArrayInputStream("\\pem\\fullchain.pem"), loadResourceAsByteArrayInputStream("\\pem\\privkey.key")).build();
+// pipeline.addLast(sslContext.newHandler(ch.alloc()));
+
+ // 添加HttpServerCodec用于处理HTTP编解码
+ pipeline.addLast(new HttpServerCodec());
+ pipeline.addLast(new ChunkedWriteHandler());
+ pipeline.addLast(new HttpObjectAggregator(65536));
+ pipeline.addLast(new WebSocketServerProtocolHandler("/client"));
+ ch.pipeline().addLast(new PushToClientChannelHandlerAdapter());
+ }
+
+
+ public static InputStream loadResourceAsByteArrayInputStream(String path) {
+ InputStream inputStream = PushToClientChannelInitializer.class.getClassLoader().getResourceAsStream(path);
+ return inputStream;
+ }
+}
diff --git a/src/main/java/com/chaozhanggui/system/cashierservice/netty/config/NettyConfig.java b/src/main/java/com/chaozhanggui/system/cashierservice/netty/config/NettyConfig.java
index 07793ec..8ded4f7 100644
--- a/src/main/java/com/chaozhanggui/system/cashierservice/netty/config/NettyConfig.java
+++ b/src/main/java/com/chaozhanggui/system/cashierservice/netty/config/NettyConfig.java
@@ -1,6 +1,7 @@
package com.chaozhanggui.system.cashierservice.netty.config;
import com.chaozhanggui.system.cashierservice.netty.PushToAppChannelInitializer;
+import com.chaozhanggui.system.cashierservice.netty.PushToClientChannelInitializer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@@ -18,6 +19,9 @@ public class NettyConfig {
@Value("${netty.server.port}")
private int port;
+ @Value("${netty.server.client-port}")
+ private int clientPort;
+
/**
* 接收者的线程数
*/
@@ -31,8 +35,11 @@ public class NettyConfig {
@Resource
private PushToAppChannelInitializer pushToAppChannelInitializer;
+ @Resource
+ private PushToClientChannelInitializer pushToClientChannelInitializer;
@PostConstruct
public void startCameraNetty() {
NettyUtils.getInstance().initNetty(port, parentGroupThreads, childGroupThreads, pushToAppChannelInitializer);
+ NettyUtils.getInstance().initNetty(clientPort, parentGroupThreads, childGroupThreads, pushToClientChannelInitializer);
}
}
diff --git a/src/main/java/com/chaozhanggui/system/cashierservice/service/LoginService.java b/src/main/java/com/chaozhanggui/system/cashierservice/service/LoginService.java
index 937bf18..db6db01 100644
--- a/src/main/java/com/chaozhanggui/system/cashierservice/service/LoginService.java
+++ b/src/main/java/com/chaozhanggui/system/cashierservice/service/LoginService.java
@@ -116,9 +116,15 @@ public class LoginService {
tbUserInfoMapper.updateByPrimaryKeySelective(userInfo);
List tbShopUsers = tbShopUserMapper.selectAllByUserId(userInfo.getId().toString());
for (TbShopUser tbShopUser : tbShopUsers) {
- tbShopUser.setTelephone(phone);
+ tbShopUser.setUserId("");
tbShopUser.setUpdatedAt(System.currentTimeMillis());
- tbShopUserMapper.updateByPrimaryKey(tbShopUser);
+ tbShopUserMapper.upUserBYId(tbShopUser);
+ }
+ List tbShopUsers1 = tbShopUserMapper.selectByPhone(telephone);
+ for (TbShopUser tbShopUser : tbShopUsers1) {
+ tbShopUser.setUpdatedAt(System.currentTimeMillis());
+ tbShopUser.setUserId(userInfo.getId().toString());
+ tbShopUserMapper.upUserBYId(tbShopUser);
}
}
}
diff --git a/src/main/java/com/chaozhanggui/system/cashierservice/service/PayService.java b/src/main/java/com/chaozhanggui/system/cashierservice/service/PayService.java
index 6e4815a..567afdb 100644
--- a/src/main/java/com/chaozhanggui/system/cashierservice/service/PayService.java
+++ b/src/main/java/com/chaozhanggui/system/cashierservice/service/PayService.java
@@ -11,6 +11,7 @@ import com.chaozhanggui.system.cashierservice.entity.vo.ShopUserListVo;
import com.chaozhanggui.system.cashierservice.exception.MsgException;
import com.chaozhanggui.system.cashierservice.model.PayReq;
import com.chaozhanggui.system.cashierservice.model.TradeQueryReq;
+import com.chaozhanggui.system.cashierservice.netty.PushToClientChannelHandlerAdapter;
import com.chaozhanggui.system.cashierservice.rabbit.RabbitProducer;
import com.chaozhanggui.system.cashierservice.redis.RedisCst;
import com.chaozhanggui.system.cashierservice.redis.RedisUtil;
@@ -148,6 +149,9 @@ public class PayService {
if(!"unpaid".equals(orderInfo.getStatus())&&!"paying".equals(orderInfo.getStatus())){
return Result.fail("订单状态异常,不允许支付");
}
+ if (System.currentTimeMillis() - orderInfo.getCreatedAt() > 60 * 15 * 1000) {
+ return Result.fail("订单十五分钟内有效,当前已超时,请重新下单。");
+ }
if(ObjectUtil.isNull(orderInfo.getMerchantId())||ObjectUtil.isEmpty(orderInfo.getMerchantId())){
return Result.fail("没有对应的商户");
@@ -304,6 +308,9 @@ public class PayService {
if (ObjectUtil.isEmpty(orderInfo)) {
return Result.fail("订单信息不存在");
}
+ if (System.currentTimeMillis() - orderInfo.getCreatedAt() > 60 * 15 * 1000) {
+ return Result.fail("订单十五分钟内有效,当前已超时,请重新下单。");
+ }
TbUserInfo userInfo= tbUserInfoMapper.selectByPrimaryKey(Integer.valueOf(orderInfo.getUserId()));
@@ -321,7 +328,7 @@ public class PayService {
if (!"unpaid".equals(orderInfo.getStatus()) && !"paying".equals(orderInfo.getStatus()) ) {
- return Result.fail("订单出状态异常");
+ return Result.fail("订单状态异常");
}
@@ -384,7 +391,7 @@ public class PayService {
producer.putOrderCollect(jsonObject.toJSONString());
producer.printMechine(orderId);
-
+ sendOrderToClient(orderInfo);
return Result.success(CodeEnum.SUCCESS,"1");
}
@@ -717,7 +724,8 @@ public class PayService {
log.info("发送打印数据");
producer.printMechine(orderInfo.getId() + "");
-
+ sendOrderToClient(orderInfo);
+ redisUtil.deleteByKey(RedisCst.ORDER_EXPIRED.concat(orderInfo.getId().toString()));
return Result.success(CodeEnum.SUCCESS,orderId);
case "REFUND_ING":
cartStatus="refunding";
@@ -751,11 +759,6 @@ public class PayService {
}
-// if("0".equals(userInfo.getIsPwd())){
-// return Result.fail("用户支付密码未设置");
-// }
-
-
TbShopInfo shopInfo= tbShopInfoMapper.selectByPrimaryKey(Integer.valueOf(shopId));
if(ObjectUtil.isEmpty(shopInfo)){
return Result.fail("对应的店铺信息不存在");
@@ -872,7 +875,8 @@ public class PayService {
log.info("发送打印数据");
producer.printMechine(orderInfo.getId() + "");
-
+ sendOrderToClient(orderInfo);
+ redisUtil.deleteByKey(RedisCst.ORDER_EXPIRED.concat(orderInfo.getId().toString()));
return "SUCCESS";
}
@@ -917,6 +921,8 @@ public class PayService {
coupons.put("type","buy");
coupons.put("orderId",orderInfo.getId().toString());
producer.printCoupons(coupons.toJSONString());
+ sendOrderToClient(orderInfo);
+ redisUtil.deleteByKey(RedisCst.ORDER_EXPIRED.concat(orderInfo.getId().toString()));
return "SUCCESS";
}
@@ -979,7 +985,11 @@ public class PayService {
}
-
+ @Transactional(rollbackFor = Exception.class)
+ public void test(String payOrderNO) {
+ TbOrderInfo orderInfo = tbOrderInfoMapper.selectByPayOrderNo(payOrderNO);
+ sendOrderToClient(orderInfo);
+ }
@@ -1170,6 +1180,34 @@ public class PayService {
return "SUCCESS";
}
+ public void sendOrderToClient(TbOrderInfo orderInfo) {
+ List tbCashierCarts = tbCashierCartMapper.selectByOrderId(orderInfo.getId().toString(), null);
+ JSONObject client = new JSONObject();
+ JSONObject order = new JSONObject();
+ order.put("orderNo",orderInfo.getOrderNo());
+ order.put("masterId",StringUtils.isNotBlank(orderInfo.getMasterId())?orderInfo.getMasterId():"");
+ order.put("tableName",StringUtils.isNotBlank(orderInfo.getTableName())?orderInfo.getTableName():"");
+ client.put("carts", tbCashierCarts);
+ client.put("type", "order");
+ client.put("amount", orderInfo.getPayAmount());
+ client.put("remark", StringUtils.isNotBlank(orderInfo.getRemark())?orderInfo.getRemark():"");
+ client.put("orderInfo", order);
+ client.put("createdAt", orderInfo.getCreatedAt());
+ client.put("outNumber", StringUtils.isNotBlank(orderInfo.getOutNumber())?orderInfo.getOutNumber():"");
+// client.put("outNumberCode", "");
+// if(StringUtils.isNotBlank(orderInfo.getOutNumber())){
+// try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
+// QrCodeUtils.createCodeToOutputStream(orderInfo.getOutNumber(), outputStream);
+// String s = Base64Utils.encodeToString(outputStream.toByteArray());
+// client.put("outNumberCode", s);
+// } catch (Exception e) {
+// log.info("生成 失败");
+// e.printStackTrace();
+// }
+// }
+ PushToClientChannelHandlerAdapter.getInstance().AppSendInfo(client.toString(), orderInfo.getShopId(), "", false);
+ }
+
// public Result returnOrder(){
//
diff --git a/src/main/java/com/chaozhanggui/system/cashierservice/util/QrCodeUtils.java b/src/main/java/com/chaozhanggui/system/cashierservice/util/QrCodeUtils.java
new file mode 100644
index 0000000..c88cbda
--- /dev/null
+++ b/src/main/java/com/chaozhanggui/system/cashierservice/util/QrCodeUtils.java
@@ -0,0 +1,115 @@
+package com.chaozhanggui.system.cashierservice.util;
+
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.EncodeHintType;
+import com.google.zxing.MultiFormatWriter;
+import com.google.zxing.WriterException;
+import com.google.zxing.common.BitMatrix;
+import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
+import org.apache.commons.lang3.StringUtils;
+
+import javax.imageio.ImageIO;
+import javax.swing.filechooser.FileSystemView;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.OutputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 二维码工具类
+ *
+ * @author GYJ
+ */
+public class QrCodeUtils {
+
+ //CODE_WIDTH:二维码宽度,单位像素
+ private static final int CODE_WIDTH = 400;
+ //CODE_HEIGHT:二维码高度,单位像素
+ private static final int CODE_HEIGHT = 400;
+ //FRONT_COLOR:二维码前景色,0x000000 表示黑色
+ private static final int FRONT_COLOR = 0x000000;
+ //BACKGROUND_COLOR:二维码背景色,0xFFFFFF 表示白色
+ //演示用 16 进制表示,和前端页面 CSS 的取色是一样的,注意前后景颜色应该对比明显,如常见的黑白
+ private static final int BACKGROUND_COLOR = 0xFFFFFF;
+
+ public static void createCodeToFile(String content, File codeImgFileSaveDir, String fileName) {
+ try {
+ if (StringUtils.isBlank(content) || StringUtils.isBlank(fileName)) {
+ return;
+ }
+ content = content.trim();
+ if (codeImgFileSaveDir==null || codeImgFileSaveDir.isFile()) {
+ //二维码图片存在目录为空,默认放在桌面...
+ codeImgFileSaveDir = FileSystemView.getFileSystemView().getHomeDirectory();
+ }
+ if (!codeImgFileSaveDir.exists()) {
+ //二维码图片存在目录不存在,开始创建...
+ codeImgFileSaveDir.mkdirs();
+ }
+
+ //核心代码-生成二维码
+ BufferedImage bufferedImage = getBufferedImage(content);
+
+ File codeImgFile = new File(codeImgFileSaveDir, fileName);
+ ImageIO.write(bufferedImage, "png", codeImgFile);
+
+ System.out.println("二维码图片生成成功:" + codeImgFile.getPath());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 生成二维码并输出到输出流, 通常用于输出到网页上进行显示,输出到网页与输出到磁盘上的文件中,区别在于最后一句 ImageIO.write
+ * write(RenderedImage im,String formatName,File output):写到文件中
+ * write(RenderedImage im,String formatName,OutputStream output):输出到输出流中
+ * @param content :二维码内容
+ * @param outputStream :输出流,比如 HttpServletResponse 的 getOutputStream
+ */
+ public static void createCodeToOutputStream(String content, OutputStream outputStream) {
+ try {
+ if (StringUtils.isBlank(content)) {
+ return;
+ }
+ content = content.trim();
+ //核心代码-生成二维码
+ BufferedImage bufferedImage = getBufferedImage(content);
+
+ //区别就是这一句,输出到输出流中,如果第三个参数是 File,则输出到文件中
+ ImageIO.write(bufferedImage, "png", outputStream);
+
+ System.out.println("二维码图片生成到输出流成功...");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ //核心代码-生成二维码
+ private static BufferedImage getBufferedImage(String content) throws WriterException {
+
+ //com.google.zxing.EncodeHintType:编码提示类型,枚举类型
+ Map hints = new HashMap();
+
+ //EncodeHintType.CHARACTER_SET:设置字符编码类型
+ hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
+
+ //EncodeHintType.ERROR_CORRECTION:设置误差校正
+ //ErrorCorrectionLevel:误差校正等级,L = ~7% correction、M = ~15% correction、Q = ~25% correction、H = ~30% correction
+ //不设置时,默认为 L 等级,等级不一样,生成的图案不同,但扫描的结果是一样的
+ hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
+
+ //EncodeHintType.MARGIN:设置二维码边距,单位像素,值越小,二维码距离四周越近
+ hints.put(EncodeHintType.MARGIN, 1);
+
+ MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
+ BitMatrix bitMatrix = multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, CODE_WIDTH, CODE_HEIGHT, hints);
+ BufferedImage bufferedImage = new BufferedImage(CODE_WIDTH, CODE_HEIGHT, BufferedImage.TYPE_INT_BGR);
+ for (int x = 0; x < CODE_WIDTH; x++) {
+ for (int y = 0; y < CODE_HEIGHT; y++) {
+ bufferedImage.setRGB(x, y, bitMatrix.get(x, y) ? FRONT_COLOR : BACKGROUND_COLOR);
+ }
+ }
+ return bufferedImage;
+ }
+}
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index 23bd948..ff32aef 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -29,6 +29,7 @@ websocket:
netty:
server:
port: 9999
+ client-port: 9998
# 接收者的线程数
parent-group-threads: 10
# 客户端的线程数
diff --git a/src/main/resources/mapper/TbShopUserMapper.xml b/src/main/resources/mapper/TbShopUserMapper.xml
index 0bdeb13..0feb3d9 100644
--- a/src/main/resources/mapper/TbShopUserMapper.xml
+++ b/src/main/resources/mapper/TbShopUserMapper.xml
@@ -380,6 +380,15 @@
where id = #{id,jdbcType=VARCHAR}
+
+
+ update tb_shop_user
+ set
+ user_id = #{userId,jdbcType=VARCHAR},
+ updated_at = #{updatedAt,jdbcType=BIGINT}
+ where id = #{id,jdbcType=VARCHAR}
+
+