| @@ -88,17 +88,17 @@ public class WebMvcConfig implements WebMvcConfigurer { | |||
| .without(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) | |||
| ); | |||
| //序列化将Long转String类型 | |||
| simpleModule.addSerializer(Long.class, ToStringSerializer.instance); | |||
| simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance); | |||
| SimpleModule bigIntegerModule = new SimpleModule(); | |||
| // simpleModule.addSerializer(Long.class, ToStringSerializer.instance); | |||
| // simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance); | |||
| // SimpleModule bigIntegerModule = new SimpleModule(); | |||
| //序列化将BigInteger转String类型 | |||
| bigIntegerModule.addSerializer(BigInteger.class, ToStringSerializer.instance); | |||
| SimpleModule bigDecimalModule = new SimpleModule(); | |||
| // bigIntegerModule.addSerializer(BigInteger.class, ToStringSerializer.instance); | |||
| // SimpleModule bigDecimalModule = new SimpleModule(); | |||
| //序列化将BigDecimal转String类型 | |||
| bigDecimalModule.addSerializer(BigDecimal.class, ToStringSerializer.instance); | |||
| // bigDecimalModule.addSerializer(BigDecimal.class, ToStringSerializer.instance); | |||
| objectMapper.registerModule(simpleModule); | |||
| objectMapper.registerModule(bigDecimalModule); | |||
| objectMapper.registerModule(bigIntegerModule); | |||
| // objectMapper.registerModule(bigDecimalModule); | |||
| // objectMapper.registerModule(bigIntegerModule); | |||
| jackson2HttpMessageConverter.setObjectMapper(objectMapper); | |||
| converters.add(jackson2HttpMessageConverter); | |||
| } | |||
| @@ -1,11 +1,17 @@ | |||
| package com.iformall; | |||
| import com.iformall.domain.po.msg.FmInsideCouponVerifyMsg; | |||
| import com.iformall.enums.EnumMsgRecordType; | |||
| import com.iformall.service.msg.impl.FmInsideCouponVerifyMsgServiceImpl; | |||
| import com.ulisesbocchio.jasyptspringboot.annotation.EnableEncryptableProperties; | |||
| import org.mybatis.spring.annotation.MapperScan; | |||
| import org.rocketmq.starter.annotation.EnableRocketMQ; | |||
| import org.springframework.beans.BeansException; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.beans.factory.annotation.Value; | |||
| import org.springframework.boot.SpringApplication; | |||
| import org.springframework.boot.autoconfigure.SpringBootApplication; | |||
| import org.springframework.context.ConfigurableApplicationContext; | |||
| import org.springframework.context.annotation.Bean; | |||
| import springfox.documentation.swagger2.annotations.EnableSwagger2; | |||
| @@ -52,8 +58,23 @@ public class ConsumerApplication { | |||
| return uploadDir; | |||
| } | |||
| public static void main(String[] args) { | |||
| SpringApplication.run(ConsumerApplication.class, args); | |||
| ConfigurableApplicationContext context = SpringApplication.run(ConsumerApplication.class, args); | |||
| // FmInsideCouponVerifyMsg verifyMsg = new FmInsideCouponVerifyMsg(); | |||
| // verifyMsg.setMsgType(EnumMsgRecordType.INSIDE_COUPON_VERIFY.getCode()); | |||
| // //verifyMsg.updateTenantInfo(tenantEntity); | |||
| // verifyMsg.setTenantId("789"); | |||
| // verifyMsg.setCouponOrderId(436060427278385152L); | |||
| // verifyMsg.setBUserId(435982884998905856L); | |||
| // try { | |||
| // context.getBean(FmInsideCouponVerifyMsgServiceImpl.class).send(verifyMsg); | |||
| // } catch (BeansException e) { | |||
| // // TODO Auto-generated catch block | |||
| // e.printStackTrace(); | |||
| // } catch (Exception e) { | |||
| // // TODO Auto-generated catch block | |||
| // e.printStackTrace(); | |||
| // } | |||
| } | |||
| } | |||
| @@ -86,8 +86,8 @@ aws: | |||
| wechat: | |||
| open: | |||
| componentAppId: "wx897e4673286c915d" | |||
| componentSecret: "cdfdfda65c45689beb6766c4c427eed2" | |||
| componentAppId: "wxdfc8fb4e62d6b52b" | |||
| componentSecret: "98daa62b316dd6feabaad708327ce233" | |||
| componentToken: "formall2018" | |||
| componentAesKey: "htKq8EjBMPNndfZQK9JiFojFaqFwFpw42VfeWFtx7HN" | |||
| redis: | |||
| @@ -4,11 +4,7 @@ spring: | |||
| #include: rabbitMQ | |||
| # JDBC | |||
| datasource: | |||
| <<<<<<< HEAD | |||
| url: jdbc:mysql://zc349w82qvn56ftl5e64-rw4rm.rwlb.rds.aliyuncs.com:3306/mallink?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useUnicode=true&useSSL=false&useAffectedRows=true | |||
| ======= | |||
| url: jdbc:mysql://202.165.179.86:3306/mallinkDevGroup1?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useUnicode=true&useSSL=false&useAffectedRows=true | |||
| >>>>>>> develop | |||
| url: jdbc:mysql://zc349w82qvn56ftl5e64-rw4rm.rwlb.rds.aliyuncs.com:3306/mallinkDevGroup1?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useUnicode=true&useSSL=false&useAffectedRows=true | |||
| username: ENC(dZ8fmrtuBMQYaRytKQgTqg==) | |||
| password: ENC(IKH7HxMZwIqMttMc9+QsqWa1KMsJvTs4) | |||
| type: com.alibaba.druid.pool.DruidDataSource | |||
| @@ -94,8 +90,8 @@ jasypt: | |||
| wechat: | |||
| open: | |||
| componentAppId: "wx897e4673286c915d" | |||
| componentSecret: "cdfdfda65c45689beb6766c4c427eed2" | |||
| componentAppId: "wxdfc8fb4e62d6b52b" | |||
| componentSecret: "98daa62b316dd6feabaad708327ce233" | |||
| componentToken: "formall2018" | |||
| componentAesKey: "htKq8EjBMPNndfZQK9JiFojFaqFwFpw42VfeWFtx7HN" | |||
| redis: | |||
| @@ -67,22 +67,22 @@ public class CouponOrderExpiringSchedule { | |||
| } | |||
| @Scheduled(cron = "0 0/2 * * * ?") // 每天凌晨00:05 | |||
| @Scheduled(cron = "0 5 0 * * ?") // 每天凌晨00:05 | |||
| // @Scheduled(cron = "*/10 * * * * ?") // 测试10秒中一次 | |||
| public void couponOrderRefundSchedule() { | |||
| List<WxCouponOrder> list = wxCouponOrderMapper.findExpiredCouponOrderByValidDate(); | |||
| CouponOrderExpiringSchedule proxy = (CouponOrderExpiringSchedule) AopContext.currentProxy(); | |||
| list.stream().forEach(co -> { | |||
| refund(co,proxy); | |||
| proxy.refund(co); | |||
| }); | |||
| } | |||
| @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class}) | |||
| public void refund(WxCouponOrder order,CouponOrderExpiringSchedule proxy) { | |||
| public void refund(WxCouponOrder order) { | |||
| // 券过期,更改状态及库存退回 | |||
| proxy.couponOrderExpire(order, false); | |||
| couponOrderExpire(order, false); | |||
| // 退款 | |||
| proxy.couponOrderExpireRefund(order, true); | |||
| couponOrderExpireRefund(order, true); | |||
| } | |||
| @@ -86,8 +86,8 @@ aws: | |||
| wechat: | |||
| open: | |||
| componentAppId: "wx897e4673286c915d" | |||
| componentSecret: "cdfdfda65c45689beb6766c4c427eed2" | |||
| componentAppId: "wxdfc8fb4e62d6b52b" | |||
| componentSecret: "98daa62b316dd6feabaad708327ce233" | |||
| componentToken: "formall2018" | |||
| componentAesKey: "htKq8EjBMPNndfZQK9JiFojFaqFwFpw42VfeWFtx7HN" | |||
| redis: | |||
| @@ -580,6 +580,33 @@ public class WxOrderServiceImpl implements WxOrderService { | |||
| * @param couponIdStr | |||
| */ | |||
| private void stockReduce(WxCUser user, WxCoupon coupon, String couponIdStr) { | |||
| //如果缓存中不存在这个key,则从coupon中取 | |||
| if(!redisLock.hasCouponStockCache(coupon.getId())) { | |||
| //此处需要加锁,防止并发设置 | |||
| long time = System.currentTimeMillis() + RedisLock.TIMEOUT; | |||
| String timeStr = String.valueOf(time); | |||
| boolean stocksetlock = redisLock.lock("couponLockStockSet_"+coupon.getId(), timeStr); | |||
| if (stocksetlock) { | |||
| if (!redisLock.hasCouponStockCache(coupon.getId())) { | |||
| WxCoupon cou = wxCouponMapper.selectById(coupon.getId()); | |||
| if (null == cou) { | |||
| redisLock.unlock("couponLockStockSet_"+coupon.getId(), timeStr); | |||
| throw new MallinkException(ErrorCode.ORDER_IS_FAIL.getCode(),"未查询到券!"+coupon.getId()); | |||
| } | |||
| try { | |||
| redisLock.setCouponStock(coupon.getId(), cou.getRemainInventory()); | |||
| }catch(Exception e) { | |||
| logger.error("set couponstock to redis fail.",e); | |||
| throw new MallinkException(ErrorCode.ORDER_IS_FAIL.getCode(),"redis设置券库存失败"+coupon.getId()); | |||
| }finally { | |||
| redisLock.unlock("couponLockStockSet_"+coupon.getId(), timeStr); | |||
| } | |||
| }else { | |||
| redisLock.unlock("couponLockStockSet_"+coupon.getId(), timeStr); | |||
| } | |||
| } | |||
| } | |||
| long redisStock = redisLock.getCouponStock(Long.parseLong(couponIdStr)); | |||
| if (redisStock<=0) { | |||
| @@ -1224,10 +1251,18 @@ public class WxOrderServiceImpl implements WxOrderService { | |||
| if (Objects.nonNull(wxCouponSendVo) && Objects.equals(EnumCouponSendSendType.MERCHANT.getCode(), wxCouponSendVo.getSendType())) { | |||
| // 商户注券减库存操作 | |||
| stockMerchantReduce(user, coupon, couponIdStr, wxCouponSendVo); | |||
| try { | |||
| stockMerchantReduce(user, coupon, couponIdStr, wxCouponSendVo); | |||
| }catch(Exception e) { | |||
| throw new MallinkException(ErrorCode.COUPON_STOCK_ERR.getCode(), e.getMessage()); | |||
| } | |||
| } else { | |||
| // 减库存操作 | |||
| stockReduce(user, coupon, couponIdStr); | |||
| try { | |||
| stockReduce(user, coupon, couponIdStr); | |||
| }catch(Exception e) { | |||
| throw new MallinkException(ErrorCode.COUPON_STOCK_ERR.getCode(), e.getMessage()); | |||
| } | |||
| } | |||
| int payment = coupon.getSalePrice(); | |||
| @@ -112,43 +112,24 @@ public class RedisLock { | |||
| * 原子性增加 | |||
| */ | |||
| public long increase(String key, long delta) { | |||
| try { | |||
| return stringRedisTemplate.opsForValue().increment(key, delta); | |||
| }catch(Exception e) { | |||
| logger.error("[Redis分布式锁] increase error,{}",e); | |||
| } | |||
| return 0; | |||
| return stringRedisTemplate.opsForValue().increment(key, delta); | |||
| } | |||
| /** | |||
| * 原子性减少 | |||
| */ | |||
| public long decrease(String key, long delta) { | |||
| try { | |||
| return stringRedisTemplate.opsForValue().decrement(key, delta); | |||
| }catch(Exception e) { | |||
| logger.error("[Redis分布式锁] decrease error,{}",e); | |||
| } | |||
| return 0; | |||
| return stringRedisTemplate.opsForValue().decrement(key, delta); | |||
| } | |||
| public long getCouponStock(long couponId) { | |||
| try { | |||
| String longstr = stringRedisTemplate.opsForValue().get(EnumCacheKey.COUPON_STOCK.getMessage()+String.valueOf(couponId)); | |||
| return Long.parseLong(longstr); | |||
| }catch (Exception e) { | |||
| logger.error("[Redis分布式锁] getCouponStock error,{}",e); | |||
| } | |||
| return 0; | |||
| String longstr = stringRedisTemplate.opsForValue().get(EnumCacheKey.COUPON_STOCK.getMessage()+String.valueOf(couponId)); | |||
| return Long.parseLong(longstr); | |||
| } | |||
| public void setCouponStock(long couponId,long number) { | |||
| try { | |||
| stringRedisTemplate.opsForValue().set(EnumCacheKey.COUPON_STOCK.getMessage()+String.valueOf(couponId), String.valueOf(number)); | |||
| }catch(Exception e) { | |||
| logger.error("[Redis分布式锁] setCouponStock error,{}",e); | |||
| } | |||
| stringRedisTemplate.opsForValue().set(EnumCacheKey.COUPON_STOCK.getMessage()+String.valueOf(couponId), String.valueOf(number)); | |||
| } | |||
| public boolean hasCouponStockCache(long couponId) { | |||
| @@ -3,7 +3,7 @@ spring: | |||
| include: rabbitMQ | |||
| # JDBC | |||
| datasource: | |||
| url: jdbc:mysql://rm-2zel9i9t555zy7lft.mysql.rds.aliyuncs.com:3306/mallink?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useUnicode=true&useSSL=false&useAffectedRows=true | |||
| url: jdbc:mysql://zc349w82qvn56ftl5e64-rw4rm.rwlb.rds.aliyuncs.com:3306/mallink?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useUnicode=true&useSSL=false&useAffectedRows=true | |||
| username: ENC(dZ8fmrtuBMQYaRytKQgTqg==) | |||
| password: ENC(IKH7HxMZwIqMttMc9+QsqWa1KMsJvTs4) | |||
| type: com.alibaba.druid.pool.DruidDataSource | |||
| @@ -87,12 +87,12 @@ wechat: | |||
| secret: "c689fabf3c4c9f5b6424ff2a36a26727" | |||
| url: "https://mall.youlane.cn" | |||
| open: | |||
| componentAppId: "wx897e4673286c915d" | |||
| componentSecret: "cdfdfda65c45689beb6766c4c427eed2" | |||
| componentAppId: "wxdfc8fb4e62d6b52b" | |||
| componentSecret: "98daa62b316dd6feabaad708327ce233" | |||
| componentToken: "formall2018" | |||
| componentAesKey: "htKq8EjBMPNndfZQK9JiFojFaqFwFpw42VfeWFtx7HN" | |||
| redis: | |||
| host: 202.165.179.86 | |||
| host: 101.201.103.81 | |||
| port: 6379 | |||
| password: ENC(xPFDlgd6v8zUhJMbcKc0KmmQiqs9qHtk) | |||
| timeout: 3600 | |||
| @@ -86,8 +86,8 @@ aws: | |||
| wechat: | |||
| open: | |||
| componentAppId: "wx897e4673286c915d" | |||
| componentSecret: "cdfdfda65c45689beb6766c4c427eed2" | |||
| componentAppId: "wxdfc8fb4e62d6b52b" | |||
| componentSecret: "98daa62b316dd6feabaad708327ce233" | |||
| componentToken: "formall2018" | |||
| componentAesKey: "htKq8EjBMPNndfZQK9JiFojFaqFwFpw42VfeWFtx7HN" | |||
| redis: | |||