Commit 3214272f authored by gaoyingwei's avatar gaoyingwei

添加 发布活动、活动下单、订单模块

parent 10a099b4
......@@ -57,6 +57,12 @@ spring:
max-attempts: 3 #重试次数
max-interval: 15000ms #重试最大时间间隔
multiplier: 2 #倍数
orderActivityExchange: ${cy_rabbitMq.orderActivityExchange}
orderActivityDelayExchange: ${cy_rabbitMq.orderActivityDelayExchange}
orderActivityAddQueue: ${cy_rabbitMq.orderActivityAddQueue}
orderActivityStatusQueue: ${cy_rabbitMq.orderActivityStatusQueue}
orderActivityCloseQueue: ${cy_rabbitMq.orderActivityCloseQueue}
orderActivityCloseDelayQueue: ${cy_rabbitMq.orderActivityCloseDelayQueue}
# 2. redis ------
# redis:
# host: ${cy_redis.ip}
......
......@@ -11,6 +11,12 @@ cy_rabbitMq:
port: 5677
username: mq
password: mq
orderActivityExchange: orderActivityExchange
orderActivityDelayExchange: orderActivityDelayExchange
orderActivityAddQueue: orderActivityAddQueue
orderActivityCloseQueue: orderActivityCloseQueue
orderActivityCloseDelayQueue: orderActivityCloseDelayQueue
orderActivityStatusQueue: orderActivityStatusQueue
# 3. rocketMq 使用 ; 分隔
cy_rocketMq:
......
......@@ -3,6 +3,15 @@ wx:
appId: wxf16fd3cfcd958706
secret: 6583a162408deebcba7ce43bff7d47dd
timeOut: 3600
pay:
# 支付请求回调地址
notifyUrl: https://qf.91isoft.com/lh/app/wxPay/notifyCallBack
notifyRefundUrl: https://qf.91isoft.com/lh/app/wxPay/notifyRefundCallBack
# 微信商户号
mchId: 1615816319
# 微信支付的商户密钥
key: b90d421495604c33a943bb9be12d28c0
certPath: /working/file/config/certs/apiclient_cert.p12
jwt:
header: Authorization
secret: mySecret
......
......@@ -157,8 +157,18 @@
<artifactId>metadata-extractor</artifactId>
<version>2.14.0</version>
</dependency>
<!-- redisson -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.20.0</version>
</dependency>
<!-- wxpay -->
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
</dependencies>
<build>
......
package org.rcisoft.app.appOrder.controller;
/*固定导入*/
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.drew.imaging.ImageMetadataReader;
import com.drew.metadata.Metadata;
import com.drew.metadata.exif.ExifIFD0Directory;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.media.Schema;
import org.jdom.JDOMException;
import org.rcisoft.business.cmsOrder.entity.CmsOrder;
import org.rcisoft.business.cmsOrder.service.CmsOrderService;
import org.rcisoft.business.memInfo.entity.MemInfo;
import org.rcisoft.business.memInfo.service.MemInfoService;
import org.rcisoft.core.anno.CyEncryptSm4Anno;
import org.rcisoft.core.anno.CyOpeLogAnno;
import org.rcisoft.core.component.CyGlobal;
import org.rcisoft.core.constant.CyMessCons;
import org.rcisoft.core.controller.CyPaginationController;
import org.rcisoft.core.exception.CyServiceException;
import org.rcisoft.core.model.CyGridModel;
import org.rcisoft.core.model.CyPersistModel;
import org.rcisoft.core.operlog.enums.CyLogTypeEnum;
import org.rcisoft.core.result.CyResult;
import org.rcisoft.core.result.enums.CyResSysExcEnum;
import org.rcisoft.core.service.CyFileStorageService;
import org.rcisoft.core.util.CyResultGenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import javax.validation.Valid;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
/**
* Created by cy on 2024年12月20日 下午3:35:34.
*/
@RestController
@RequestMapping("/app")
public class AppOrderController extends CyPaginationController<CmsOrder> {
@Autowired
private CmsOrderService cmsOrderServiceImpl;
@CyOpeLogAnno(title = "system-订单信息表管理-活动下单", businessType = CyLogTypeEnum.INSERT)
@Operation(summary="活动下单", description="活动下单")
@PostMapping(value = "/order/add")
public CyResult add(@Valid CmsOrder cmsOrder, BindingResult bindingResult) {
CyPersistModel data = cmsOrderServiceImpl.persist(cmsOrder);
return CyResultGenUtil.builder(data,
CyMessCons.MESSAGE_ALERT_SUCCESS,
CyMessCons.MESSAGE_ALERT_ERROR,
cmsOrder);
}
@CyOpeLogAnno(title = "system-订单管理-活动取消", businessType = CyLogTypeEnum.UPDATE)
@Operation(summary = "活动取消", description = "活动取消")
@PostMapping(value = "/order/cancel")
public CyResult cancel(@RequestBody CmsOrder orderInfo) {
return CyResultGenUtil.builder(new CyPersistModel(1),
CyMessCons.MESSAGE_ALERT_SUCCESS,
CyMessCons.MESSAGE_ALERT_ERROR,
cmsOrderServiceImpl.cancel(orderInfo));
}
@Operation(summary="查询会员我的订单列表", description="查询会员我的订单列表")
@GetMapping("/order/selectOrderUserByPagination")
public CyGridModel selectOrderUserByPagination(CmsOrder orderInfo)
{
cmsOrderServiceImpl.selectOrderUserByPagination(getPaginationUtility(), orderInfo);
return getGridModelResponse();
}
}
package org.rcisoft.app.login.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
......@@ -20,11 +21,13 @@ import org.rcisoft.core.jwt.util.CyJwtUtil;
import org.rcisoft.core.service.CyRedisService;
import org.rcisoft.core.util.CyAESUtils;
import org.rcisoft.core.util.CyUserUtil;
import org.rcisoft.core.util.RedisCons;
import org.rcisoft.sys.rbac.menu.dao.SysMenuRbacRepository;
import org.rcisoft.sys.rbac.menu.dto.SysMenuRbacDTO;
import org.rcisoft.sys.rbac.menu.entity.SysMenuRbac;
import org.rcisoft.sys.rbac.user.dao.SysUserRbacRepository;
import org.rcisoft.sys.rbac.user.entity.SysUserRbac;
import org.rcisoft.sys.wbac.user.entity.SysUser;
import org.rcisoft.tencent.cons.CyWxMiniCons;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
......@@ -317,6 +320,10 @@ public class WxMiniServiceImpl implements WxMiniService {
sysUserRbac.setNotDeleted();
sysUserRbac.setStart();
sysUserRbacRepository.insert(sysUserRbac);
//将会员信息存入redis
SysUser user = new SysUser();
BeanUtil.copyProperties(sysUserRbac, user);
cyRedisServiceImpl.set(RedisCons.MEMBER_INFO +":"+ sysUserRbac.getBusinessId(),user);
}
//2.1.2 openId 是否绑定 情况:用户旧的微信注销了,更换了微信,但是绑定的手机号都是相同的
else if (StringUtils.isNotEmpty(sysUserRbac.getWxOpenid()) && !sysUserRbac.getWxOpenid().equals(openId)) {
......
package org.rcisoft.app.pay.controller;
import lombok.extern.slf4j.Slf4j;
import org.jdom.JDOMException;
import org.rcisoft.app.pay.service.WxPayService;
import org.rcisoft.business.cmsOrder.dto.OrderActivityDto;
import org.rcisoft.business.cmsOrder.entity.CmsOrder;
import org.rcisoft.core.constant.CyMessCons;
import org.rcisoft.core.jwt.util.CyJwtUtil;
import org.rcisoft.core.model.CyPersistModel;
import org.rcisoft.core.result.CyResult;
import org.rcisoft.core.util.CyResultGenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;
/**
* @author cy
* Created by cy on 21/5/10.
* @descript
*/
@RestController
@RequestMapping("/app/wxPay")
@Slf4j
public class WxPayController {
@Autowired
private WxPayService wxPayService;
@Autowired
private CyJwtUtil cyJwtUtil;
/**
* 创建微信预支付订单
*
* @return
*/
@PostMapping("/pay")
public Map<String, Object> pay(HttpServletRequest request,@RequestBody OrderActivityDto orderActivityDto) throws IOException, JDOMException {
return wxPayService.wxPay(orderActivityDto.getOrderId(), orderActivityDto.getActivityId(), request);
}
/**
* 小程序调用wx.requestPayment(OBJECT)发起微信支付成功后更新订单状态
*
* @return
*/
@PostMapping("/updateOrderStatus")
public CyResult updateOrderStatus(@RequestBody OrderActivityDto orderActivityDto) {
CyPersistModel data = wxPayService.updateOrderStatus(orderActivityDto.getOrderId(), orderActivityDto.getActivityId());
return CyResultGenUtil.builder(data,
CyMessCons.MESSAGE_ALERT_SUCCESS,
CyMessCons.MESSAGE_ALERT_ERROR,
data);
}
//微信异步回调通知支付
@RequestMapping("/notifyCallBack")
@ResponseBody
public void notifyCallBack(HttpServletRequest request, HttpServletResponse response) throws IOException, JDOMException {
wxPayService.wxNotify(request,response);
}
//微信异步回调通知退款
@RequestMapping("/notifyRefundCallBack")
@ResponseBody
public void notifyRefundCallBack(HttpServletRequest request, HttpServletResponse response) throws Exception {
wxPayService.notifyRefundCallBack(request,response);
}
@PostMapping("/test")
public CyResult test(@RequestBody CmsOrder orderInfo) {
String data = wxPayService.refundOrder(orderInfo);
return CyResultGenUtil.builder(new CyPersistModel(1),
CyMessCons.MESSAGE_ALERT_SUCCESS,
CyMessCons.MESSAGE_ALERT_ERROR,
data);
}
}
package org.rcisoft.app.pay.service;
import com.alibaba.fastjson.JSONObject;
import org.jdom.JDOMException;
import org.rcisoft.business.cmsOrder.entity.CmsOrder;
import org.rcisoft.core.model.CyPersistModel;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Created with family.
* author: cy
* Date: 2021/5/10
* Time: 3:41 PM
* description:
*/
public interface WxPayService {
JSONObject wxPay(Long orderId, Long activityId, HttpServletRequest request) throws IOException, JDOMException;
void wxNotify(HttpServletRequest request, HttpServletResponse response) throws IOException, JDOMException;
void notifyRefundCallBack(HttpServletRequest request, HttpServletResponse response) throws Exception;
/**
* 小程序调用wx.requestPayment(OBJECT)发起微信支付成功后更新订单状态
* @param orderId
* @param activityId
* @param request
* @return
*/
CyPersistModel updateOrderStatus(Long orderId, Long activityId);
//主动查询微信订单状态
String selectWxOrderStatus(String orderNo) throws IOException, JDOMException;
//申请退款
String refundOrder(CmsOrder orderNo);
//主动查询微信订单退款状态
String selectWxOrderRefundStatus(String transactionId) throws IOException, JDOMException;
}
......@@ -143,4 +143,16 @@ public class CmsActivityController extends CyPaginationController<CmsActivity> {
List<CmsActivity> cmsActivityList = cmsActivityServiceImpl.export(cmsActivity);
CyEpExcelUtil.exportExcel(cmsActivityList, "活动信息", "活动信息", CmsActivity.class, excelName, response);
}
@PreAuthorize("@cyPerm.hasPerm('cms:activity:pushActivityInfo')")
@CyOpeLogAnno(title = "system-活动管理-发布/取消活动", businessType = CyLogTypeEnum.UPDATE)
@Operation(summary = "发布/取消活动", description = "发布/取消活动")
@PutMapping("/pushActivityInfo")
public CyResult pushActivityInfo(@RequestParam Long businessId, @RequestParam String status) {
CyPersistModel data = cmsActivityServiceImpl.pushActivityInfo(businessId, status);
return CyResultGenUtil.builder(data,
CyMessCons.MESSAGE_ALERT_SUCCESS,
CyMessCons.MESSAGE_ALERT_ERROR,
businessId);
}
}
......@@ -67,4 +67,11 @@ public interface CmsActivityService {
*/
CyPersistModel updateStatus(CmsActivity cmsActivity);
/**
* 发布、取消发布活动
*
* @return 结果
*/
CyPersistModel pushActivityInfo(Long businessId, String status);
}
......@@ -2,6 +2,7 @@ package org.rcisoft.business.cmsActivity.service.impl;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.rcisoft.business.cmsActivity.dao.CmsActivityRepository;
......@@ -11,14 +12,24 @@ import org.rcisoft.common.component.Global;
import org.rcisoft.core.exception.CyServiceException;
import org.rcisoft.core.model.CyPageInfo;
import org.rcisoft.core.model.CyPersistModel;
import org.rcisoft.core.service.CyRedisService;
import org.rcisoft.core.util.CyUserUtil;
import org.rcisoft.core.util.RedisCons;
import org.rcisoft.core.util.TimeUtil;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* @author cy
......@@ -31,8 +42,12 @@ public class CmsActivityServiceImpl extends ServiceImpl<CmsActivityRepository, C
@Autowired
private Global global;
@Autowired(required = false)
private CyRedisService cyRedisServiceImpl;
@Autowired
private RedissonClient redissonClient;
@Autowired
private RedisTemplate redisTemplate;
/**
* 保存 活动
*
......@@ -161,4 +176,64 @@ public class CmsActivityServiceImpl extends ServiceImpl<CmsActivityRepository, C
return new CyPersistModel(line);
}
/**
* 修改活动
*
* @return 结果
*/
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT)
@Override
public CyPersistModel pushActivityInfo(Long businessId,String status)
{
CmsActivity info = baseMapper.selectById(businessId);
int line = 0;
//如果是发布操作,需要校验
if ("1".equals(status)){
if ("1".equals(info.getPublishStatus()))
throw new CyServiceException("活动不是未发布状态,不能发布");
info.setUpdateDate(new Date());
info.setUpdateBy(CyUserUtil.getAuthenBusinessId());
info.setPublishDate(new Date());
info.setPublishStatus(status);
line = baseMapper.updateById(info);
Date endTime = TimeUtil.getTime(info.getEndTime(), Calendar.DATE,1);
//将活动信息插入redis
long time = TimeUtil.getTimeSecond(new Date(),endTime);
cyRedisServiceImpl.set(RedisCons.ACTIVITY_DETAIL +":"+ businessId,info,time);
cyRedisServiceImpl.set(RedisCons.ACTIVITY_COUNT +":"+ businessId,info.getMaxApplicationCount(),time);
} else {
//如果取消发布,加redis锁
boolean isGetLock = false;
RLock lock = redissonClient.getLock(RedisCons.ACTIVITY_INFO + businessId);
try {
isGetLock = lock.tryLock(Long.parseLong(RedisCons.ORDER_INFO_LOCK_WAIT_TIME),
Long.parseLong(RedisCons.ORDER_INFO_LOCK_LEASE_TIME), TimeUnit.SECONDS);
if (isGetLock) {
//校验活动是否已经报名,状态是否为发布
extracted(businessId, info);
info.setUpdateDate(new Date());
info.setUpdateBy(CyUserUtil.getAuthenBusinessId());
info.setPublishStatus(status);
line = baseMapper.updateById(info);
cyRedisServiceImpl.del(RedisCons.ACTIVITY_DETAIL +":"+ businessId);
cyRedisServiceImpl.del(RedisCons.ACTIVITY_COUNT +":"+ businessId);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
isGetLock = false;
} finally {
lock.unlock();
log.error("释放成功");
}
}
return new CyPersistModel(line);
}
private void extracted(Long businessId, CmsActivity info) {
Set<String> map = redisTemplate.keys(RedisCons.ORDER_ACTIVITY + ":" + businessId + "*");
if (CollectionUtils.isNotEmpty(map)) //报名人数和实际剩余报名人数不等
throw new CyServiceException("活动已经报名,不允许取消发布");
if ("0".equals(info.getPublishStatus()))
throw new CyServiceException("活动未发布,不能取消");
}
}
package org.rcisoft.business.cmsActivity.service.impl;
import cn.hutool.core.lang.Assert;
import org.rcisoft.core.util.IStockCallback;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* 扣库存
*
*/
@Service
public class StockService {
Logger logger = LoggerFactory.getLogger(StockService.class);
@Autowired
private RedissonClient redissonClient;
/**
* 不限库存
*/
public static final long UNINITIALIZED_STOCK = -3L;
/**
* Redis 客户端
*/
@Autowired
private RedisTemplate redisTemplate;
/**
* 执行扣库存的脚本
*/
public static final String STOCK_LUA;
@Value("${spring.data.redis.host}")
private String redisIP;
@Value("${spring.data.redis.port}")
private String redisPort;
static {
/**
*
* @desc 扣减库存Lua脚本
* 库存(stock)-1:表示不限库存
* 库存(stock)0:表示没有库存
* 库存(stock)大于0:表示剩余库存
*
* @params 库存key
* @return
* -3:库存未初始化
* -2:库存不足
* -1:不限库存
* 大于等于0:剩余库存(扣减之后剩余的库存)
* redis缓存的库存(value)是-1表示不限库存,直接返回1
*/
StringBuilder sb = new StringBuilder();
sb.append("if (redis.call('exists', KEYS[1]) == 1) then");
sb.append(" local stock = tonumber(redis.call('get', KEYS[1]));");
sb.append(" local num = tonumber(ARGV[1]);");
sb.append(" if (stock == -1) then");
sb.append(" return -1;");
sb.append(" end;");
sb.append(" if (stock >= num) then");
sb.append(" return redis.call('incrby', KEYS[1], 0 - num);");
sb.append(" end;");
sb.append(" return -2;");
sb.append("end;");
sb.append("return -3;");
STOCK_LUA = sb.toString();
}
/**
* @param key 库存key
* @param expire 库存有效时间,单位秒
* @param num 扣减数量
* @param stockCallback 初始化库存回调函数
* @return -2:库存不足; -1:不限库存; 大于等于0:扣减库存之后的剩余库存
*/
public long stock(String key, long expire, int num, IStockCallback stockCallback) {
long stock = stock(key, num);
// 初始化库存
if (stock == UNINITIALIZED_STOCK) {
RLock redisLock = redissonClient.getLock(key);
try {
// 获取锁
if (redisLock.tryLock()) {
// 双重验证,避免并发时重复回源到数据库
stock = stock(key, num);
if (stock == UNINITIALIZED_STOCK) {
// 获取初始化库存
final int initStock = stockCallback.getStock();
// 将库存设置到redis
redisTemplate.opsForValue().set(key, initStock, expire, TimeUnit.SECONDS);
// 调一次扣库存的操作
stock = stock(key, num);
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
} finally {
redisLock.unlock();
}
}
return stock;
}
/**
* 加库存(还原库存)
*
* @param key 库存key
* @param num 库存数量
* @return
*/
public long addStock(String key, int num) {
return addStock(key, null, num);
}
/**
* 加库存
*
* @param key 库存key
* @param expire 过期时间(秒)
* @param num 库存数量
* @return
*/
public long addStock(String key, Long expire, int num) {
boolean hasKey = redisTemplate.hasKey(key);
// 判断key是否存在,存在就直接更新
if (hasKey) {
redisTemplate.opsForValue().increment(key, num);
return num;
}
Assert.notNull(expire,"初始化库存失败,库存过期时间不能为null");
RLock redisLock = redissonClient.getLock(key);
try {
if (redisLock.tryLock()) {
// 获取到锁后再次判断一下是否有key
hasKey = redisTemplate.hasKey(key);
if (!hasKey) {
// 初始化库存
redisTemplate.opsForValue().set(key, num, expire, TimeUnit.SECONDS);
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
} finally {
redisLock.unlock();
}
return num;
}
/**
* 获取库存
*
* @param key 库存key
* @return -1:不限库存; 大于等于0:剩余库存
*/
public int getStock(String key) {
Integer stock = (Integer) redisTemplate.opsForValue().get(key);
return stock == null ? -1 : stock;
}
/**
* 扣库存
*
* @param key 库存key
* @param num 扣减库存数量
* @return 扣减之后剩余的库存【-3:库存未初始化; -2:库存不足; -1:不限库存; 大于等于0:扣减库存之后的剩余库存】
*/
private Long stock(String key, int num) {
// 脚本里的KEYS参数
List<String> keys = new ArrayList<>();
keys.add(key);
// 脚本里的ARGV参数
List<String> args = new ArrayList<>();
args.add(Integer.toString(num));
long result = UNINITIALIZED_STOCK;
try (JedisPool jedisPool = new JedisPool(redisIP, Integer.parseInt(redisPort));){
Jedis jedis = jedisPool.getResource();
result = (long) jedis.evalsha(jedis.scriptLoad(STOCK_LUA), keys , args);
} catch (Exception e){
logger.error(e.getMessage(),e);
}
logger.info("扣减之后剩余的库存:{}" , result);
return result;
}
}
......@@ -9,7 +9,7 @@ import org.rcisoft.business.cmsApplication.service.CmsApplicationService;
import org.rcisoft.common.component.Global;
import org.rcisoft.core.model.CyPageInfo;
import org.rcisoft.core.model.CyPersistModel;
import org.rcisoft.core.util.CyUserUtil;
import org.rcisoft.core.util.*;
import org.rcisoft.sys.wbac.user.dao.SysUserRepository;
import org.rcisoft.sys.wbac.user.entity.SysUser;
import org.springframework.beans.factory.annotation.Autowired;
......
package org.rcisoft.business.cmsOrder.controller;
/*固定导入*/
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.Operation;
import org.jdom.JDOMException;
import org.rcisoft.core.anno.CyOpeLogAnno;
import org.rcisoft.core.operlog.enums.CyLogTypeEnum;
import org.rcisoft.core.util.CyEpExcelUtil;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.BindingResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.rcisoft.core.result.CyResult;
import org.rcisoft.core.util.CyResultGenUtil;
import org.rcisoft.core.model.CyPersistModel;
import org.rcisoft.core.constant.CyMessCons;
import org.rcisoft.core.controller.CyPaginationController;
import org.rcisoft.core.util.CyUserUtil;
import org.rcisoft.core.model.CyGridModel;
import org.rcisoft.core.exception.CyServiceException;
import jakarta.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import org.rcisoft.business.cmsOrder.entity.CmsOrder;
import org.rcisoft.business.cmsOrder.service.CmsOrderService;
import java.io.IOException;
import java.util.List;
/**
* Created by cy on 2025年1月6日 下午1:44:44.
*/
@RestController
@RequestMapping("/cmsOrder")
public class CmsOrderController extends CyPaginationController<CmsOrder> {
@Autowired
private CmsOrderService cmsOrderServiceImpl;
//@PreAuthorize("@cyPerm.hasPerm('sys:order:add')")
// @CyOpeLogAnno(title = "system-订单信息表管理-新增订单信息表", businessType = CyLogTypeEnum.INSERT)
// @Operation(summary="添加订单信息表", description="添加订单信息表")
// @PostMapping(value = "/add")
// public CyResult add(@Valid CmsOrder cmsOrder, BindingResult bindingResult) {
// CyPersistModel data = cmsOrderServiceImpl.persist(cmsOrder);
// return CyResultGenUtil.builder(data,
// CyMessCons.MESSAGE_ALERT_SUCCESS,
// CyMessCons.MESSAGE_ALERT_ERROR,
// cmsOrder);
// }
@PreAuthorize("@cyPerm.hasPerm('sys:order:delete')")
@CyOpeLogAnno(title = "system-订单信息表管理-删除订单信息表", businessType = CyLogTypeEnum.DELETE)
@Operation(summary="逻辑删除订单信息表", description="逻辑删除订单信息表")
@Parameters({@Parameter(name = "businessId", description = "businessId", required = true)})
@DeleteMapping("/deleteLogical/{businessId:\\w+}")
public CyResult deleteLogical(@PathVariable Long businessId,CmsOrder cmsOrder) {
cmsOrder.setBusinessId(businessId);
CyPersistModel data = cmsOrderServiceImpl.removeLogical(cmsOrder);
return CyResultGenUtil.builder(data,
CyMessCons.MESSAGE_ALERT_SUCCESS,
CyMessCons.MESSAGE_ALERT_ERROR,
businessId);
}
@PreAuthorize("@cyPerm.hasPerm('sys:order:delete')")
@CyOpeLogAnno(title = "system-订单信息表管理-删除订单信息表", businessType = CyLogTypeEnum.DELETE)
@Operation(summary="删除订单信息表", description="删除订单信息表")
@Parameters({@Parameter(name = "businessId", description = "businessId", required = true)})
@DeleteMapping("/delete/{businessId:\\w+}")
public CyResult delete(@PathVariable Long businessId,CmsOrder cmsOrder) {
cmsOrder.setBusinessId(businessId);
CyPersistModel data = cmsOrderServiceImpl.remove(cmsOrder);
return CyResultGenUtil.builder(data,
CyMessCons.MESSAGE_ALERT_SUCCESS,
CyMessCons.MESSAGE_ALERT_ERROR,
businessId);
}
@PreAuthorize("@cyPerm.hasPerm('sys:order:update')")
@CyOpeLogAnno(title = "system-订单信息表管理-修改订单信息表", businessType = CyLogTypeEnum.UPDATE)
@Operation(summary="修改订单信息表", description="修改订单信息表")
@Parameters({@Parameter(name = "businessId", description = "businessId", required = false)})
@PutMapping("/update/{businessId:\\w+}")
public CyResult update(@PathVariable Long businessId, @Valid CmsOrder cmsOrder, BindingResult bindingResult) {
cmsOrder.setBusinessId(businessId);
CyPersistModel data = cmsOrderServiceImpl.merge(cmsOrder);
return CyResultGenUtil.builder(data,
CyMessCons.MESSAGE_ALERT_SUCCESS,
CyMessCons.MESSAGE_ALERT_ERROR,
cmsOrder);
}
@PreAuthorize("@cyPerm.hasPerm('sys:order:query')")
@CyOpeLogAnno(title = "system-订单信息表管理-查询订单信息表", businessType = CyLogTypeEnum.QUERY)
@Operation(summary="查询单一订单信息表", description="查询单一订单信息表")
@Parameters({@Parameter(name = "businessId", description = "businessId", required = true)})
@GetMapping("/detail/{businessId:\\w+}")
public CyResult detail(@PathVariable String businessId) {
return CyResultGenUtil.builder(new CyPersistModel(1),
CyMessCons.MESSAGE_ALERT_SUCCESS,
CyMessCons.MESSAGE_ALERT_ERROR,
cmsOrderServiceImpl.findById(businessId));
}
// @PreAuthorize("@cyPerm.hasPerm('sys:order:list')")
@CyOpeLogAnno(title = "system-订单信息表管理-查询订单信息表", businessType = CyLogTypeEnum.QUERY)
@Operation(summary="查询订单信息表集合", description="查询订单信息表集合")
@GetMapping(value = "/listAll")
public CyResult listAll(CmsOrder cmsOrder) {
return CyResultGenUtil.builder(new CyPersistModel(1),
CyMessCons.MESSAGE_ALERT_SUCCESS,
CyMessCons.MESSAGE_ALERT_ERROR,
cmsOrderServiceImpl.findAll(cmsOrder));
}
@PreAuthorize("@cyPerm.hasPerm('sys:order:list')")
@CyOpeLogAnno(title = "system-订单信息表管理-查询订单信息表", businessType = CyLogTypeEnum.QUERY)
@Operation(summary="分页查询订单信息表集合", description="分页查询订单信息表集合")
@GetMapping(value = "/list")
public CyGridModel listByPagination(CmsOrder cmsOrder) {
cmsOrderServiceImpl.findAllByPagination(getPaginationUtility(), cmsOrder);
return getGridModelResponse();
}
@CyOpeLogAnno(title = "system-订单信息表管理-查询订单信息表", businessType = CyLogTypeEnum.EXPORT)
@Operation(summary = "导出订单信息表信息", description = "导出订单信息表信息")
@GetMapping(value = "/export")
public void outCmsOrder(HttpServletResponse response,CmsOrder cmsOrder,@PathVariable @RequestParam(defaultValue = "0") String excelId) {
String excelName="";
switch(excelId){
case "0": excelName="订单信息表信息.xls";break;
case "1": excelName="订单信息表信息.xlsx";break;
case "2": excelName="订单信息表信息.csv";break;
}
List<CmsOrder> cmsOrderList = cmsOrderServiceImpl.export(cmsOrder);
CyEpExcelUtil.exportExcel(cmsOrderList, "订单信息表信息", "订单信息表信息", CmsOrder.class, excelName, response);
}
@CyOpeLogAnno(title = "system-订单管理-退款确认", businessType = CyLogTypeEnum.UPDATE)
@Operation(summary = "退款确认", description = "退款确认")
@PostMapping(value = "/order/refundConfirm")
public CyResult refundConfirm(@RequestBody CmsOrder orderInfo) throws IOException, JDOMException {
return CyResultGenUtil.builder(new CyPersistModel(1),
CyMessCons.MESSAGE_ALERT_SUCCESS,
CyMessCons.MESSAGE_ALERT_ERROR,
cmsOrderServiceImpl.refundConfirm(orderInfo));
}
@CyOpeLogAnno(title = "system-订单管理-支付确认", businessType = CyLogTypeEnum.UPDATE)
@Operation(summary = "支付确认", description = "支付确认")
@PostMapping(value = "/order/payConfirm")
public CyResult payConfirm(@RequestBody CmsOrder orderInfo)throws IOException, JDOMException {
return CyResultGenUtil.builder(new CyPersistModel(1),
CyMessCons.MESSAGE_ALERT_SUCCESS,
CyMessCons.MESSAGE_ALERT_ERROR,
cmsOrderServiceImpl.payConfirm(orderInfo));
}
@CyOpeLogAnno(title = "system-订单管理-活动退款补偿", businessType = CyLogTypeEnum.UPDATE)
@Operation(summary = "活动退款补偿", description = "活动退款补偿")
@GetMapping(value = "/refundReimbursement")
public CyResult refundReimbursement(@RequestParam List<Long> ids) {
return CyResultGenUtil.builder(new CyPersistModel(1),
CyMessCons.MESSAGE_ALERT_SUCCESS,
CyMessCons.MESSAGE_ALERT_ERROR,
cmsOrderServiceImpl.refundReimbursement(ids));
}
/**
* 查询异常订单[根据搜索条件,时间范围跨度3个月,时间最早支持30天前)
*/
@Operation(summary="查询异常订单列表", description="查询异常订单列表")
@GetMapping("/selectErrorOrderByPagination")
public CyGridModel selectErrorOrderByPagination(CmsOrder orderInfo)
{
cmsOrderServiceImpl.selectErrorOrderByPagination(getPaginationUtility(), orderInfo);
return getGridModelResponse();
}
@CyOpeLogAnno(title = "system-订单管理-异常订单手动补偿", businessType = CyLogTypeEnum.UPDATE)
@Operation(summary = "异常订单手动补偿", description = "异常订单手动补偿")
@PostMapping(value = "/manualCompensateOrder")
public CyResult manualCompensateOrder(@RequestBody CmsOrder dto) {
return CyResultGenUtil.builder(new CyPersistModel(1),
CyMessCons.MESSAGE_ALERT_SUCCESS,
CyMessCons.MESSAGE_ALERT_ERROR,
cmsOrderServiceImpl.manualCompensateOrder(dto));
}
}
package org.rcisoft.business.cmsOrder.dao;
import org.rcisoft.core.mapper.CyBaseMapper;
import org.rcisoft.business.cmsOrder.entity.CmsOrder;
import org.apache.ibatis.annotations.ResultMap;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;
import org.rcisoft.core.model.CyPageInfo;
import org.apache.ibatis.annotations.Param;
import com.baomidou.mybatisplus.core.metadata.IPage;
import java.util.List;
/**
* Created with cy on 2025年1月6日 下午1:44:44.
*/
public interface CmsOrderRepository extends CyBaseMapper<CmsOrder> {
List<CmsOrder> queryCmsOrders(@Param("entity") CmsOrder cmsOrder);
/**
* 分页查询 cmsOrder
*
*/
IPage<CmsOrder> queryCmsOrdersPaged(CyPageInfo cyPageInfo,@Param("entity") CmsOrder cmsOrder);
/**
* 查询会员我的订单列表
*
* @param orderInfo 订单
* @return 订单集合
*/
List<CmsOrder> queryOrderUserList(@Param("entity")CmsOrder orderInfo);
/**
* 根据id查询订单其他信息
*
* @return 订单集合
*/
List<CmsOrder> queryOrderInfoByIds(@Param("list") List<CmsOrder> list);
}
package org.rcisoft.business.cmsOrder.dto;
import lombok.Data;
@Data
public class OrderActivityDto {
private static final long serialVersionUID = 1L;
/** 订单id */
private Long orderId;
/** 活动id */
private Long activityId;
}
package org.rcisoft.business.cmsOrder.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.rcisoft.business.cmsOrder.dto.OrderActivityDto;
import org.rcisoft.core.entity.CyIdSnowflakeEntity;
import org.springframework.data.annotation.Transient;
import org.springframework.format.annotation.DateTimeFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.baomidou.mybatisplus.annotation.TableField;
import cn.afterturn.easypoi.excel.annotation.Excel;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import cn.afterturn.easypoi.excel.annotation.Excel;
import org.rcisoft.core.entity.CyIdEntity;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import com.baomidou.mybatisplus.annotation.TableName;
/**
* Created with cy on 2025年1月6日 下午1:44:44.
*/
@Data
@TableName("cms_order")
public class CmsOrder extends CyIdSnowflakeEntity<CmsOrder> {
/**
* @desc 订单名称
* @column name
* @default
*/
@Excel(name = "订单名称", orderNum = "0", width = 20)
private String name;
/**
* @desc 商品id
* @column goods_id
* @default
*/
@Excel(name = "商品id", orderNum = "1", width = 20)
private Integer goodsId;
/**
* @desc 会员id
* @column user_id
* @default
*/
@Excel(name = "会员id", orderNum = "2", width = 20)
private Integer userId;
/**
* @desc 会员账号
* @column account
* @default
*/
@Excel(name = "会员账号", orderNum = "3", width = 20)
private String account;
/**
* @desc 购买数量
* @column num
* @default
*/
@Excel(name = "购买数量", orderNum = "4", width = 20)
private Integer num;
/**
* @desc 总价
* @column price
* @default
*/
@Excel(name = "总价", orderNum = "5", width = 20)
private BigDecimal price;
/**
* @desc 支付金额
* @column pay_price
* @default
*/
@Excel(name = "支付金额", orderNum = "6", width = 20)
private BigDecimal payPrice;
/**
* @desc 订单类型
* @column type
* @default
*/
@Excel(name = "订单类型", orderNum = "7", width = 20)
private Integer type;
/**
* @desc 下单时间
* @column order_time
* @default
*/
@JsonFormat(
pattern = "yyyy-MM-dd"
)
@Excel(name = "下单时间", orderNum = "8", width = 20, format = "yyyy-MM-dd")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date orderTime;
/**
* @desc 微信支付订单号
* @column transaction_id
* @default
*/
@Excel(name = "微信支付订单号", orderNum = "9", width = 20)
private String transactionId;
/**
* @desc 退款时间
* @column refund_time
* @default
*/
@JsonFormat(
pattern = "yyyy-MM-dd"
)
@Excel(name = "退款时间", orderNum = "10", width = 20, format = "yyyy-MM-dd")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date refundTime;
/**
* @desc 退款次数
* @column refund_count
* @default
*/
@Excel(name = "退款次数", orderNum = "11", width = 20)
private Integer refundCount;
/**
* @desc 订单状态(0 待支付 1已取消 2退款中 3退款中 4后台退款中 5后台退款中 6退款完成 7后台退款完成 8支付中 9 支付完成 10订单关闭 11已核销)
* @column status
* @default
*/
@Excel(name = "订单状态(0 待支付 1已取消 2退款中 3退款中 4后台退款中 5后台退款中 6退款完成 7后台退款完成 8支付中 9 支付完成 10订单关闭 11已核销)", orderNum = "12", width = 20)
private Integer status;
/**
* @desc 核销商家id
* @column cancel_id
* @default
*/
@Excel(name = "核销商家id", orderNum = "13", width = 20)
private BigInteger cancelId;
/**
* @desc 核销时间
* @column cancel_time
* @default
*/
@JsonFormat(
pattern = "yyyy-MM-dd"
)
@Excel(name = "核销时间", orderNum = "14", width = 20, format = "yyyy-MM-dd")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date cancelTime;
/**
* @desc 创建时间
* @column create_time
* @default
*/
@JsonFormat(
pattern = "yyyy-MM-dd"
)
@Excel(name = "创建时间", orderNum = "15", width = 20, format = "yyyy-MM-dd")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date createTime;
/**
* @desc 更新时间
* @column update_time
* @default
*/
@JsonFormat(
pattern = "yyyy-MM-dd"
)
@Excel(name = "更新时间", orderNum = "16", width = 20, format = "yyyy-MM-dd")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date updateTime;
/**
* 开始时间
*/
@JsonIgnore
@TableField(exist = false)
private String beginTime;
/**
* 结束时间
*/
@JsonIgnore
@TableField(exist = false)
private String endTime;
//同步状态 0未同步 1已同步
@Transient
@TableField(exist = false)
private Integer state;
//后台人工退单字段
@Transient
@TableField(exist = false)
private Integer manualRefund;
//订单状态list
@Transient
@TableField(exist = false)
private List<Integer> statusList;
//活动图片
@Transient
@TableField(exist = false)
private String imgUrl;
//活动开始时间
@Transient
@TableField(exist = false)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date activityBeginDate;
@Transient
@TableField(exist = false)
private List<OrderActivityDto> dtos;
}
package org.rcisoft.business.cmsOrder.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.jdom.JDOMException;
import org.rcisoft.business.cmsOrder.entity.CmsOrder;
import org.rcisoft.business.memInfo.entity.MemInfo;
import org.rcisoft.core.model.CyPersistModel;
import org.rcisoft.core.aop.CyPageUtilAsp;
import org.rcisoft.core.model.CyPageInfo;
import java.io.IOException;
import java.util.List;
/**
* Created by cy on 2025年1月6日 下午1:44:44.
*/
public interface CmsOrderService {
/**
* 保存 订单信息表
* @param cmsOrder
* @return
*/
CyPersistModel persist(CmsOrder cmsOrder);
/**
* 删除 订单信息表
* @param cmsOrder
* @return
*/
CyPersistModel remove(CmsOrder cmsOrder);
/**
* 逻辑删除 订单信息表
* @param cmsOrder
* @return
*/
CyPersistModel removeLogical(CmsOrder cmsOrder);
/**
* 修改 订单信息表
* @param cmsOrder
* @return
*/
CyPersistModel merge(CmsOrder cmsOrder);
/**
* 根据id查询 订单信息表
* @param id
* @return
*/
CmsOrder findById(String id);
/**
* 分页查询 订单信息表
* @param cmsOrder
* @return
*/
IPage<CmsOrder> findAllByPagination(CyPageInfo<CmsOrder> paginationUtility,
CmsOrder cmsOrder);
/**
* 查询list 订单信息表
* @param cmsOrder
* @return
*/
List<CmsOrder> findAll(CmsOrder cmsOrder);
/**
* 导出订单信息表
* @return
*/
List<CmsOrder> export(CmsOrder cmsOrder);
/**
* 活动取消
* @param orderInfo
* @return
*/
int cancel(CmsOrder orderInfo);
/**
* 查询会员我的订单列表
*
* @param orderInfo 订单
* @return 订单集合
*/
public IPage<CmsOrder> selectOrderUserByPagination(CyPageInfo<CmsOrder> paginationUtility, CmsOrder orderInfo);
/**
* 退款确认
* @param orderInfo
* @return
*/
int refundConfirm(CmsOrder orderInfo) throws IOException, JDOMException;
/**
* 支付确认
* @param orderInfo
* @return
*/
int payConfirm(CmsOrder orderInfo)throws IOException, JDOMException;
/**
* 查询异常订单列表
*
* @param orderInfo 订单
* @return 订单集合
*/
public IPage<CmsOrder> selectErrorOrderByPagination(CyPageInfo<CmsOrder> paginationUtility, CmsOrder orderInfo);
/**
* 活动退款补偿
* @param ids
* @return
*/
int refundReimbursement(List<Long> ids);
/**
* 异常订单手动补偿
* @param dto
* @return
*/
int manualCompensateOrder(CmsOrder dto);
}
package org.rcisoft.core.async;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import lombok.NoArgsConstructor;
import org.rcisoft.app.pay.service.WxPayService;
import org.rcisoft.business.cmsActivity.dao.CmsActivityRepository;
import org.rcisoft.business.cmsActivity.entity.CmsActivity;
import org.rcisoft.business.cmsOrder.dao.CmsOrderRepository;
import org.rcisoft.business.cmsOrder.entity.CmsOrder;
import org.rcisoft.core.component.CySpringBeanComp;
import org.rcisoft.core.rabbitmq.bean.RabbitMQConfigBean;
import org.rcisoft.core.service.impl.CyRedisServiceImpl;
import org.rcisoft.core.util.RabbitClusterUtil;
import org.rcisoft.core.util.RedisCons;
import org.rcisoft.core.util.TimeUtil;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
/**
* 异步工厂(产生任务用)
*
* @author isoft
*/
@NoArgsConstructor
public class AsyncFactory
{
private static final Logger log = LoggerFactory.getLogger(AsyncFactory.class);
//加载redis优惠券数量
// public static TimerTask loadCouponCountRedis(final Long id) {
// return new TimerTask() {
// @Override
// public void run() {
// // 查询优惠券剩余数量,加载redis
// CouponInfo info = CySpringBeanComp.getBean(CouponInfoRepository.class).selectCouponInfoById(id);
// Integer count = CySpringBeanComp.getBean(CouponInfoRepository.class).selectCountById(id);
// Integer num = info.getNum() - count;
// CySpringBeanComp.getBean(CyRedisServiceImpl.class).set(RedisCons.COUPON_COUNT +":"+ id,num);
// }
// };
// }
//加载活动信息、数量
public static TimerTask loadActivityRedis(final Integer id) {
return new TimerTask() {
@Override
public void run() {
CmsActivity info = CySpringBeanComp.getBean(CmsActivityRepository.class).selectById(id);
//redis ttl 活动结束时间+1天
Date endTime = TimeUtil.getTime(info.getEndTime(), Calendar.DATE, 1);
//将活动信息插入redis
long time = TimeUtil.getTimeSecond(new Date(), endTime);
CySpringBeanComp.getBean(CyRedisServiceImpl.class).set(RedisCons.ACTIVITY_DETAIL + ":" + id, info, time);
// if (info.getIsRestrictions().equals(0)) {
AtomicReference<Integer> num = new AtomicReference<>(info.getMaxApplicationCount());
//已报名人数计算: 数据库+ redis【order:activity:${所有}】 value 【hash】未取消 的并集
QueryWrapper<CmsOrder> wrapper = new QueryWrapper<>();
wrapper.eq("activity_id", id);
wrapper.notIn("status", 1, 2, 3, 4, 5, 6, 7, 10);
wrapper.eq("del_flag", 0);
List<CmsOrder> orderList = CySpringBeanComp.getBean(CmsOrderRepository.class).selectList(wrapper);
for (CmsOrder orderInfo : orderList) {
num.set(num.get() - orderInfo.getNum());
}
List<Long> orderIds = orderList.stream().map(CmsOrder::getBusinessId).toList();
Set<String> map = CySpringBeanComp.getBean(RedisTemplate.class).keys(RedisCons.ORDER_ACTIVITY + ":" + id + "*");
if (CollectionUtils.isNotEmpty(map)) {
//遍历获取对应报名量
map.forEach(m -> {
Object detail = CySpringBeanComp.getBean(CyRedisServiceImpl.class).get(m);
CmsOrder order = JSON.parseObject(JSON.toJSONString(detail), CmsOrder.class);
if (!orderIds.contains(order.getBusinessId()))
num.set(num.get() - order.getNum());
});
}
CySpringBeanComp.getBean(CyRedisServiceImpl.class).set(RedisCons.ACTIVITY_COUNT + ":" + id, num.get(), time);
// } else {
// CySpringBeanComp.getBean(CyRedisServiceImpl.class).set(RedisCons.ACTIVITY_COUNT + ":" + id, -1, time);
// }
}
};
}
// //加载redis会员信息
// public static TimerTask loadMemberRedis(final Long id) {
// return new TimerTask() {
// @Override
// public void run() {
// // 查询会员信息,加载redis
// SysUser info = CySpringBeanComp.getBean(SysUserRepositorys.class).selectUserById(id);
// CySpringBeanComp.getBean(CyRedisServiceImpl.class).set(RedisCons.MEMBER_INFO +":"+ id,info);
// }
// };
// }
//
// //加载redis会员信息
// public static TimerTask loadBenefitsRedis(final Integer level) {
// return new TimerTask() {
// @Override
// public void run() {
// // 查询会员权益信息,加载redis
// MemberBenefits info = CySpringBeanComp.getBean(MemberBenefitsRepository.class).selectMemberBenefitsByLevel(level);
// CySpringBeanComp.getBean(CyRedisServiceImpl.class).set(RedisCons.BENEFITS_INFO +":"+ level,info);
// }
// };
// }
//加载redis用户优惠券信息
// public static TimerTask loadCouponUserRedis(final Long id) {
// return new TimerTask() {
// @Override
// public void run() {
// // 查询用户优惠券信息,加载redis
// UserCouponRelative info = CySpringBeanComp.getBean(CouponInfoRepository.class).selectUserCouponRelativeById(id);
// info.setBusinessList(CySpringBeanComp.getBean(CouponInfoRepository.class).selectBusinessIds(id));
// Date endTime = TimeUtil.getTime(info.getUseEndTime(), Calendar.DATE,1);
// long time = TimeUtil.getTimeSecond(new Date(),endTime);
// if (time > 0)
// CySpringBeanComp.getBean(CyRedisServiceImpl.class).set(RedisCons.COUPON_DETAIL +":"+ id,info,time);
// }
// };
// }
//异步调用wx退款接口
public static TimerTask refundOrder(final CmsOrder orderInfo) {
return new TimerTask() {
@Override
public void run() {
//调用退款接口
String result = CySpringBeanComp.getBean(WxPayService.class).refundOrder(orderInfo);
//redisson key:【order:redis:${oid}】
boolean isGetLock = false;
RLock redisLock = CySpringBeanComp.getBean(RedissonClient.class).getLock(RedisCons.ORDER_REDIS + orderInfo.getBusinessId());
try {
isGetLock = redisLock.tryLock(Long.parseLong(RedisCons.ORDER_INFO_LOCK_WAIT_TIME),
Long.parseLong(RedisCons.ORDER_INFO_LOCK_LEASE_TIME), TimeUnit.SECONDS);
if (isGetLock) {
orderInfo.setRefundTime(new Date());
orderInfo.setState(0);
if ("SUCCESS".equals(result)){ //接口成功
if (Objects.equals(orderInfo.getManualRefund(), 1))
orderInfo.setStatus(4);
else
orderInfo.setStatus(2);
} else { //接口失败
if (Objects.equals(orderInfo.getManualRefund(), 1))
orderInfo.setStatus(5);
else
orderInfo.setStatus(3);
orderInfo.setRefundCount(1);
}
//redis key: 【order:activity:${aid}:${oid}】 value 【hash】;ttl:-1;hash state-> 【未同步】,status -> 退款中 (2 3)
CySpringBeanComp.getBean(CyRedisServiceImpl.class).set(RedisCons.ORDER_ACTIVITY +":"+ orderInfo.getGoodsId() + ":" + orderInfo.getBusinessId(),orderInfo);
//发送 mq,exchange:`order_activity` route-key:`order_activity_status` value 【订单】
CySpringBeanComp.getBean(RabbitClusterUtil.class).sendMsg(orderInfo,
CySpringBeanComp.getBean(RabbitMQConfigBean.class).ORDER_EXCHANGE_NAME,
CySpringBeanComp.getBean(RabbitMQConfigBean.class).ORDER_STATUS_QUEUE_NAME);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
isGetLock = false;
} finally {
redisLock.unlock();
log.error("释放成功");
}
}
};
}
}
package org.rcisoft.core.rabbitmq;
/**
* rabbitmq
*
*/
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.rcisoft.business.cmsOrder.dao.CmsOrderRepository;
import org.rcisoft.business.cmsOrder.entity.CmsOrder;
import org.rcisoft.core.rabbitmq.bean.RabbitMQConfigBean;
import org.rcisoft.core.service.CyRedisService;
import org.rcisoft.core.util.RedisCons;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.concurrent.TimeUnit;
@Component
@Slf4j
public class OrderActivityAddRabbitListener {
@Autowired
RabbitMQConfigBean rabbitMQConfigBean;
@Autowired
private RedissonClient redissonClient;
@Autowired
private CmsOrderRepository orderRepository;
@Autowired(required = false)
private CyRedisService cyRedisServiceImpl;
/**
* 1.2 mq流程参考
* <p>
*/
@Transactional(propagation = Propagation.REQUIRED)
@RabbitListener(queues = "${spring.rabbitmq.orderActivityAddQueue:orderActivityAddQueue}")
public void directConsumer(String msg1, Channel channel, Message message) throws IOException {
try {
log.error("---orderActivityAddQueue:"+msg1);
String msg = new String(((Message) message).getBody(), StandardCharsets.UTF_8);
CmsOrder orderInfo = JSONUtil.toBean(msg, CmsOrder.class);
log.error("---CmsOrder:"+orderInfo);
//加redis锁
boolean isGetLock = false;
RLock lock = redissonClient.getLock(RedisCons.ORDER_DB + orderInfo.getBusinessId());
try {
isGetLock = lock.tryLock(Long.parseLong(RedisCons.ORDER_INFO_LOCK_WAIT_TIME),
Long.parseLong(RedisCons.ORDER_INFO_LOCK_LEASE_TIME), TimeUnit.SECONDS);
if (isGetLock) {
//查询DB -> 是否已落库
CmsOrder info = orderRepository.selectById(orderInfo.getBusinessId());
if (info == null) {
//未落库 -> 【order:activity:${aid}:${oid}】落库;【未同步】 => 更新落库【订单状态信息,退款信息等其他信息
Object detail = cyRedisServiceImpl.get(RedisCons.ORDER_ACTIVITY +":"+ orderInfo.getGoodsId() +":"+ orderInfo.getBusinessId());
if (detail!=null) {
CmsOrder orderDetail = JSON.parseObject(JSON.toJSONString(detail), CmsOrder.class);
if (orderDetail.getState().equals(0)){ //未同步
orderRepository.insert(orderDetail);
//如果有优惠券,进行核销
// if (orderDetail.getCouponId() != null) {
// UserCouponRelative userCouponRelative = new UserCouponRelative();
// userCouponRelative.setBusinessId(orderDetail.getCouponId());
// userCouponRelative.setCancelId(orderDetail.getStoreId());
// userCouponRelative.setOrderId(orderDetail.getBusinessId());
// userCouponRelative.setStatus(1);
// userCouponRelative.setCancelTime(new Date());
// couponInfoRepository.useCouponById(userCouponRelative);
// }
//加订单redis锁
RLock redisLock = redissonClient.getLock(RedisCons.ORDER_REDIS + orderInfo.getBusinessId());
try {
isGetLock = redisLock.tryLock(Long.parseLong(RedisCons.ORDER_INFO_LOCK_WAIT_TIME),
Long.parseLong(RedisCons.ORDER_INFO_LOCK_LEASE_TIME), TimeUnit.SECONDS);
if (isGetLock) {
//redis key: 【order:activity:${aid}:${oid}】 value 【hash】;ttl:-1;hash state-> 【已同步】
orderDetail.setState(1);
cyRedisServiceImpl.set(RedisCons.ORDER_ACTIVITY +":"+ orderInfo.getGoodsId() + ":" + orderInfo.getBusinessId(),orderDetail);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
isGetLock = false;
} finally {
redisLock.unlock();
log.error("释放成功");
}
}
}
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
isGetLock = false;
} finally {
lock.unlock();
log.error("释放成功");
}
} catch (RuntimeException e) {
log.error(e.getMessage());
} finally {
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}
}
}
package org.rcisoft.core.rabbitmq;
/**
* rabbitmq
*
*/
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.rcisoft.business.cmsActivity.dao.CmsActivityRepository;
import org.rcisoft.business.cmsActivity.entity.CmsActivity;
import org.rcisoft.business.cmsActivity.service.impl.StockService;
import org.rcisoft.business.cmsOrder.dao.CmsOrderRepository;
import org.rcisoft.business.cmsOrder.entity.CmsOrder;
import org.rcisoft.core.rabbitmq.bean.RabbitMQConfigBean;
import org.rcisoft.core.service.CyRedisService;
import org.rcisoft.core.util.RedisCons;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.concurrent.TimeUnit;
@Component
@Slf4j
public class OrderActivityCloseRabbitListener {
@Autowired
RabbitMQConfigBean rabbitMQConfigBean;
@Autowired
private RedissonClient redissonClient;
@Autowired(required = false)
private CyRedisService cyRedisServiceImpl;
@Autowired
private StockService stockService;
@Autowired
private CmsOrderRepository orderRepository;
// @Autowired
// private CouponInfoRepository couponInfoRepository;
@Autowired
private CmsActivityRepository activityInfoRepository;
/**
* 1.2 mq流程参考
* <p>
*/
@Transactional(propagation = Propagation.REQUIRED)
@RabbitListener(queues = "${spring.rabbitmq.orderActivityCloseQueue:orderActivityCloseQueue}")
public void directConsumer(String msg1, Channel channel, Message message) throws IOException {
try {
log.error("---orderActivityCloseQueue:"+msg1);
String msg = new String(((Message) message).getBody(), StandardCharsets.UTF_8);
CmsOrder orderInfo = JSONUtil.toBean(msg, CmsOrder.class);
log.error("---CmsOrder:"+orderInfo);
//加redis锁
boolean isGetLock = false;
RLock lock = redissonClient.getLock(RedisCons.ORDER_DB + orderInfo.getBusinessId());
try {
isGetLock = lock.tryLock(Long.parseLong(RedisCons.ORDER_INFO_LOCK_WAIT_TIME),
Long.parseLong(RedisCons.ORDER_INFO_LOCK_LEASE_TIME), TimeUnit.SECONDS);
if (isGetLock) {
// redis key: 【order:activity:${oid}】 value 【hash】;hash state 是否是 【待支付
Object detail = cyRedisServiceImpl.get(RedisCons.ORDER_ACTIVITY +":"+ orderInfo.getGoodsId() +":"+ orderInfo.getBusinessId());
if (detail!=null) {
CmsOrder orderDetail = JSON.parseObject(JSON.toJSONString(detail), CmsOrder.class);
if (orderDetail.getState().equals(0) && orderDetail.getStatus().equals(0)) {
//如果订单待支付,则关闭订单
orderDetail.setStatus(10);
orderDetail.setUpdateDate(new Date());
//查询DB -> 是否已落库
CmsOrder info = orderRepository.selectById(orderInfo.getBusinessId());
if (info != null)
orderRepository.updateById(orderDetail);
else
orderRepository.insert(orderDetail);
//如果使用了优惠券,则改为未使用
// if (orderDetail.getCouponId() != null) {
// UserCouponRelative userCouponRelative = new UserCouponRelative();
// userCouponRelative.setBusinessId(orderDetail.getCouponId());
// userCouponRelative.setStatus(0);
// couponInfoRepository.cancelCouponById(userCouponRelative);
// }
//加订单redis锁
RLock redisLock = redissonClient.getLock(RedisCons.ORDER_REDIS + orderInfo.getBusinessId());
try {
isGetLock = redisLock.tryLock(Long.parseLong(RedisCons.ORDER_INFO_LOCK_WAIT_TIME),
Long.parseLong(RedisCons.ORDER_INFO_LOCK_LEASE_TIME), TimeUnit.SECONDS);
if (isGetLock) {
//redis key: 【order:activity:${aid}:${oid}】 value 【hash】;ttl:-1;hash state-> 【已同步】
orderDetail.setState(1);
cyRedisServiceImpl.set(RedisCons.ORDER_ACTIVITY +":"+ orderInfo.getGoodsId() + ":" + orderInfo.getBusinessId(),orderDetail);
//退人数
// CmsActivity activityInfo = activityInfoRepository.selectById(orderInfo.getActivityId());
stockService.addStock(RedisCons.ACTIVITY_COUNT +":"+ orderDetail.getGoodsId(), orderDetail.getNum());
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
isGetLock = false;
} finally {
redisLock.unlock();
log.error("释放成功");
}
}
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
isGetLock = false;
} finally {
lock.unlock();
log.error("释放成功");
}
} catch (RuntimeException e) {
log.error(e.getMessage());
}
finally {
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}
}
}
package org.rcisoft.core.rabbitmq.bean;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
/**
* 广播模式
*/
@Configuration
@Data
public class RabbitMQConfigBean {
// 交换器名称和队列 :订单
@Value("${spring.rabbitmq.orderActivityExchange}")
public String ORDER_EXCHANGE_NAME;
@Value("${spring.rabbitmq.orderActivityDelayExchange}")
public String ORDER_EXCHANGE_DELAY_NAME;
@Value("${spring.rabbitmq.orderActivityAddQueue}")
public String ORDER_ADD_QUEUE_NAME;
@Value("${spring.rabbitmq.orderActivityStatusQueue}")
public String ORDER_STATUS_QUEUE_NAME;
@Value("${spring.rabbitmq.orderActivityCloseQueue}")
public String ORDER_CLOSE_QUEUE_NAME;
@Value("${spring.rabbitmq.orderActivityCloseDelayQueue}")
public String ORDER_CLOSE_QUEUE_DELAY_NAME;
}
package org.rcisoft.core.rabbitmq.config;
import com.github.wxpay.sdk.WXPayConfig;
import org.springframework.context.annotation.Configuration;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
@Configuration
public class PayConfig implements WXPayConfig {
private byte[] certData;
private String appId;
private String mchId;
private String key;
public PayConfig() {
super();
}
/**
* 微信退款所需要的配置! 退款只需要证书即可。
* @throws Exception
*/
public PayConfig(String appId,String mchId,String key,String certPath) throws Exception {
File file = new File(certPath);
InputStream certStream = new FileInputStream(file);
this.certData = new byte[(int) file.length()];
certStream.read(this.certData);
certStream.close();
this.appId = appId;
this.mchId = mchId;
this.key = key;
}
@Override
public String getAppID() {
return appId; //appid
}
@Override
public String getMchID() {
return mchId; //商户号id
}
@Override
public String getKey() {
return key; //支付API密钥
}
@Override
public InputStream getCertStream() {
ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
return certBis;
}
@Override
public int getHttpConnectTimeoutMs() {
return 8000;
}
@Override
public int getHttpReadTimeoutMs() {
return 10000;
}
}
package org.rcisoft.core.rabbitmq.config;
import org.rcisoft.core.rabbitmq.bean.RabbitMQConfigBean;
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* RabbitMq配置类
*
*/
@Configuration
public class RabbitMQClusterConfig {
public static final long MIN = 60 * 1000L;
private static final String X_MESSAGE_TTL = "x-message-ttl";
private static final String X_DEAD_LETTER_EXCHANGE = "x-dead-letter-exchange";
private static final String X_DEAD_LETTER_ROUTING_KEY = "x-dead-letter-routing-key";
@Autowired
RabbitMQConfigBean rabbitMQConfigBean;
/**
* 以下 消息队列
* @return
*/
// 创建持久化的Exchange
@Bean
Exchange orderActivityExchange() {
return ExchangeBuilder.directExchange(rabbitMQConfigBean.ORDER_EXCHANGE_NAME).durable(true).build();
}
// 创建持久化的死信Exchange
@Bean
Exchange orderActivityDelayExchange() {
return ExchangeBuilder.directExchange(rabbitMQConfigBean.ORDER_EXCHANGE_DELAY_NAME).durable(true).build();
}
// 创建持久化的queue
@Bean
Queue orderActivityAddQueue() {
return QueueBuilder.durable(rabbitMQConfigBean.ORDER_ADD_QUEUE_NAME).build();
}
// 创建持久化的queue
@Bean
Queue orderActivityStatusQueue() {
return QueueBuilder.durable(rabbitMQConfigBean.ORDER_STATUS_QUEUE_NAME).build();
}
// 创建持久化的queue
@Bean
Queue orderActivityCloseQueue() {
return QueueBuilder.durable(rabbitMQConfigBean.ORDER_CLOSE_QUEUE_NAME).build();
}
// 创建持久化的queue
@Bean
Queue orderActivityCloseDelayQueue() {
return QueueBuilder.durable(rabbitMQConfigBean.ORDER_CLOSE_QUEUE_DELAY_NAME)
.withArgument(X_MESSAGE_TTL, 30 * MIN)
.withArgument(X_DEAD_LETTER_EXCHANGE,rabbitMQConfigBean.ORDER_EXCHANGE_NAME)
.withArgument(X_DEAD_LETTER_ROUTING_KEY,rabbitMQConfigBean.ORDER_CLOSE_QUEUE_NAME).build();
// .ttl(25000)
// .deadLetterExchange(rabbitMQConfigBean.ORDER_EXCHANGE_NAME)
// .deadLetterRoutingKey(rabbitMQConfigBean.ORDER_CLOSE_QUEUE_NAME).build();
}
// 创建绑定
@Bean
Binding orderActivityAddBindings(){
return BindingBuilder.bind(orderActivityAddQueue()).to(orderActivityExchange()).with(rabbitMQConfigBean.ORDER_ADD_QUEUE_NAME).and(null);
}
// 创建绑定
@Bean
Binding orderActivityStatusBindings(){
return BindingBuilder.bind(orderActivityStatusQueue()).to(orderActivityExchange()).with(rabbitMQConfigBean.ORDER_STATUS_QUEUE_NAME).and(null);
}
// 创建绑定
@Bean
Binding orderActivityCloseBindings(){
return BindingBuilder.bind(orderActivityCloseQueue()).to(orderActivityExchange()).with(rabbitMQConfigBean.ORDER_CLOSE_QUEUE_NAME).and(null);
}
// 创建绑定
@Bean
Binding orderActivityCloseDelayBindings(){
return BindingBuilder.bind(orderActivityCloseDelayQueue()).to(orderActivityDelayExchange()).with(rabbitMQConfigBean.ORDER_CLOSE_QUEUE_NAME).and(null);
}
}
package org.rcisoft.core.rabbitmq.config;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//@ConditionalOnProperty(prefix = "cy.model", name = {"redis"}, havingValue = "true")
@Configuration
@Slf4j
public class RedissonConfig {
@Value("${spring.data.redis.host}")
private String redisIP;
@Value("${spring.data.redis.port}")
private String redisPort;
@Value("${spring.data.redis.password}")
private String redisPassword;
private Config config = new Config();
@Bean(destroyMethod = "shutdown")
public RedissonClient init() {
try {
//设置编解码器(默认FST)
//config.setCodec(new JsonJacksonCodec());
/**
*
* ERROR o.r.c.h.CommandDecoder.decodeCommand.134 - Unable to decode data. reply: +PONG
* , channel: [id: 0x2bcaea2d, L:/192.168.1.74:53284 - R:117.122.212.91/117.122.212.91:26070], command: CommandData [promise=RedissonPromise [promise=ImmediateEventExecutor$ImmediatePromise@7490414a(failure: io.netty.util.concurrent.DefaultPromise$StacklessCancellationException)], command=(PING), params=[], codec=org.redisson.client.codec.StringCodec]
* java.util.concurrent.CancellationException: null
*
* 发现并不是解码器的问题,debug一停,就会有该问题
*/
//config.setCodec(new StringCodec());
config.useSingleServer().setAddress("redis://" + redisIP + ":" + redisPort).setConnectTimeout(30000)//同任何节点建立连接时的等待超时。时间单位是毫秒。
.setTimeout(3000)//等待节点回复命令的时间。该时间从命令发送成功时开始计时。
.setRetryInterval(3000)//当与某个节点的连接断开时,等待与其重新建立连接的时间间隔。时间单位是毫秒。
.setPingConnectionInterval(1000)
.setPassword(StringUtils.isAnyEmpty(redisPassword) ? null : redisPassword);
return Redisson.create(config);
} catch (Exception e) {
log.error(e.getMessage());
}
return null;
}
}
package org.rcisoft.core.schedule;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.rcisoft.business.cmsActivity.dao.CmsActivityRepository;
import org.rcisoft.business.cmsActivity.entity.CmsActivity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;
@Component
@Slf4j
public class ActivitySyncSchedule {
@Autowired
private CmsActivityRepository activityInfoRepository;
//定时同步活动状态结束
// @Scheduled(cron = "0 0/10 * * * ?")
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT)
public void execute() {
// 查询DB中的未删除的活动
QueryWrapper<CmsActivity> wrapper = new QueryWrapper<>();
wrapper.eq("del_flag",0);
List<CmsActivity> list = activityInfoRepository.selectList(wrapper);
for (CmsActivity activityInfo : list) {
//如果活动结束时间已过,改状态为已过期
if (activityInfo.getEndTime().before(new Date())) {
CmsActivity info = new CmsActivity();
info.setBusinessId(activityInfo.getBusinessId());
// info.setStatus(2);
// activityInfoRepository.updateById(info);
}
}
}
}
This diff is collapsed.
package org.rcisoft.core.util;
/**
* 获取库存回调
* @author wuKeFan
*/
public interface IStockCallback {
/**
* 获取库存
* @return
*/
int getStock();
}
package org.rcisoft.core.util;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.rcisoft.core.exception.CyServiceException;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.util.*;
@Slf4j
public class PayUtil {
/**
* 签名字符串
* @param text需要签名的字符串
* @param key 密钥
* @param input_charset编码格式
* @return 签名结果
*/
public static String sign(String text, String key, String inputCharset) {
text = text + "&key=" + key;
return DigestUtils.md5Hex(getContentBytes(text, inputCharset));
}
/**
* 签名字符串
* @param text需要签名的字符串
* @param sign 签名结果
* @param key密钥
* @param input_charset 编码格式
* @return 签名结果
*/
public static boolean verify(String text, String sign, String key, String inputCharset) {
text = text + key;
String mysign = DigestUtils.md5Hex(getContentBytes(text, inputCharset));
if (mysign.equals(sign)) {
return true;
} else {
return false;
}
}
/**
* @param content
* @param charset
* @return
* @throws SignatureException
* @throws UnsupportedEncodingException
*/
public static byte[] getContentBytes(String content, String charset) {
if (charset == null || "".equals(charset)) {
return content.getBytes();
}
try {
return content.getBytes(charset);
} catch (UnsupportedEncodingException e) {
throw new CyServiceException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);
}
}
/**
* 生成6位或10位随机数 param codeLength(多少位)
* @return
*/
public static String createCode(int codeLength) {
StringBuilder code = new StringBuilder();
for (int i = 0; i < codeLength; i++) {
code.append((int) (Math.random() * 9));
}
return code.toString();
}
@SuppressWarnings("unused")
private static boolean isValidChar(char ch) {
if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))
return true;
return (ch >= 0x4e00 && ch <= 0x7fff) || (ch >= 0x8000 && ch <= 0x952f);// 简体中文汉字编码
}
/**
* 除去数组中的空值和签名参数
* @param sArray 签名参数组
* @return 去掉空值与签名参数后的新签名参数组
*/
public static Map<String, String> paraFilter(Map<String, String> sArray) {
Map<String, String> result = new HashMap<>();
if (sArray == null || sArray.size() <= 0) {
return result;
}
for (String key : sArray.keySet()) {
String value = sArray.get(key);
if (value == null || value.equals("") || key.equalsIgnoreCase("sign")
|| key.equalsIgnoreCase("sign_type")) {
continue;
}
result.put(key, value);
}
return result;
}
/**
* 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
* @param params 需要排序并参与字符拼接的参数组
* @return 拼接后字符串
*/
public static String createLinkString(Map<String, String> params) {
List<String> keys = new ArrayList<>(params.keySet());
Collections.sort(keys);
String prestr = "";
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
String value = params.get(key);
if (i == keys.size() - 1) {// 拼接时,不包括最后一个&字符
prestr = prestr + key + "=" + value;
} else {
prestr = prestr + key + "=" + value + "&";
}
}
return prestr;
}
/**
*
* @param requestUrl请求地址
* @param requestMethod请求方法
* @param outputStr参数
*/
public static String httpRequest(String requestUrl,String requestMethod,String outputStr){
// 创建SSLContext
StringBuffer buffer = null;
try{
URL url = new URL(requestUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod(requestMethod);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.connect();
//往服务器端写内容
if(null !=outputStr){
OutputStream os=conn.getOutputStream();
os.write(outputStr.getBytes("utf-8"));
os.close();
}
// 读取服务器端返回的内容
InputStream is = conn.getInputStream();
InputStreamReader isr = new InputStreamReader(is, "utf-8");
BufferedReader br = new BufferedReader(isr);
buffer = new StringBuffer();
String line = null;
while ((line = br.readLine()) != null) {
buffer.append(line);
}
br.close();
}catch(Exception e){
e.printStackTrace();
}
return buffer.toString();
}
public static String urlEncodeUTF8(String source){
String result=source;
try {
result=java.net.URLEncoder.encode(source, "UTF-8");
} catch (UnsupportedEncodingException e) {
log.error("error",e);
}
return result;
}
/**
* 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。
* @param strxml
* @return
* @throws JDOMException
* @throws IOException
*/
public static Map doXMLParse(String strxml) throws IOException, JDOMException {
if(null == strxml || "".equals(strxml)) {
return null;
}
Map m = new HashMap();
InputStream in = String2Inputstream(strxml);
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(in);
Element root = doc.getRootElement();
List list = root.getChildren();
Iterator it = list.iterator();
while(it.hasNext()) {
Element e = (Element) it.next();
String k = e.getName();
String v = "";
List children = e.getChildren();
if(children.isEmpty()) {
v = e.getTextNormalize();
} else {
v = getChildrenText(children);
}
m.put(k, v);
}
//关闭流
in.close();
return m;
}
/**
* 获取子结点的xml
* @param children
* @return String
*/
public static String getChildrenText(List children) {
StringBuffer sb = new StringBuffer();
if(!children.isEmpty()) {
Iterator it = children.iterator();
while(it.hasNext()) {
Element e = (Element) it.next();
String name = e.getName();
String value = e.getTextNormalize();
List list = e.getChildren();
sb.append("<" + name + ">");
if(!list.isEmpty()) {
sb.append(getChildrenText(list));
}
sb.append(value);
sb.append("</" + name + ">");
}
}
return sb.toString();
}
public static InputStream String2Inputstream(String str) {
return new ByteArrayInputStream(str.getBytes());
}
public static String getMD5(String str) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
String result = MD5(str, md);
return result;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return "";
}
}
public static String MD5(String strSrc, MessageDigest md) {
byte[] bt = strSrc.getBytes();
md.update(bt);
String strDes = bytes2Hex(md.digest());
return strDes;
}
public static String bytes2Hex(byte[] bts) {
StringBuffer des = new StringBuffer();
String tmp = null;
for (int i = 0; i < bts.length; i++) {
tmp = (Integer.toHexString(bts[i] & 0xFF));
if (tmp.length() == 1) {
des.append("0");
}
des.append(tmp);
}
return des.toString();
}
public static String getRefundDecrypt(String reqInfoSecret, String key) {
String result = "";
try {
Base64.Decoder decoder = Base64.getDecoder();
byte[] base64ByteArr = decoder.decode(reqInfoSecret);
Security.addProvider(new BouncyCastleProvider());
String md5key = PayUtil.getMD5(key);
log.info("-----md5key:"+md5key);
SecretKey secretKey = new SecretKeySpec(md5key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] resultbt = cipher.doFinal(base64ByteArr);
result = new String(resultbt);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
package org.rcisoft.core.util;
import cn.hutool.json.JSONUtil;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.core.RabbitTemplate.ConfirmCallback;
import org.springframework.amqp.rabbit.core.RabbitTemplate.ReturnsCallback;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import java.util.UUID;
//mq
@Configuration
public class RabbitClusterUtil {
private static final Logger log = LoggerFactory.getLogger(RabbitClusterUtil.class);
@Autowired(required = false)
RabbitTemplate rabbitTemplate;
// public RabbitTemplate rabbitTemplate() {
//// RabbitTemplate template = new RabbitTemplate(connectionFactory());
// return template;
// }
final ConfirmCallback confirmCallback = new ConfirmCallback() {
//初始化
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
if (!ack) {
RabbitClusterUtil.log.error("异常处理....correlationData: " + correlationData);
}
}
};
final ReturnsCallback returnCallback = new ReturnsCallback() {
//初始化
public void returnedMessage(ReturnedMessage returnedMessage) {
RabbitClusterUtil.log.error("return exchange: " + returnedMessage.getExchange() + ", routingKey: " +
returnedMessage.getRoutingKey() + ", replyCode: " + returnedMessage.getReplyCode() + ", replyText: " + returnedMessage.getReplyText());
}
};
public RabbitClusterUtil() {
}
public void sendMsg(Object msg, String exchangeName, String routeKey) {
//向mq发送消息
String msgId = UUID.randomUUID().toString();
this.rabbitTemplate.setConfirmCallback(this.confirmCallback);
this.rabbitTemplate.setReturnsCallback(this.returnCallback);
MessageProperties props = (MessageProperties)MessagePropertiesBuilder.newInstance().setDeliveryMode(MessageDeliveryMode.fromInt(2)).build();
Message message = new Message(msg == null ? "".getBytes() : JSONUtil.toJsonStr(msg).getBytes(), props);
this.rabbitTemplate.convertAndSend(exchangeName, routeKey, message, new CorrelationData(msgId));
}
}
package org.rcisoft.core.util;
/**
* Created by lcy on 17/2/11.
*/
public class RedisCons {
//公告浏览数
public static final String ANNOUNCEMENT_VIEW_NUM = "announcement:view";
//活动详情
public static final String ACTIVITY_DETAIL = "activity:detail";
//活动信息锁
public static final String ACTIVITY_INFO = "activity:info:";
//活动人数
public static final String ACTIVITY_COUNT = "activity:count";
//优惠券详情
public static final String COUPON_DETAIL = "coupon:detail";
//优惠券数量
public static final String COUPON_COUNT = "coupon:count";
//优惠券信息锁
public static final String COUPON_INFO = "coupon:info:";
//订单活动信息
public static final String ORDER_ACTIVITY = "order:activity";
//订单数据库锁
public static final String ORDER_DB = "order:db:";
//订单redis锁
public static final String ORDER_REDIS = "order:redis:";
//会员信息
public static final String MEMBER_INFO = "member:info";
//会员权益信息
public static final String BENEFITS_INFO = "benefits:info";
public static final String ORDER_INFO_LOCK_WAIT_TIME = "20";
public static final String TEST_ORDER_INFO_LOCK_WAIT_TIME = "30";
public static final String ORDER_INFO_LOCK_LEASE_TIME = "10";
}
package org.rcisoft.core.util;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
/**
* <h1>Java 雪花算法</h1>
* Created by woniu
*/
public class TimeUtil {
//计算两个时间相差的秒数
public static long getTimeSecond(String startTime, String endTime) throws ParseException {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
long eTime = df.parse(endTime).getTime();
long sTime = df.parse(startTime).getTime();
return (eTime - sTime) / 1000;
}
public static long getTimeSecond(Date startTime, Date endTime) {
long eTime = endTime.getTime();
long sTime = startTime.getTime();
return (eTime - sTime) / 1000;
}
/*日期加+1天*/
public static Date getTime(Date date,int field,int amount) {
Calendar calendar = new GregorianCalendar();
calendar.setTime(date);
calendar.add(field,amount); //整数往后推,负数往前移动
date=calendar.getTime(); //结果
return date;
}
//获取日期加N天后的最后一秒时间
public static Date getTimeLast(Date date,int field,int amount) {
Calendar calendar = new GregorianCalendar();
calendar.setTime(date);
calendar.add(field,amount); //整数往后推,负数往前移动
calendar.set(Calendar.HOUR_OF_DAY,23);
calendar.set(Calendar.MINUTE,59);
calendar.set(Calendar.SECOND,59);
date=calendar.getTime(); //结果
return date;
}
/**
public static void main(String[] args) throws ParseException {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date a = getTimeLast(new Date(),Calendar.DATE,2);
System.out.println(a);
}
*/
}
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment