From 3191f721ce118bf0b04d46b2d06ee0046a9dba3f Mon Sep 17 00:00:00 2001
From: czk <13938338+chen-zhaozhaokai@user.noreply.gitee.com>
Date: Mon, 20 May 2024 16:04:56 +0800
Subject: [PATCH] =?UTF-8?q?=E6=8B=BC=E5=9B=A2=E4=BC=98=E5=8C=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
mall_auth/pom.xml | 8 +-
.../mall/auth/controller/AuthController.java | 6 +-
.../com/mall/auth/service/AuthService.java | 3 +
.../auth/service/impl/AuthServiceImpl.java | 3 +-
mall_auth/src/main/resources/bootstrap.yml | 12 ++
.../com/mall/common/utils/SecurityUtils.java | 44 ++++
.../com/mall/server/ServerApplication.java | 2 +
.../mall/server/aop/LogAnnotationAspect.java | 24 ++-
.../mall/server/config/GroupDelayConfig.java | 94 +++++++++
...elayConfig.java => SpikesDelayConfig.java} | 12 +-
.../server/controller/TeamworkController.java | 55 +++++
.../mall/server/domain/TeamworkEntity.java | 109 ++++++++++
.../server/domain/TeamworkRecordEntity.java | 65 ++++++
.../mall/server/domain/vo/GroupBookingVo.java | 18 ++
.../mall/server/mapper/TeamworkMapper.java | 12 ++
.../server/mapper/TeamworkRecordMapper.java | 12 ++
.../server/monitor/GroupBookingMonitor.java | 68 +++++++
.../mall/server/monitor/SpikesMonitor.java | 50 +++--
.../mall/server/service/TeamworkService.java | 17 ++
.../service/impl/SpikesServiceImpl.java | 4 +-
.../service/impl/TeamworkServiceImpl.java | 192 ++++++++++++++++++
21 files changed, 772 insertions(+), 38 deletions(-)
create mode 100644 mall_modules/mall_server/src/main/java/com/mall/server/config/GroupDelayConfig.java
rename mall_modules/mall_server/src/main/java/com/mall/server/config/{DelayConfig.java => SpikesDelayConfig.java} (87%)
create mode 100644 mall_modules/mall_server/src/main/java/com/mall/server/controller/TeamworkController.java
create mode 100644 mall_modules/mall_server/src/main/java/com/mall/server/domain/TeamworkEntity.java
create mode 100644 mall_modules/mall_server/src/main/java/com/mall/server/domain/TeamworkRecordEntity.java
create mode 100644 mall_modules/mall_server/src/main/java/com/mall/server/domain/vo/GroupBookingVo.java
create mode 100644 mall_modules/mall_server/src/main/java/com/mall/server/mapper/TeamworkMapper.java
create mode 100644 mall_modules/mall_server/src/main/java/com/mall/server/mapper/TeamworkRecordMapper.java
create mode 100644 mall_modules/mall_server/src/main/java/com/mall/server/monitor/GroupBookingMonitor.java
create mode 100644 mall_modules/mall_server/src/main/java/com/mall/server/service/TeamworkService.java
create mode 100644 mall_modules/mall_server/src/main/java/com/mall/server/service/impl/TeamworkServiceImpl.java
diff --git a/mall_auth/pom.xml b/mall_auth/pom.xml
index ad03314..0b4e0b5 100644
--- a/mall_auth/pom.xml
+++ b/mall_auth/pom.xml
@@ -36,12 +36,18 @@
aliyun-sdk-oss
3.10.2
-
junit
junit
4.12
+
+
+ org.springframework.cloud
+ spring-cloud-starter-zipkin
+ 2.2.8.RELEASE
+
+
diff --git a/mall_auth/src/main/java/com/mall/auth/controller/AuthController.java b/mall_auth/src/main/java/com/mall/auth/controller/AuthController.java
index 253eb54..ff79378 100644
--- a/mall_auth/src/main/java/com/mall/auth/controller/AuthController.java
+++ b/mall_auth/src/main/java/com/mall/auth/controller/AuthController.java
@@ -16,6 +16,9 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
+import java.io.IOException;
+import java.util.Base64;
+import java.util.HashMap;
import java.util.concurrent.CompletableFuture;
/**
@@ -112,7 +115,4 @@ public class AuthController {
return authService.authentication(idCardRequest);
}
- @Autowired
- private UserServiceFeign userServiceFeign;
-
}
diff --git a/mall_auth/src/main/java/com/mall/auth/service/AuthService.java b/mall_auth/src/main/java/com/mall/auth/service/AuthService.java
index 70be632..83e92bb 100644
--- a/mall_auth/src/main/java/com/mall/auth/service/AuthService.java
+++ b/mall_auth/src/main/java/com/mall/auth/service/AuthService.java
@@ -8,6 +8,8 @@ import com.mall.common.domain.vo.UserInfoVo;
import com.mall.common.result.Result;
import org.springframework.web.multipart.MultipartFile;
+import java.util.HashMap;
+
public interface AuthService {
Result login(LoginVo loginVo);
@@ -25,4 +27,5 @@ public interface AuthService {
Result authentication(IdCardRequest idCardRequest);
+
}
diff --git a/mall_auth/src/main/java/com/mall/auth/service/impl/AuthServiceImpl.java b/mall_auth/src/main/java/com/mall/auth/service/impl/AuthServiceImpl.java
index 2c0a477..3eddc76 100644
--- a/mall_auth/src/main/java/com/mall/auth/service/impl/AuthServiceImpl.java
+++ b/mall_auth/src/main/java/com/mall/auth/service/impl/AuthServiceImpl.java
@@ -216,10 +216,9 @@ public class AuthServiceImpl implements AuthService {
return idCardCheckLifeVo;
}, threadPoolConfig.getThreadPoolExecutor());
-// CompletableFuture.allOf(f1,f2).join();
IdCardValidateVo idCardValidateVo = null;
IdCardCheckLifeVo idCardCheckLifeVo = null;
-
+// CompletableFuture.allOf(f1,f2).join();
try {
idCardValidateVo = f1.get();
idCardCheckLifeVo = f2.get();
diff --git a/mall_auth/src/main/resources/bootstrap.yml b/mall_auth/src/main/resources/bootstrap.yml
index 19925c4..c22cc25 100644
--- a/mall_auth/src/main/resources/bootstrap.yml
+++ b/mall_auth/src/main/resources/bootstrap.yml
@@ -3,6 +3,18 @@ server:
port: 9000
# Spring
spring:
+ #服务追踪
+ zipkin:
+ base-url: http://124.221.183.9:9411/ # zipkin服务器的地址
+ discovery-client-enabled: false #关闭服务发现,否则spring cloud会把zipkin的url当作服务名称
+ sender:
+ type: web #设苦使用http的方式传输数据
+ sleuth:
+ traceId128: true
+ sampler:
+ probability: 1.0 #抽样采集率为100%,默认为0.1 ,即10%
+ propagation-keys: user_name
+
servlet:
multipart:
#这将限制单个文件的最大大小为10MB
diff --git a/mall_common/src/main/java/com/mall/common/utils/SecurityUtils.java b/mall_common/src/main/java/com/mall/common/utils/SecurityUtils.java
index a38aa1b..6d5bea1 100644
--- a/mall_common/src/main/java/com/mall/common/utils/SecurityUtils.java
+++ b/mall_common/src/main/java/com/mall/common/utils/SecurityUtils.java
@@ -1,6 +1,9 @@
package com.mall.common.utils;
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
@@ -12,6 +15,7 @@ import java.util.Base64;
*/
public class SecurityUtils {
+ private static final String key = "01020304";
/**
* 生成BCryptPasswordEncoder密码
@@ -51,4 +55,44 @@ public class SecurityUtils {
throw new RuntimeException(e);
}
}
+
+ // 加密方法
+ public static String encrypt(String plaintext) throws Exception {
+ // 创建 Cipher 对象
+ Cipher cipher = Cipher.getInstance("DES");
+
+ // 创建 SecretKey 对象
+ SecretKey secretKey = new SecretKeySpec(key.getBytes(), "DES");
+
+ // 初始化 Cipher 对象为加密模式,并传入密钥
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey);
+
+ // 执行加密操作
+ byte[] encryptedBytes = cipher.doFinal(plaintext.getBytes());
+
+ // 对加密后的数据进行 Base64 编码
+ return Base64.getEncoder().encodeToString(encryptedBytes);
+ }
+
+ // 解密方法
+ public static String decrypt(String ciphertext) throws Exception {
+ // 创建 Cipher 对象
+ Cipher cipher = Cipher.getInstance("DES");
+
+ // 创建 SecretKey 对象
+ SecretKey secretKey = new SecretKeySpec(key.getBytes(), "DES");
+
+ // 初始化 Cipher 对象为解密模式,并传入密钥
+ cipher.init(Cipher.DECRYPT_MODE, secretKey);
+
+ // 对 Base64 编码后的密文进行解码
+ byte[] encryptedBytes = Base64.getDecoder().decode(ciphertext);
+
+ // 执行解密操作
+ byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
+
+ // 将解密后的字节数组转换为字符串并返回
+ return new String(decryptedBytes);
+ }
+
}
diff --git a/mall_modules/mall_server/src/main/java/com/mall/server/ServerApplication.java b/mall_modules/mall_server/src/main/java/com/mall/server/ServerApplication.java
index c58d53a..dd9197f 100644
--- a/mall_modules/mall_server/src/main/java/com/mall/server/ServerApplication.java
+++ b/mall_modules/mall_server/src/main/java/com/mall/server/ServerApplication.java
@@ -2,6 +2,7 @@ package com.mall.server;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
@@ -10,6 +11,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
@EnableFeignClients
+@EnableAsync
public class ServerApplication {
public static void main(String[] args) {
SpringApplication.run(ServerApplication.class,args);
diff --git a/mall_modules/mall_server/src/main/java/com/mall/server/aop/LogAnnotationAspect.java b/mall_modules/mall_server/src/main/java/com/mall/server/aop/LogAnnotationAspect.java
index aaeac6a..907a399 100644
--- a/mall_modules/mall_server/src/main/java/com/mall/server/aop/LogAnnotationAspect.java
+++ b/mall_modules/mall_server/src/main/java/com/mall/server/aop/LogAnnotationAspect.java
@@ -21,19 +21,27 @@ public class LogAnnotationAspect {
@Pointcut("execution(* com.mall.server.service.impl.*.*(..))")
private void allMethod(){}
- //应用周围通知
+// 应用周围通知
@Around("allMethod()")
- public void doAround(ProceedingJoinPoint call) throws Throwable{
- long start = new Date().getTime();
+ public Object doAround(ProceedingJoinPoint call) throws Throwable {
+ long start = System.currentTimeMillis(); // 更推荐使用 System.currentTimeMillis()
String methodName = call.getSignature().getName(); // 获取方法名
Object[] args = call.getArgs(); // 获取方法的参数
- call.proceed();
- long end = new Date().getTime();
- log.info("耗时:"+(end-start)/1000+"秒");
- log.info(methodName+"()方法执行");
+
+ // 调用原始方法并获取返回值
+ Object proceed = call.proceed();
+
+ long end = System.currentTimeMillis(); // 更推荐使用 System.currentTimeMillis()
+ log.info("方法 {} 执行耗时:{} 秒", methodName, (end - start) / 1000.0);
+
+ // 打印方法名和参数
+ log.info("{}() 方法执行", methodName);
for (Object arg : args) {
- log.info("参数:"+String.valueOf(arg));
+ log.info("参数:{}", String.valueOf(arg));
}
+
+ // 将方法的返回值传回
+ return proceed; // 确保返回原方法的返回值
}
}
diff --git a/mall_modules/mall_server/src/main/java/com/mall/server/config/GroupDelayConfig.java b/mall_modules/mall_server/src/main/java/com/mall/server/config/GroupDelayConfig.java
new file mode 100644
index 0000000..d159a7f
--- /dev/null
+++ b/mall_modules/mall_server/src/main/java/com/mall/server/config/GroupDelayConfig.java
@@ -0,0 +1,94 @@
+package com.mall.server.config;
+
+import lombok.extern.log4j.Log4j2;
+import org.springframework.amqp.core.Binding;
+import org.springframework.amqp.core.BindingBuilder;
+import org.springframework.amqp.core.DirectExchange;
+import org.springframework.amqp.core.Queue;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.HashMap;
+
+/**
+ * 拼团延迟队列
+ */
+@Log4j2
+@Configuration
+public class GroupDelayConfig {
+
+ /**
+ * 队列
+ */
+ public static final String CZKQUEUE = "group_queue";
+ /**
+ * 交换机
+ */
+ public static final String EXCHANGE = "group_exchange";
+ /**
+ * 路由key
+ */
+ public static final String ROUKEYCZK = "group_queue";
+
+
+
+ @Bean
+ public DirectExchange directExchange() {
+ return new DirectExchange(EXCHANGE);
+ }
+
+ @Bean
+ public Queue autoDeleteQueue1(){
+ HashMap map = new HashMap<>();
+ map.put("x-dead-letter-exchange",DEADEXCHANGE);
+ map.put("x-dead-letter-routing-key",DEADROUKEY);
+ map.put("x-message-ttl",MESSAGE_FIVE);
+ return new Queue(CZKQUEUE,true,false,false,map);
+ }
+
+ @Bean
+ public Binding binding1a() {
+ return BindingBuilder.bind(autoDeleteQueue1())
+ .to(directExchange())
+ .with(ROUKEYCZK);
+ }
+
+ /**
+ * 死信交换机
+ */
+ public static final String DEADEXCHANGE = "group_dead_exchange";
+ /**
+ * 死信队列
+ */
+ public static final String DEADQUEUE = "group_dead_queue";
+ /**
+ * 死信路由key
+ */
+ public static final String DEADROUKEY = "group_dead_queue";
+ /**
+ * 5秒
+ */
+ public static final Integer MESSAGE_FIVE = 20000;
+ /**
+ * 10分钟
+ */
+ public static final Integer MESSAGE_FEN = 600000;
+
+
+ @Bean
+ public DirectExchange deadExchange() {
+ return new DirectExchange(DEADEXCHANGE);
+ }
+
+ @Bean
+ public Queue autoDeleteQueue2(){
+ return new Queue(DEADQUEUE,true);
+ }
+
+ @Bean
+ public Binding binding2() {
+ return BindingBuilder.bind(autoDeleteQueue2())
+ .to(deadExchange())
+ .with(DEADROUKEY);
+ }
+}
diff --git a/mall_modules/mall_server/src/main/java/com/mall/server/config/DelayConfig.java b/mall_modules/mall_server/src/main/java/com/mall/server/config/SpikesDelayConfig.java
similarity index 87%
rename from mall_modules/mall_server/src/main/java/com/mall/server/config/DelayConfig.java
rename to mall_modules/mall_server/src/main/java/com/mall/server/config/SpikesDelayConfig.java
index a6b7570..90d58e7 100644
--- a/mall_modules/mall_server/src/main/java/com/mall/server/config/DelayConfig.java
+++ b/mall_modules/mall_server/src/main/java/com/mall/server/config/SpikesDelayConfig.java
@@ -4,22 +4,16 @@ import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
-import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
/**
- * @Author:Chen
- * @Package:com.bw.common.config
- * @Project:holiday2
- * @name:RabbitConfig
- * @Date:2024/2/5 10:55
- * @Description: TODO
+ * 秒杀延迟队列
*/
@Log4j2
@Configuration
-public class DelayConfig {
+public class SpikesDelayConfig {
/**
* 队列
@@ -72,7 +66,7 @@ public class DelayConfig {
/**
* 5秒
*/
- public static final Integer MESSAGE_FIVE = 5000;
+ public static final Integer MESSAGE_FIVE = 20000;
/**
* 10分钟
*/
diff --git a/mall_modules/mall_server/src/main/java/com/mall/server/controller/TeamworkController.java b/mall_modules/mall_server/src/main/java/com/mall/server/controller/TeamworkController.java
new file mode 100644
index 0000000..f9bdaae
--- /dev/null
+++ b/mall_modules/mall_server/src/main/java/com/mall/server/controller/TeamworkController.java
@@ -0,0 +1,55 @@
+package com.mall.server.controller;
+
+import cn.hutool.crypto.SecureUtil;
+import com.mall.common.result.BizException;
+import com.mall.common.result.Result;
+import com.mall.common.utils.SecurityUtils;
+import com.mall.server.service.TeamworkService;
+import io.swagger.models.auth.In;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ *拼团Controller
+ */
+@RestController
+@RequestMapping("/teamwork")
+public class TeamworkController {
+
+ @Autowired
+ private TeamworkService teamworkService;
+
+ /**
+ * 用户开启拼团
+ * @param id
+ * @return
+ */
+ @GetMapping("groupBooking")
+ public Result groupBooking(@NotNull String id, @RequestParam Integer state){
+ //state 0未加密 1加密
+ if(state==null || state==0){
+ return teamworkService.groupBooking(Long.parseLong(id));
+ }
+ String skuId = null;
+ try {
+ skuId = SecurityUtils.decrypt(id);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ return teamworkService.groupBooking(Long.parseLong(skuId));
+ }
+
+ /**
+ * 分享加密路径
+ * @param skuId
+ * @return
+ */
+ @GetMapping("encryption")
+ public Result encryption(@NotNull Long skuId){
+ return teamworkService.encryption(skuId);
+ }
+
+}
diff --git a/mall_modules/mall_server/src/main/java/com/mall/server/domain/TeamworkEntity.java b/mall_modules/mall_server/src/main/java/com/mall/server/domain/TeamworkEntity.java
new file mode 100644
index 0000000..90992c7
--- /dev/null
+++ b/mall_modules/mall_server/src/main/java/com/mall/server/domain/TeamworkEntity.java
@@ -0,0 +1,109 @@
+package com.mall.server.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+import java.text.DecimalFormat;
+import java.util.Date;
+
+/**
+ *拼团表
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@TableName("pms_teamwork")
+public class TeamworkEntity {
+ /**
+ * 主键id
+ */
+ @TableId(type = IdType.AUTO)
+ private Long id;
+ /**
+ * 用户id
+ */
+ private Long userId;
+ /**
+ * 开团时间
+ */
+ private Date startGroupTime;
+ /**
+ * 几人团
+ */
+ private Integer groupOfSeveral;
+ /**
+ * 几人参与
+ */
+ private Integer severalPeopleInvolved;
+ /**
+ * 拼团号
+ */
+ private Integer packageNumber;
+ /**
+ * 结束时间
+ */
+ private Date finishTime;
+ /**
+ * 拼团名称
+ */
+ private String groupName;
+ /**
+ * 拼团简介
+ */
+ private String groupIntroduce;
+ /**
+ * 原价
+ */
+ private BigDecimal originalPrice;
+ /**
+ * 拼团价
+ */
+ private BigDecimal groupPrice;
+ /**
+ * 拼团时效
+ */
+ private Date groupAging;
+ /**
+ * 拼团人数
+ */
+ private Integer groupNumber;
+ /**
+ * 购买数量限制
+ */
+ private Integer buyNumRestrict;
+ /**
+ * 运费类型0-包邮 1-不包邮
+ */
+ private Integer freightType;
+ /**
+ * 拼团状态0正在平团1拼团成功2拼团失败
+ */
+ private Integer groupStatus;
+ /**
+ * 活动状态
+ */
+ private Integer activeState;
+ /**
+ * 商品属性
+ */
+ private Long skuId;
+ /**
+ * 后台人员设置默认拼团持续时间(时间到未成团,解散)
+ */
+ private Integer continueDate;
+ /**
+ * 拼团活动开始日期
+ */
+ private Date createDate;
+ /**
+ * 拼团活动结束日期
+ */
+ private Date endDate;
+}
diff --git a/mall_modules/mall_server/src/main/java/com/mall/server/domain/TeamworkRecordEntity.java b/mall_modules/mall_server/src/main/java/com/mall/server/domain/TeamworkRecordEntity.java
new file mode 100644
index 0000000..5877096
--- /dev/null
+++ b/mall_modules/mall_server/src/main/java/com/mall/server/domain/TeamworkRecordEntity.java
@@ -0,0 +1,65 @@
+package com.mall.server.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+import java.text.DecimalFormat;
+import java.util.Date;
+
+/**
+ *拼团记录表
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@TableName("pms_teamwork_record")
+public class TeamworkRecordEntity {
+ /**
+ * 拼团记录主键ID
+ */
+ @TableId(type = IdType.AUTO)
+ private Long id;
+ /**
+ * 拼团订单号
+ */
+ private String teamworkOrderSn;
+ /**
+ * 拼团id
+ */
+ private Long teamworkId;
+ /**
+ * 购买价格
+ */
+ private BigDecimal price;
+ /**
+ * 购买个数
+ */
+ private Integer num;
+ /**
+ * 是否成团 0未 1成
+ */
+ private Integer severalPeopleInvolved;
+ /**
+ * 创建时间
+ */
+ private Date createTime;
+ /**
+ * 用户id
+ */
+ private Long userId;
+ /**
+ * 拼团商品id
+ */
+ private Long skuId;
+ /**
+ * 判断是否为商品拼团发起人 0是 1 不是
+ */
+ private Integer state;
+}
diff --git a/mall_modules/mall_server/src/main/java/com/mall/server/domain/vo/GroupBookingVo.java b/mall_modules/mall_server/src/main/java/com/mall/server/domain/vo/GroupBookingVo.java
new file mode 100644
index 0000000..2ca6c7b
--- /dev/null
+++ b/mall_modules/mall_server/src/main/java/com/mall/server/domain/vo/GroupBookingVo.java
@@ -0,0 +1,18 @@
+package com.mall.server.domain.vo;
+
+import com.mall.common.domain.OrderItemEntity;
+import com.mall.server.domain.TeamworkRecordEntity;
+import lombok.Builder;
+import lombok.Data;
+
+/**
+ *拼团下单添加记录
+ */
+@Data
+@Builder
+public class GroupBookingVo {
+
+ private TeamworkRecordEntity teamworkRecordEntity;
+ private OrderItemEntity orderItemEntity;
+
+}
diff --git a/mall_modules/mall_server/src/main/java/com/mall/server/mapper/TeamworkMapper.java b/mall_modules/mall_server/src/main/java/com/mall/server/mapper/TeamworkMapper.java
new file mode 100644
index 0000000..6713b98
--- /dev/null
+++ b/mall_modules/mall_server/src/main/java/com/mall/server/mapper/TeamworkMapper.java
@@ -0,0 +1,12 @@
+package com.mall.server.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.mall.server.domain.TeamworkEntity;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ *拼团Mapper
+ */
+@Mapper
+public interface TeamworkMapper extends BaseMapper {
+}
diff --git a/mall_modules/mall_server/src/main/java/com/mall/server/mapper/TeamworkRecordMapper.java b/mall_modules/mall_server/src/main/java/com/mall/server/mapper/TeamworkRecordMapper.java
new file mode 100644
index 0000000..7b3bdee
--- /dev/null
+++ b/mall_modules/mall_server/src/main/java/com/mall/server/mapper/TeamworkRecordMapper.java
@@ -0,0 +1,12 @@
+package com.mall.server.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.mall.server.domain.TeamworkRecordEntity;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ *拼团记录表
+ */
+@Mapper
+public interface TeamworkRecordMapper extends BaseMapper {
+}
diff --git a/mall_modules/mall_server/src/main/java/com/mall/server/monitor/GroupBookingMonitor.java b/mall_modules/mall_server/src/main/java/com/mall/server/monitor/GroupBookingMonitor.java
new file mode 100644
index 0000000..fa61d56
--- /dev/null
+++ b/mall_modules/mall_server/src/main/java/com/mall/server/monitor/GroupBookingMonitor.java
@@ -0,0 +1,68 @@
+package com.mall.server.monitor;
+
+import com.alibaba.fastjson.JSON;
+import com.mall.common.domain.OrderItemEntity;
+import com.mall.server.domain.vo.GroupBookingVo;
+import com.mall.server.mapper.OrderItemMapper;
+import com.mall.server.mapper.TeamworkRecordMapper;
+import com.rabbitmq.client.Channel;
+import org.springframework.amqp.core.Message;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationEvent;
+import org.springframework.context.event.EventListener;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+
+/**
+ *监听添加拼团记录表和下单
+ */
+@Component
+public class GroupBookingMonitor {
+
+ @Autowired
+ private TeamworkRecordMapper teamworkRecordMapper;
+
+ @Autowired
+ private OrderItemMapper orderItemMapper;
+
+ /**
+ * 添加拼团记录表和下单
+ * @param groupBookingVo
+ */
+ @Async
+ @EventListener(GroupBookingVo.class)
+ public void customerEventListener(GroupBookingVo groupBookingVo) {
+ orderItemMapper.insert(groupBookingVo.getOrderItemEntity());
+ teamworkRecordMapper.insert(groupBookingVo.getTeamworkRecordEntity());
+ }
+
+ /**
+ * 拼团超时,进行业务处理
+ * @param msg
+ * @param message
+ * @param channel
+ */
+ public void GroupConsumer(String msg, Message message, Channel channel){
+ long deliveryTag = message.getMessageProperties().getDeliveryTag();
+
+ try {
+
+ channel.basicAck(deliveryTag,false);
+ } catch (IOException e) {
+ try {
+ if(deliveryTag<3){
+ Thread.sleep(3000);
+ channel.basicNack(deliveryTag,false,true);
+ }else {
+ channel.basicNack(deliveryTag,false,false);
+ }
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ }
+
+}
diff --git a/mall_modules/mall_server/src/main/java/com/mall/server/monitor/SpikesMonitor.java b/mall_modules/mall_server/src/main/java/com/mall/server/monitor/SpikesMonitor.java
index 49cec22..a55079e 100644
--- a/mall_modules/mall_server/src/main/java/com/mall/server/monitor/SpikesMonitor.java
+++ b/mall_modules/mall_server/src/main/java/com/mall/server/monitor/SpikesMonitor.java
@@ -3,7 +3,7 @@ package com.mall.server.monitor;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.mall.common.domain.OrderItemEntity;
-import com.mall.server.config.DelayConfig;
+import com.mall.server.config.SpikesDelayConfig;
import com.mall.server.config.MqConfig;
import com.mall.server.constant.SpikesConstant;
import com.mall.server.service.OrderItemService;
@@ -31,22 +31,35 @@ public class SpikesMonitor {
@Autowired
private OrderItemService orderItemService;
- @RabbitListener(queues = DelayConfig.DEADQUEUE)
+ /**
+ * 取消订单
+ * @param meg
+ * @param message
+ * @param channel
+ */
+ @RabbitListener(queues = SpikesDelayConfig.DEADQUEUE)
public void consumer(String meg, Message message, Channel channel){
log.info("延迟队列接受到消息"+meg);
long deliveryTag = message.getMessageProperties().getDeliveryTag();
+ if(meg==null){
+ try {
+ channel.basicAck(deliveryTag,false);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
String[] split = meg.split(",");
String skuId = split[0];
String orderSn = split[1];
- OrderItemEntity orderItemEntity = orderItemService.getOne(
- new LambdaQueryWrapper()
- .eq(OrderItemEntity::getOrderSn, orderSn)
- );
- if (orderItemEntity.getStatus().equals(0)) {
- RSemaphore semaphore = redissonClient.getSemaphore(SpikesConstant.SPIKES_INVENTORY + skuId);
- semaphore.release(1);
- }
try {
+ OrderItemEntity orderItemEntity = orderItemService.getOne(
+ new LambdaQueryWrapper()
+ .eq(OrderItemEntity::getOrderSn, orderSn)
+ );
+ if (orderItemEntity.getStatus().equals(0)) {
+ RSemaphore semaphore = redissonClient.getSemaphore(SpikesConstant.SPIKES_INVENTORY + skuId);
+ semaphore.release(1);
+ }
channel.basicAck(deliveryTag,false);
} catch (IOException e) {
try {
@@ -62,14 +75,25 @@ public class SpikesMonitor {
}
}
+ /**
+ * 下订单
+ * @param meg
+ * @param message
+ * @param channel
+ */
@RabbitListener(queues = MqConfig.DXQUEUE)
public void orderConsumer(String meg, Message message, Channel channel){
log.info("下订单"+meg);
long deliveryTag = message.getMessageProperties().getDeliveryTag();
-
- orderItemService.save(JSON.parseObject(meg,OrderItemEntity.class));
-
+ if(meg ==null){
+ try {
+ channel.basicAck(deliveryTag,false);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
try {
+ orderItemService.save(JSON.parseObject(meg,OrderItemEntity.class));
channel.basicAck(deliveryTag,false);
} catch (IOException e) {
try {
diff --git a/mall_modules/mall_server/src/main/java/com/mall/server/service/TeamworkService.java b/mall_modules/mall_server/src/main/java/com/mall/server/service/TeamworkService.java
new file mode 100644
index 0000000..abb2ea1
--- /dev/null
+++ b/mall_modules/mall_server/src/main/java/com/mall/server/service/TeamworkService.java
@@ -0,0 +1,17 @@
+package com.mall.server.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.mall.common.result.Result;
+import com.mall.server.domain.TeamworkEntity;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *拼团Service
+ */
+public interface TeamworkService extends IService {
+ Result groupBooking(Long skuId);
+
+ Result encryption(Long skuId);
+}
diff --git a/mall_modules/mall_server/src/main/java/com/mall/server/service/impl/SpikesServiceImpl.java b/mall_modules/mall_server/src/main/java/com/mall/server/service/impl/SpikesServiceImpl.java
index 84d8da0..1697c4a 100644
--- a/mall_modules/mall_server/src/main/java/com/mall/server/service/impl/SpikesServiceImpl.java
+++ b/mall_modules/mall_server/src/main/java/com/mall/server/service/impl/SpikesServiceImpl.java
@@ -12,7 +12,7 @@ import com.mall.common.result.BizException;
import com.mall.common.result.Result;
import com.mall.common.utils.IdUtils;
import com.mall.common.utils.StringUtils;
-import com.mall.server.config.DelayConfig;
+import com.mall.server.config.SpikesDelayConfig;
import com.mall.server.config.MqConfig;
import com.mall.server.constant.SpikesConstant;
import com.mall.server.domain.SkuEntity;
@@ -193,7 +193,7 @@ public class SpikesServiceImpl extends ServiceImpl
});
rabbitTemplate.convertAndSend(
- DelayConfig.EXCHANGE, DelayConfig.ROUKEYCZK, skuId + "," + orderSn,
+ SpikesDelayConfig.EXCHANGE, SpikesDelayConfig.ROUKEYCZK, skuId + "," + orderSn,
message -> {
message.getMessageProperties().setMessageId(IdUtils.genId());
return message;
diff --git a/mall_modules/mall_server/src/main/java/com/mall/server/service/impl/TeamworkServiceImpl.java b/mall_modules/mall_server/src/main/java/com/mall/server/service/impl/TeamworkServiceImpl.java
new file mode 100644
index 0000000..8d8e7fc
--- /dev/null
+++ b/mall_modules/mall_server/src/main/java/com/mall/server/service/impl/TeamworkServiceImpl.java
@@ -0,0 +1,192 @@
+package com.mall.server.service.impl;
+
+import cn.hutool.crypto.Mode;
+import cn.hutool.crypto.Padding;
+import cn.hutool.crypto.SecureUtil;
+import cn.hutool.crypto.symmetric.DES;
+import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.mall.common.constant.TokenConstants;
+import com.mall.common.domain.OrderItemEntity;
+import com.mall.common.domain.UserInfo;
+import com.mall.common.redis.RedisCache;
+import com.mall.common.result.BizException;
+import com.mall.common.result.Result;
+import com.mall.common.utils.IdUtils;
+import com.mall.common.utils.SecurityUtils;
+import com.mall.common.utils.StringUtils;
+import com.mall.server.config.GroupDelayConfig;
+import com.mall.server.domain.SkuEntity;
+import com.mall.server.domain.TeamworkEntity;
+import com.mall.server.domain.TeamworkRecordEntity;
+import com.mall.server.domain.vo.GroupBookingVo;
+import com.mall.server.mapper.OrderItemMapper;
+import com.mall.server.mapper.SkuMapper;
+import com.mall.server.mapper.TeamworkMapper;
+import com.mall.server.mapper.TeamworkRecordMapper;
+import com.mall.server.service.TeamworkService;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 拼团ServiceImpl
+ */
+@Service
+public class TeamworkServiceImpl extends ServiceImpl
+ implements TeamworkService {
+
+ @Autowired
+ private TeamworkMapper teamworkMapper;
+
+ @Autowired
+ private TeamworkRecordMapper teamworkRecordMapper;
+
+ @Autowired
+ private RedisCache redisCache;
+
+ @Autowired
+ private HttpServletRequest request;
+
+ @Autowired
+ private SkuMapper skuMapper;
+
+ @Autowired
+ private ApplicationContext applicationContext;
+
+ @Autowired
+ private OrderItemMapper orderItemMapper;
+
+ @Autowired
+ private RabbitTemplate rabbitTemplate;
+
+ public UserInfo getLogin() {
+ String token = request.getHeader(TokenConstants.TOKEN);
+ if (StringUtils.isBlank(token)) {
+ throw new BizException(401, "未登录");
+ }
+ UserInfo userInfo = redisCache.getCacheObject(TokenConstants.TOKEN + token);
+ return userInfo;
+ }
+
+ @Transactional
+ @Override
+ public Result groupBooking(Long skuId) {
+ UserInfo login = getLogin();
+ if (redisCache.hasKey("groupBooking_" + login.getId() + skuId)) {
+ throw new BizException(500, "禁止重复抢购欧");
+ }
+ redisCache.setCacheObject("groupBooking_" + login.getId() + skuId, IdUtils.genId().toString(), 1L, TimeUnit.MINUTES);
+ //商品id查询商品表
+ SkuEntity skuEntity = skuMapper.selectOne(
+ new LambdaQueryWrapper()
+ .eq(SkuEntity::getId, skuId)
+ );
+ //商品的拼图id查询拼团表
+ TeamworkEntity teamworkEntity = teamworkMapper.selectOne(
+ new LambdaQueryWrapper()
+ .eq(TeamworkEntity::getId, skuEntity.getBargainId())
+ );
+ //校验拼团时间
+ if (teamworkEntity.getCreateDate().compareTo(new Date()) > 0 || teamworkEntity.getEndDate().compareTo(new Date()) < 0) {
+ throw new BizException(500, skuEntity.getName() + "该商品不在拼团时间内");
+ }
+ //查询拼团记录防止用户拼同一活动同一商品
+ TeamworkRecordEntity teamworkRecordEntity = teamworkRecordMapper.selectOne(
+ new LambdaQueryWrapper()
+ .eq(TeamworkRecordEntity::getUserId, login.getId())
+ .eq(TeamworkRecordEntity::getTeamworkId, teamworkEntity.getId())
+ .eq(TeamworkRecordEntity::getSkuId, skuEntity.getId())
+ );
+ if (teamworkRecordEntity != null) {
+ throw new BizException(500, "禁止重复拼团");
+ }
+ //根据拼团id和商品id查询拼团记录表几人拼团
+ List teamworkRecordEntityList = teamworkRecordMapper.selectList(
+ new LambdaQueryWrapper()
+ .eq(TeamworkRecordEntity::getTeamworkId, teamworkEntity.getId())
+ .eq(TeamworkRecordEntity::getSkuId, skuEntity.getId())
+ );
+ //订单信息
+ String orderSn = IdUtils.genId();
+ OrderItemEntity orderItem = OrderItemEntity.builder()
+ .userId(login.getId())
+ .orderSn(orderSn)
+ .skuId(skuId)
+ .skuName(skuEntity.getName())
+ .skuPic(skuEntity.getDefaultImage())
+ .skuPrice(skuEntity.getPrice())
+// .promotionAmount()
+// .couponAmount()
+// .integrationAmount()
+ .realAmount(skuEntity.getActivityPrice())
+ .status(0).build();
+ //拼团记录表
+ TeamworkRecordEntity teamworkRecord = TeamworkRecordEntity.builder()
+ .teamworkOrderSn(orderSn)
+ .teamworkId(teamworkEntity.getId())
+ .price(skuEntity.getPrice())
+ .num(1)
+ .severalPeopleInvolved(0)
+ .createTime(new Date())
+ .userId(login.getId())
+ .skuId(skuEntity.getId())
+ .state(0).build();//发起人
+ //参与拼团
+ if (teamworkRecordEntityList.size() != 0) {
+ //团满
+ if (teamworkRecordEntityList.size() == teamworkEntity.getGroupOfSeveral()) {
+ throw new BizException(500, "拼团人数已满");
+ }
+ teamworkRecord.setState(1);
+ applicationContext.publishEvent(
+ GroupBookingVo.builder()
+ .orderItemEntity(orderItem)
+ .teamworkRecordEntity(teamworkRecord).build()
+ );
+ return Result.success(orderSn, "拼团成功");
+ }
+ //拼团发起人
+ applicationContext.publishEvent(
+ GroupBookingVo.builder()
+ .orderItemEntity(orderItem)
+ .teamworkRecordEntity(teamworkRecord).build()
+ );
+ //发起拼团之后扣减库存,把一整个拼团的库存全部扣减
+ skuMapper.updateById(
+ SkuEntity.builder()
+ .id(skuId)
+ .inventoryRestrict(teamworkEntity.getGroupOfSeveral())
+ .build()
+ );
+ //延迟队列48小时后没有成团,取消拼团,并归还库存,支付的退款
+ rabbitTemplate.convertAndSend(GroupDelayConfig.EXCHANGE, GroupDelayConfig.ROUKEYCZK, orderSn,
+ message -> {
+ message.getMessageProperties().setMessageId(orderSn);
+ return message;
+ });
+ return Result.success(orderSn, "拼团成功");
+ }
+
+ @Override
+ public Result encryption(Long skuId) {
+ String encrypt = null;
+ try {
+ encrypt = SecurityUtils.encrypt(skuId.toString());
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ return Result.success("http://localhost:9002/teamwork/groupBooking?skuId=" + encrypt + "&state=1", "加密路径成功");
+ }
+
+}