diff --git a/mallinkAdmin/pom.xml b/mallinkAdmin/pom.xml index 638b94239..4b844ae82 100644 --- a/mallinkAdmin/pom.xml +++ b/mallinkAdmin/pom.xml @@ -13,8 +13,8 @@ mallinkAdmin - 3.7.0 - 3.7.0 + 3.7.0.B + 3.7.0.B diff --git a/mallinkAdmin/src/main/java/com/iformall/controller/market/WxCouponPasswordController.java b/mallinkAdmin/src/main/java/com/iformall/controller/market/WxCouponPasswordController.java index 849c859e1..98fdf1c3e 100644 --- a/mallinkAdmin/src/main/java/com/iformall/controller/market/WxCouponPasswordController.java +++ b/mallinkAdmin/src/main/java/com/iformall/controller/market/WxCouponPasswordController.java @@ -2,6 +2,7 @@ package com.iformall.controller.market; import com.github.pagehelper.PageInfo; import com.iformall.annotation.SystemControllerLog; +import com.iformall.common.ErrorCode; import com.iformall.common.ResultData; import com.iformall.controller.base.BaseController; import com.iformall.domain.po.base.BaseEntity; @@ -15,10 +16,7 @@ import io.swagger.annotations.ApiOperation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; /** * @author gongbiao @@ -59,5 +57,27 @@ public class WxCouponPasswordController extends BaseController { return new ResultData(page); } + @ApiOperation(value = "卡密延期", notes = "{\"couponId\":\"string\", \"expireDate\":\"string\"}") + @PostMapping("/postpone") + @SystemControllerLog(description = "卡密延期") + public ResultData postpone(@RequestBody WxCouponPassword wxCouponPassword) { + logger.debug("[" + getIpAddr() + "] WxCouponPasswordController::postpone"); + if (wxCouponPassword.getCouponId() == null) { + logger.error("couponId不能为空: "); + return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); + } + WxCouponPassword couponPassword = new WxCouponPassword(); + couponPassword.updateTenantInfo(getTenantInfo()); + couponPassword.setCouponId(wxCouponPassword.getCouponId()); + couponPassword.setExpireDate(wxCouponPassword.getExpireDate()); + try { + wxCouponPasswordService.postpone(couponPassword); + } catch (Exception e) { + logger.error(e.getMessage()); + return new ResultData(ErrorCode.COUPON_PASSWORD_POSTPONE_ERR); + } + return new ResultData(); + } + } diff --git a/mallinkAdmin/src/main/java/com/iformall/log/TableOperateAspect.java b/mallinkAdmin/src/main/java/com/iformall/log/TableOperateAspect.java index d65be0d47..3dee1b300 100644 --- a/mallinkAdmin/src/main/java/com/iformall/log/TableOperateAspect.java +++ b/mallinkAdmin/src/main/java/com/iformall/log/TableOperateAspect.java @@ -3,6 +3,7 @@ package com.iformall.log; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.google.common.collect.Lists; import com.google.common.collect.MapDifference; import com.google.common.collect.Maps; import com.iformall.common.LogColumn; @@ -17,7 +18,6 @@ import com.iformall.service.invest.impl.InvestBaseServiceImpl; import com.iformall.utils.SpringContextUtils; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.compress.utils.Lists; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.reflect.FieldUtils; import org.aspectj.lang.ProceedingJoinPoint; diff --git a/mallinkBApi/src/main/java/com/iformall/annotation/RedisCache.java b/mallinkBApi/src/main/java/com/iformall/annotation/RedisCache.java new file mode 100644 index 000000000..a7ca0d919 --- /dev/null +++ b/mallinkBApi/src/main/java/com/iformall/annotation/RedisCache.java @@ -0,0 +1,53 @@ +package com.iformall.annotation; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.concurrent.TimeUnit; + + +/** + * /api/user/detail + * /api/couponOrder/getUnverifiedAmountOnDate + * /api/micropay/getMicroPayAmountOnDate + * /api/couponOrder/getVerifiedAmountOnDate + * /api/wxDateAmountRecord/listMicropay + * /api/wxDateAmountRecord/listVerified + * /api/wxDateAmountRecord/listOrder + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface RedisCache { + + /** + * 缓存key的名称 + * @return + */ + String key() default ""; + + /** + * 自动生成key + * @return + */ + boolean autoKey() default true; + + /** + * 参数md5,解决key过长问题 + * @return + */ + boolean md5() default true ; + + /** + * key 过期日期默认60秒 + * @return + */ + int expireTime() default 60; + + /** + * 时间单位默认为秒 + * @return + */ + TimeUnit dateUnit() default TimeUnit.SECONDS; +} diff --git a/mallinkBApi/src/main/java/com/iformall/aop/RedisCacheAspect.java b/mallinkBApi/src/main/java/com/iformall/aop/RedisCacheAspect.java new file mode 100644 index 000000000..463eb0a0a --- /dev/null +++ b/mallinkBApi/src/main/java/com/iformall/aop/RedisCacheAspect.java @@ -0,0 +1,158 @@ +package com.iformall.aop; + + +import com.alibaba.fastjson.JSONObject; +import com.iformall.annotation.RedisCache; +import com.iformall.common.ErrorCode; +import com.iformall.domain.po.WxBuser; +import com.iformall.exception.MallinkException; +import com.iformall.service.WxBuserTokenService; +import com.iformall.utils.HashUtil; +import com.iformall.utils.RedisLock; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletRequest; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Objects; + +@Slf4j +@Aspect +@Component +public class RedisCacheAspect { + + /** + * 参数分隔符 param1|param2|param3 + **/ + private static final String DELIMITER_PARAMS = "|"; + + /** + * key 分隔符 + */ + private static final String DELIMITER_KEY = ":"; + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + @Autowired + RedisLock redisLock; + + @Autowired + private WxBuserTokenService userTokenService; + + @Pointcut("@annotation(com.iformall.annotation.RedisCache)") + public void cacheAspect() { + } + + @Around("cacheAspect()") + public Object round(ProceedingJoinPoint jp) throws Throwable { + HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + // 查询token信息 + //从header中获取token + String token = request.getHeader("token"); + //如果header中不存在token,则从参数中获取token + if (StringUtils.isBlank(token)) { + token = request.getParameter("token"); + } + String tenantId; + + WxBuser wxBuser = null; + if (StringUtils.isNotBlank(token)) { + wxBuser = userTokenService.getByToken(token); + } + if (Objects.isNull(wxBuser) || wxBuser.getExpireTime().getTime() < System.currentTimeMillis()) { + tenantId = "0"; + } else { + tenantId = wxBuser.getTenantId(); + } + + // 请求参数 + Object[] args = jp.getArgs(); + // 接口 返回结果 + Object result; + String redisKey; + + //得到注释的名称 + MethodSignature signature = (MethodSignature) jp.getSignature(); + //判断tag是否在用户权限中 如果存在加入参数查询 + Method method = signature.getMethod(); + RedisCache cache = method.getAnnotation(RedisCache.class) ; + if (cache.autoKey()) { + // 构建 redisKey => reqPath:tenantId:md5(param1_param2_param3) + String requestUrl = request.getRequestURI(); + // 接口路径 reqPath => /api/xxx + String reqPath = requestUrl.substring(requestUrl.indexOf("/api/")); + if (cache.md5()) { + redisKey = StringUtils.join(reqPath, DELIMITER_KEY, tenantId, DELIMITER_KEY, HashUtil.md5(StringUtils.join(args, DELIMITER_PARAMS))); + } else { + redisKey = StringUtils.join(reqPath, DELIMITER_KEY, tenantId, DELIMITER_KEY, StringUtils.join(args, DELIMITER_PARAMS)); + } + } else { + redisKey = cache.key(); + } + + // redisKey 不存在,获取接口数据并返回 + if (StringUtils.isBlank(redisKey)) { + result = jp.proceed(args); + } else { + ValueOperations valueOperations = stringRedisTemplate.opsForValue(); + String value = valueOperations.get(redisKey); + if (value == null) { + String lockKey = StringUtils.join(redisKey, ":", "lock"); + long time = System.currentTimeMillis() + 2000; + String timeStr = String.valueOf(time); + try { + //分布式锁,保证一个线程读DB,其它线程排队 + if (redisLock.lock2(lockKey, timeStr)) { + log.debug("CacheAspect 读库中, key:{}: " + lockKey); + result = jp.proceed(args); + String json_data = JSONObject.toJSONString(result); + valueOperations.set(redisKey, json_data, cache.expireTime(), cache.dateUnit()); + log.debug("CacheAspect 缓存不存在,获取接口数据并放入缓存,key:{}, expire:{}", redisKey, cache.expireTime()); + } else { + log.debug("CacheAspect 读库等待中, key:{}: " + lockKey); + Thread.sleep(2000); + value = valueOperations.get(redisKey); + result = parseCache(jp, redisKey, value); + } + } catch (Throwable throwable) { + log.error("CacheAspect proceed error , Illegal argument: {} in {}.{}()", Arrays.toString(jp.getArgs()), + jp.getSignature().getDeclaringTypeName(), jp.getSignature().getName(), throwable); + if (throwable instanceof MallinkException) { + throw throwable; + } + throw new MallinkException(ErrorCode.SYS_SERVER_ERROR); + } finally { + redisLock.unlock(lockKey, timeStr); + } + } else { + result = parseCache(jp, redisKey, value); + } + // 计数器 + stringRedisTemplate.opsForHash().increment("hotapi", redisKey, 1); + } + return result; + } + + private Object parseCache(ProceedingJoinPoint jp, String redisKey, String value) { + if (StringUtils.isBlank(value)) { + log.debug("CacheAspect 缓存存在,解析缓存数据为空:{},key:{}", value, redisKey); + return null; + } + Class returnType = ((MethodSignature) jp.getSignature()).getReturnType(); + log.debug("CacheAspect 缓存存在,解析缓存并返回,key:{}", redisKey); + return JSONObject.parseObject(value, returnType); + } +} \ No newline at end of file diff --git a/mallinkBApi/src/main/java/com/iformall/config/RedisConfig.java b/mallinkBApi/src/main/java/com/iformall/config/RedisConfig.java index 857f38ec2..ce8351901 100644 --- a/mallinkBApi/src/main/java/com/iformall/config/RedisConfig.java +++ b/mallinkBApi/src/main/java/com/iformall/config/RedisConfig.java @@ -16,6 +16,8 @@ import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.cache.RedisCacheWriter; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.ValueOperations; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; @@ -172,4 +174,12 @@ public class RedisConfig extends CachingConfigurerSupport { template.setConnectionFactory(connectionFactory); return template; } + + @Bean("stringValueOperations") + public ValueOperations getStringValueOperations(RedisConnectionFactory connectionFactory) { + StringRedisTemplate template = new StringRedisTemplate(); + template.setConnectionFactory(connectionFactory); + template.afterPropertiesSet(); + return template.opsForValue(); + } } diff --git a/mallinkBApi/src/main/java/com/iformall/controller/WxCouponOrderController.java b/mallinkBApi/src/main/java/com/iformall/controller/WxCouponOrderController.java index 423ad596c..76ba76ac5 100644 --- a/mallinkBApi/src/main/java/com/iformall/controller/WxCouponOrderController.java +++ b/mallinkBApi/src/main/java/com/iformall/controller/WxCouponOrderController.java @@ -1,6 +1,7 @@ package com.iformall.controller; import com.github.pagehelper.PageInfo; +import com.iformall.annotation.RedisCache; import com.iformall.common.ErrorCode; import com.iformall.common.Result; import com.iformall.common.ResultData; @@ -86,6 +87,7 @@ public class WxCouponOrderController extends BaseController { } + @RedisCache @ApiOperation("某日期交易总流水") @GetMapping("getUnverifiedAmountOnDate") @ApiImplicitParams({ @@ -94,6 +96,7 @@ public class WxCouponOrderController extends BaseController { return wxCouponOrderService.listOnDateAsPage(getUser().getId(), date, null, null, false); } + @RedisCache @ApiOperation("某日期核销总流水") @GetMapping("getVerifiedAmountOnDate") @ApiImplicitParams({ diff --git a/mallinkBApi/src/main/java/com/iformall/controller/WxDateAmountRecordController.java b/mallinkBApi/src/main/java/com/iformall/controller/WxDateAmountRecordController.java index 80f9ffc7e..7b96bed78 100644 --- a/mallinkBApi/src/main/java/com/iformall/controller/WxDateAmountRecordController.java +++ b/mallinkBApi/src/main/java/com/iformall/controller/WxDateAmountRecordController.java @@ -1,6 +1,7 @@ package com.iformall.controller; import com.github.pagehelper.PageInfo; +import com.iformall.annotation.RedisCache; import com.iformall.common.ResultData; import com.iformall.domain.po.base.BaseEntity; import com.iformall.domain.po.WxDateAmountRecord; @@ -31,19 +32,21 @@ public class WxDateAmountRecordController extends BaseController { @Autowired private WxDateAmountRecordService wxDateAmountRecordService; - + @RedisCache @ApiOperation("首页查询交易金额记录接口") @GetMapping("listOrder") public ResultData listOrder() { return list(EnumDateAmtType.PAY_RECORD.getCode()); } + @RedisCache @ApiOperation("首页查询核销金额记录接口") @GetMapping("listVerified") public ResultData listVerified() { return list(EnumDateAmtType.VERIFY_RECORD.getCode()); } + @RedisCache @ApiOperation("首页查询刷卡金额记录接口") @GetMapping("listMicropay") public ResultData listMicropay() { diff --git a/mallinkBApi/src/main/java/com/iformall/controller/WxMerchantBUserController.java b/mallinkBApi/src/main/java/com/iformall/controller/WxMerchantBUserController.java index 47a356477..a989e452e 100644 --- a/mallinkBApi/src/main/java/com/iformall/controller/WxMerchantBUserController.java +++ b/mallinkBApi/src/main/java/com/iformall/controller/WxMerchantBUserController.java @@ -2,6 +2,7 @@ package com.iformall.controller; import com.iformall.annotation.AuthIgnore; +import com.iformall.annotation.RedisCache; import com.iformall.common.ErrorCode; import com.iformall.common.ResultData; import com.iformall.domain.po.WxMall; @@ -55,6 +56,7 @@ public class WxMerchantBUserController extends BaseController { @Autowired private WxScoreRulesService wxScoreRulesService; + @RedisCache @ApiOperation("查寻当bUser详情接口") @GetMapping("/detail") public ResultData detail() { diff --git a/mallinkBApi/src/main/java/com/iformall/controller/WxMerchantController.java b/mallinkBApi/src/main/java/com/iformall/controller/WxMerchantController.java index c9341e365..d6e658972 100644 --- a/mallinkBApi/src/main/java/com/iformall/controller/WxMerchantController.java +++ b/mallinkBApi/src/main/java/com/iformall/controller/WxMerchantController.java @@ -2,11 +2,9 @@ package com.iformall.controller; import com.iformall.common.ErrorCode; import com.iformall.common.ResultData; -import com.iformall.domain.po.WxBuser; -import com.iformall.domain.po.WxMerchant; -import com.iformall.domain.po.WxMerchantBUser; -import com.iformall.domain.po.WxProfitSharingReceiver; +import com.iformall.domain.po.*; import com.iformall.enums.EnumMsgSend; +import com.iformall.service.WxCUserService; import com.iformall.service.WxMerchantService; import com.iformall.service.WxProfitSharingReceiverService; import io.swagger.annotations.Api; @@ -29,6 +27,9 @@ public class WxMerchantController extends BaseController { @Autowired private WxProfitSharingReceiverService wxProfitSharingReceiverService; + @Autowired + private WxCUserService cUserService; + @ApiOperation("查询当前租户下商户名称列表") @GetMapping("/name_list") public ResultData nameList() { @@ -97,6 +98,24 @@ public class WxMerchantController extends BaseController { return new ResultData(has); } + @ApiOperation("获取微信OpenId") + @GetMapping("/getOpenIdByPhone") + @ApiImplicitParam(name = "phone", value = "商户C端注册手机号", dataType = "String", paramType = "query", required = true) + public ResultData getOpenIdByPhone(@ModelAttribute String phone) { + log.debug("[" + getIpAddr() + "] WxMerchantController::getOpenIdByPhone"); + if (!hasPermission()) { + return new ResultData(ErrorCode.USER_NO_PERMISSION); + } + if (StringUtils.isBlank(phone)) { + return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "商户C端注册手机号不能为空"); + } + WxCUser cuUser = new WxCUser(); + cuUser.updateTenantInfo(getTenantInfo()); + cuUser.setPhone(phone); + WxCUser mUser = cUserService.getByObject(cuUser); + return new ResultData(mUser.getOpenId()); + } + public boolean hasPermission() { WxMerchantBUser user = getUser(); WxBuser buser = getBuser(); diff --git a/mallinkBApi/src/main/java/com/iformall/controller/WxMicroPayController.java b/mallinkBApi/src/main/java/com/iformall/controller/WxMicroPayController.java index 845acb5b4..280f294eb 100644 --- a/mallinkBApi/src/main/java/com/iformall/controller/WxMicroPayController.java +++ b/mallinkBApi/src/main/java/com/iformall/controller/WxMicroPayController.java @@ -2,6 +2,7 @@ package com.iformall.controller; import com.alibaba.fastjson.JSONArray; +import com.iformall.annotation.RedisCache; import com.iformall.common.ErrorCode; import com.iformall.common.ResultData; import com.iformall.domain.po.*; @@ -225,6 +226,7 @@ public class WxMicroPayController extends BaseController { } } + @RedisCache @ApiOperation("付款码支付交易流水分页列表接口") @GetMapping("listMicroPay") @ApiImplicitParams({ @@ -235,6 +237,7 @@ public class WxMicroPayController extends BaseController { return wxOrderService.microPayListOnDateAsPage(getUser().getId(), EnumOrderType.MICROPAY.getCode(), date, pageNum, pageSize); } + @RedisCache @ApiOperation("付款码支付某日期交易总流水") @GetMapping("getMicroPayAmountOnDate") @ApiImplicitParams({ @@ -243,6 +246,16 @@ public class WxMicroPayController extends BaseController { return wxOrderService.microPayListOnDateAsPage(getUser().getId(), EnumOrderType.MICROPAY.getCode(), date, null, null); } + @ApiOperation("付款码支付某日异常交易分页列表接口") + @GetMapping("listMicroPayExp") + @ApiImplicitParams({ + @ApiImplicitParam(name = "date", value = "日期yyyy-MM-dd", dataType = "string", paramType = "query"), + @ApiImplicitParam(name = "pageNum", value = "页数", dataType = "int", paramType = "query",required = true), + @ApiImplicitParam(name = "pageSize", value = "每页条数", dataType = "int", paramType = "query",required = true)}) + public ResultData listMicroPayExp(String date, Integer pageNum, Integer pageSize) { + return wxOrderService.microPayExpListOnDateAsPage(getUser().getId(), EnumOrderType.MICROPAY.getCode(), date, pageNum, pageSize); + } + @ApiOperation(value = "付款码支付退款", notes = "{\"orderId\":\"string\"}") @PostMapping("/microPayRefund") diff --git a/mallinkCApi/src/main/java/com/iformall/annotation/RedisCache.java b/mallinkCApi/src/main/java/com/iformall/annotation/RedisCache.java new file mode 100644 index 000000000..185736606 --- /dev/null +++ b/mallinkCApi/src/main/java/com/iformall/annotation/RedisCache.java @@ -0,0 +1,53 @@ +package com.iformall.annotation; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.concurrent.TimeUnit; + + +/** + * - /api/wxCouponChannel/change + * - /api/user/userinfo + * - /api/wxBusiness/listAll + * - /api/wxCampaign/list + * - /api/mall/mallInfo + * - /api/mall/getAppIcon + * - /api/mall/getWeapNote + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface RedisCache { + + /** + * 缓存key的名称 + * @return + */ + String key() default ""; + + /** + * 自动生成key + * @return + */ + boolean autoKey() default true; + + /** + * 参数md5,解决key过长问题 + * @return + */ + boolean md5() default true ; + + /** + * key 过期日期默认60秒 + * @return + */ + int expireTime() default 60; + + /** + * 时间单位默认为秒 + * @return + */ + TimeUnit dateUnit() default TimeUnit.SECONDS; +} diff --git a/mallinkCApi/src/main/java/com/iformall/aop/RedisCacheAspect.java b/mallinkCApi/src/main/java/com/iformall/aop/RedisCacheAspect.java new file mode 100644 index 000000000..a451b2cac --- /dev/null +++ b/mallinkCApi/src/main/java/com/iformall/aop/RedisCacheAspect.java @@ -0,0 +1,152 @@ +package com.iformall.aop; + + +import com.alibaba.fastjson.JSONObject; +import com.iformall.annotation.RedisCache; +import com.iformall.domain.po.WxCUser; +import com.iformall.service.WxCUserTokenService; +import com.iformall.utils.HashUtil; +import com.iformall.utils.RedisLock; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletRequest; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Objects; + +@Slf4j +@Aspect +@Component +public class RedisCacheAspect { + + /** + * 参数分隔符 param1|param2|param3 + **/ + private static final String DELIMITER_PARAMS = "|"; + + /** + * key 分隔符 + */ + private static final String DELIMITER_KEY = ":"; + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + @Autowired + RedisLock redisLock; + + @Autowired + private WxCUserTokenService userTokenService; + + @Pointcut("@annotation(com.iformall.annotation.RedisCache)") + public void cacheAspect() { + } + + @Around("cacheAspect()") + public Object round(ProceedingJoinPoint jp) throws Throwable { + HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + // 查询token信息 + //从header中获取token + String token = request.getHeader("token"); + //如果header中不存在token,则从参数中获取token + if (StringUtils.isBlank(token)) { + token = request.getParameter("token"); + } + String tenantId; + WxCUser wxCUser = null ; + if(StringUtils.isNotBlank(token)) { + wxCUser = userTokenService.getByToken(token); + } + if (Objects.isNull(wxCUser) || wxCUser.getExpireTime().getTime() < System.currentTimeMillis()) { + tenantId = "0"; + } else { + tenantId = wxCUser.getTenantId(); + } + + // 请求参数 + Object[] args = jp.getArgs(); + // 接口 返回结果 + Object result; + String redisKey; + + //得到注释的名称 + MethodSignature signature = (MethodSignature) jp.getSignature(); + //判断tag是否在用户权限中 如果存在加入参数查询 + Method method = signature.getMethod(); + RedisCache cache = method.getAnnotation(RedisCache.class) ; + if (cache.autoKey()) { + // 构建 redisKey => reqPath:tenantId:md5(param1_param2_param3) + String requestUrl = request.getRequestURI(); + // 接口路径 reqPath => /api/xxx + String reqPath = requestUrl.substring(requestUrl.indexOf("/api/")); + if (cache.md5()) { + redisKey = StringUtils.join(reqPath, DELIMITER_KEY, tenantId, DELIMITER_KEY, HashUtil.md5(StringUtils.join(args, DELIMITER_PARAMS))); + } else { + redisKey = StringUtils.join(reqPath, DELIMITER_KEY, tenantId, DELIMITER_KEY, StringUtils.join(args, DELIMITER_PARAMS)); + } + } else { + redisKey = cache.key(); + } + + // redisKey 不存在,获取接口数据并返回 + if (StringUtils.isBlank(redisKey)) { + result = jp.proceed(args); + } else { + ValueOperations valueOperations = stringRedisTemplate.opsForValue(); + String value = valueOperations.get(redisKey); + if (value == null) { + String lockKey = StringUtils.join(redisKey, ":", "lock"); + long time = System.currentTimeMillis() + 2000; + String timeStr = String.valueOf(time); + try { + //分布式锁,保证一个线程读DB,其它线程排队 + if (redisLock.lock2(lockKey, timeStr)) { + log.debug("CacheAspect 读库中, key:{}: " + lockKey); + result = jp.proceed(args); + String json_data = JSONObject.toJSONString(result); + valueOperations.set(redisKey, json_data, cache.expireTime(), cache.dateUnit()); + log.debug("CacheAspect 缓存不存在,获取接口数据并放入缓存,key:{}, expire:{}", redisKey, cache.expireTime()); + } else { + log.debug("CacheAspect 读库等待中, key:{}: " + lockKey); + Thread.sleep(2000); + value = valueOperations.get(redisKey); + result = parseCache(jp, redisKey, value); + } + } catch (Throwable throwable) { + log.error("CacheAspect proceed error , Illegal argument: {} in {}.{}()", Arrays.toString(jp.getArgs()), + jp.getSignature().getDeclaringTypeName(), jp.getSignature().getName(), throwable); + throw throwable; + } finally { + redisLock.unlock(lockKey, timeStr); + } + } else { + result = parseCache(jp, redisKey, value); + } + // 计数器 + stringRedisTemplate.opsForHash().increment("hotapi", redisKey, 1); + } + return result; + } + + private Object parseCache(ProceedingJoinPoint jp, String redisKey, String value) { + if (StringUtils.isBlank(value)) { + log.debug("CacheAspect 缓存存在,解析缓存数据为空:{},key:{}", value, redisKey); + return null; + } + Class returnType = ((MethodSignature) jp.getSignature()).getReturnType(); + log.debug("CacheAspect 缓存存在,解析缓存并返回,key:{}", redisKey); + return JSONObject.parseObject(value, returnType); + } +} diff --git a/mallinkCApi/src/main/java/com/iformall/config/RedisConfig.java b/mallinkCApi/src/main/java/com/iformall/config/RedisConfig.java index 54f945030..f91b29800 100644 --- a/mallinkCApi/src/main/java/com/iformall/config/RedisConfig.java +++ b/mallinkCApi/src/main/java/com/iformall/config/RedisConfig.java @@ -16,6 +16,8 @@ import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.cache.RedisCacheWriter; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.ValueOperations; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; @@ -174,4 +176,31 @@ public class RedisConfig extends CachingConfigurerSupport { template.setConnectionFactory(connectionFactory); return template; } + + @Bean("pressOrderRedisTemplate") + public RedisTemplate getPressOrderRedisTemplate(RedisConnectionFactory connectionFactory) { + RedisTemplate template = new RedisTemplate<>(); + + Jackson2JsonRedisSerializer j = new Jackson2JsonRedisSerializer(WxOrder.class); + + // value值的序列化 + template.setValueSerializer(j); + template.setHashKeySerializer(j); + + // key的序列化 + template.setKeySerializer(new StringRedisSerializer()); + template.setHashKeySerializer(new StringRedisSerializer()); + + template.setConnectionFactory(connectionFactory); + return template; + } + + + @Bean("stringValueOperations") + public ValueOperations getStringValueOperations(RedisConnectionFactory connectionFactory) { + StringRedisTemplate template = new StringRedisTemplate(); + template.setConnectionFactory(connectionFactory); + template.afterPropertiesSet(); + return template.opsForValue(); + } } diff --git a/mallinkCApi/src/main/java/com/iformall/controller/WxBusinessController.java b/mallinkCApi/src/main/java/com/iformall/controller/WxBusinessController.java index d82b02018..aae158683 100644 --- a/mallinkCApi/src/main/java/com/iformall/controller/WxBusinessController.java +++ b/mallinkCApi/src/main/java/com/iformall/controller/WxBusinessController.java @@ -1,6 +1,7 @@ package com.iformall.controller; import com.github.pagehelper.PageInfo; +import com.iformall.annotation.RedisCache; import com.iformall.common.ResultData; import com.iformall.domain.po.WxBusiness; import com.iformall.domain.po.WxCUser; @@ -26,6 +27,7 @@ public class WxBusinessController extends BaseController { @Autowired private WxBusinessService wxBusinessService; + @RedisCache @ApiOperation("业态全列表接口") @GetMapping("listAll") public ResultData listAll(Integer filter) { diff --git a/mallinkCApi/src/main/java/com/iformall/controller/WxCampaignController.java b/mallinkCApi/src/main/java/com/iformall/controller/WxCampaignController.java index 5e32285b8..c0db1b156 100644 --- a/mallinkCApi/src/main/java/com/iformall/controller/WxCampaignController.java +++ b/mallinkCApi/src/main/java/com/iformall/controller/WxCampaignController.java @@ -1,6 +1,7 @@ package com.iformall.controller; import com.github.pagehelper.PageInfo; +import com.iformall.annotation.RedisCache; import com.iformall.common.Result; import com.iformall.common.ResultData; import com.iformall.domain.po.base.BaseEntity; @@ -38,6 +39,7 @@ public class WxCampaignController extends BaseController { @Autowired private WxCouponChannelService wxCouponChannelService; + @RedisCache @ApiOperation("分页列表接口") @GetMapping("list") @ApiImplicitParams({ diff --git a/mallinkCApi/src/main/java/com/iformall/controller/WxCarController.java b/mallinkCApi/src/main/java/com/iformall/controller/WxCarController.java index 9c9c681f4..c9b1809f7 100644 --- a/mallinkCApi/src/main/java/com/iformall/controller/WxCarController.java +++ b/mallinkCApi/src/main/java/com/iformall/controller/WxCarController.java @@ -704,10 +704,14 @@ public class WxCarController extends BaseController { String unionId = objParams.getString(BoLinkUtil.BOLINK_UNION_ID); String key = objParams.getString(BoLinkUtil.BOLINK_KEY); String ret = BoLinkUtil.getStopFee(url, comid, unionId, key, carNumber); - JSONObject retObj = JSON.parseObject(ret); - JSONObject dataObj = retObj.getJSONObject(BoLinkUtil.BOLINK_DATA); - if (dataObj.getIntValue(BoLinkUtil.BOLINK_STATE) == BoLinkUtil.BOLINK_SUCCESS) { - return new ResultData(dataObj); + if (ret != null) { + JSONObject retObj = JSON.parseObject(ret); + JSONObject dataObj = retObj.getJSONObject(BoLinkUtil.BOLINK_DATA); + if (dataObj.getIntValue(BoLinkUtil.BOLINK_STATE) == BoLinkUtil.BOLINK_SUCCESS) { + return new ResultData(dataObj); + } else { + return new ResultData(ErrorCode.BOLINK_STOP_FEE_FAIL); + } } else { return new ResultData(ErrorCode.BOLINK_STOP_FEE_FAIL); } diff --git a/mallinkCApi/src/main/java/com/iformall/controller/WxCouponChannelController.java b/mallinkCApi/src/main/java/com/iformall/controller/WxCouponChannelController.java index 996f9ac55..657395cca 100644 --- a/mallinkCApi/src/main/java/com/iformall/controller/WxCouponChannelController.java +++ b/mallinkCApi/src/main/java/com/iformall/controller/WxCouponChannelController.java @@ -1,6 +1,7 @@ package com.iformall.controller; import com.github.pagehelper.PageInfo; +import com.iformall.annotation.RedisCache; import com.iformall.common.ResultData; import com.iformall.domain.po.base.BaseEntity; import com.iformall.domain.po.WxCouponChannel; @@ -97,7 +98,7 @@ public class WxCouponChannelController extends BaseController { } } - + @RedisCache @ApiOperation("分页列表接口") @GetMapping("change") public ResultData change(@ModelAttribute WxCouponChannel wxCouponChannel) { diff --git a/mallinkCApi/src/main/java/com/iformall/controller/WxLiveController.java b/mallinkCApi/src/main/java/com/iformall/controller/WxLiveController.java new file mode 100755 index 000000000..fc239aadf --- /dev/null +++ b/mallinkCApi/src/main/java/com/iformall/controller/WxLiveController.java @@ -0,0 +1,69 @@ +package com.iformall.controller; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import com.iformall.annotation.RedisCache; +import com.iformall.common.ErrorCode; +import com.iformall.common.ResultData; +import com.iformall.domain.po.*; +import com.iformall.exception.MallinkException; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import me.chanjar.weixin.common.error.WxErrorException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.*; + +import java.util.concurrent.TimeUnit; + +@RestController +@RequestMapping("/api/live") +@Api(tags = "微信直播相关接口") +public class WxLiveController extends BaseController { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + /** + * 获取所有直播间和商品信息(没有分页直接获取全部) + * + * @return + */ + @ApiOperation("获取所有直播间和商品信息") + @RedisCache(expireTime = 30,dateUnit = TimeUnit.MINUTES) + @GetMapping("/roomList") + public ResultData getLiveinfos(String appId) { + ResultData resultData = new ResultData(); + try { + WxMaService wxMaService = getWeappService(appId); + resultData.data = wxMaService.getLiveService().getLiveinfos(); + } catch (WxErrorException e) { + logger.error("getLiveinfos error", e); + throw new MallinkException(ErrorCode.SYS_SERVER_ERROR); + } + return resultData; + } + + /** + * 获取直播房间回放数据信息. + *

+ * 获取回放 (默认:get_replay) + * + * @param room_id 直播间 id + * @param start 起始拉取视频,start = 0 表示从第 1 个视频片段开始拉取 + * @param limit 每次拉取的个数上限,不要设置过大,建议 100 以内 + * @return + */ + @ApiOperation("获取直播房间回放数据和商品信息") + @RedisCache(expireTime = 30,dateUnit = TimeUnit.MINUTES) + @GetMapping("/replayList") + public ResultData getLiveReplay(Integer room_id, Integer start, Integer limit) { + ResultData resultData = new ResultData(); + WxCUser user = getUser(); + try { + WxMaService wxMaService = getWeappService(user.getAppId()); + resultData.data = wxMaService.getLiveService().getLiveReplay(room_id,start,limit); + } catch (WxErrorException e) { + logger.error("getLiveReplay error", e); + throw new MallinkException(ErrorCode.SYS_SERVER_ERROR); + } + return resultData; + } +} diff --git a/mallinkCApi/src/main/java/com/iformall/controller/WxMallController.java b/mallinkCApi/src/main/java/com/iformall/controller/WxMallController.java index e203ad210..2f6b5813b 100644 --- a/mallinkCApi/src/main/java/com/iformall/controller/WxMallController.java +++ b/mallinkCApi/src/main/java/com/iformall/controller/WxMallController.java @@ -1,13 +1,12 @@ package com.iformall.controller; import com.iformall.annotation.AuthIgnore; +import com.iformall.annotation.RedisCache; import com.iformall.common.ErrorCode; import com.iformall.common.Result; import com.iformall.common.ResultData; import com.iformall.domain.po.*; import com.iformall.domain.po.base.TenantEntity; -import com.iformall.domain.vo.WxMerchantVo; -import com.iformall.enums.EnumMerchantStatus; import com.iformall.service.*; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; @@ -16,13 +15,9 @@ 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.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; @RestController @RequestMapping("/api/mall") @@ -45,6 +40,10 @@ public class WxMallController extends BaseController { @Autowired private WxLevelConfigService wxLevelConfigService; + @Autowired + private RedisService redisService; + + @RedisCache @AuthIgnore @ApiOperation("商场图标") @GetMapping("/getAppIcon") @@ -64,6 +63,7 @@ public class WxMallController extends BaseController { return new ResultData(Result.SUCCESS, "查询成功", resultMap); } + @RedisCache @AuthIgnore @ApiOperation("商场提示信息") @GetMapping("/getWeapNote") @@ -82,6 +82,7 @@ public class WxMallController extends BaseController { return new ResultData(Result.SUCCESS, "查询成功", resultMap); } + @RedisCache @ApiOperation("商场信息") @GetMapping("/mallInfo") public ResultData getMallInfo() { @@ -113,7 +114,7 @@ public class WxMallController extends BaseController { return new ResultData(Result.SUCCESS, "查询成功", map); } - + @RedisCache() @AuthIgnore @ApiOperation("获取后端版本号") @GetMapping("/version") @@ -121,5 +122,16 @@ public class WxMallController extends BaseController { return new ResultData(version); } + @ApiOperation("获取热点缓存接口对应redis key") + @GetMapping("/hotApis") + public ResultData hotApis() { + return new ResultData(redisService.hotApi()); + } + + @ApiOperation("删除指定key") + @PostMapping("/delRedisKey") + public ResultData delRedisKey(@RequestBody Collection keys) { + return new ResultData(redisService.delRedisKey(keys)); + } } diff --git a/mallinkCApi/src/main/java/com/iformall/controller/WxPressOrderController.java b/mallinkCApi/src/main/java/com/iformall/controller/WxPressOrderController.java index cd6a448db..50661e33b 100644 --- a/mallinkCApi/src/main/java/com/iformall/controller/WxPressOrderController.java +++ b/mallinkCApi/src/main/java/com/iformall/controller/WxPressOrderController.java @@ -2,15 +2,16 @@ package com.iformall.controller; import com.iformall.common.ErrorCode; import com.iformall.common.ResultData; -import com.iformall.domain.po.WxCUser; -import com.iformall.domain.po.WxCoupon; import com.iformall.domain.po.WxOrder; +import com.iformall.domain.po.WxOrderPress; +import com.iformall.domain.vo.WxCouponCVo; import com.iformall.enums.EnumOrderPressStatus; import com.iformall.enums.EnumOrderStatus; import com.iformall.exception.MallinkException; import com.iformall.service.WxCouponService; import com.iformall.service.WxOrderPressService; import com.iformall.service.WxOrderService; +import com.iformall.utils.RedisLock; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiOperation; @@ -18,11 +19,16 @@ import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; import java.util.Date; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.TimeUnit; @RestController @RequestMapping("/api/press") @@ -39,6 +45,17 @@ public class WxPressOrderController extends BaseController { @Autowired WxOrderPressService wxOrderPressService; + @Autowired + @Qualifier("pressOrderRedisTemplate") + RedisTemplate orderRedisTemplate; + + @Autowired + @Qualifier("couponDetailRedisTemplate") + RedisTemplate couponCVoRedisTemplate; + + @Autowired + RedisLock redisLock; + // 砍价列表 - /api/wxCouponChannel/list // 我的砍价 - /api/order/pressOrderList // 砍价订单详情 - /api/order/pressOrderDetail @@ -49,6 +66,7 @@ public class WxPressOrderController extends BaseController { @ApiOperation(value = "参与砍价", notes = "{\"orderId\":\"String\"}") @PostMapping("pressOrderJoin") + @Transactional public ResultData pressOrderJoin(@RequestBody Map paramMap) { Date curDate = new Date(); String orderIdStr = paramMap.get("orderId"); @@ -56,19 +74,50 @@ public class WxPressOrderController extends BaseController { return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "orderId不能为空"); } Long orderId = 0L; + WxOrder order = null; try { orderId = Long.valueOf(orderIdStr); } catch (NumberFormatException e) { logger.error("orderId convert error, " + orderIdStr + ", e:" + e.getMessage()); return new ResultData(ErrorCode.SYS_PARAMETER_CAST_ERROR.getCode(), "orderId: " + orderIdStr + ", e:" + e.getMessage()); } - WxOrder order = wxOrderService.getById(orderId); + String key = "pressorder:" + orderId; + ValueOperations operations = orderRedisTemplate.opsForValue(); + // 缓存 + boolean hasKey = orderRedisTemplate.hasKey(key); + if (hasKey) { + // 从缓存获取砍价订单信息 + order = operations.get(key); + } else { + // 订单没有入缓存,需要从数据库中读取 + order = wxOrderService.getById(orderId); + if (order != null) { + // 订单优化,进缓存 + orderRedisTemplate.opsForValue().set(key, order, 3600, TimeUnit.SECONDS); + } + } if(order == null) { logger.error("订单不存在:" + orderId); return new ResultData(ErrorCode.ORDER_IS_NOT_FIND); } - WxCoupon coupon = wxCouponService.getById(order.getProductId()); - if(coupon == null) { + WxCouponCVo wxCouponCVo = null; + String cdKey = "cd:" + order.getProductId(); + + ValueOperations cdOperations = couponCVoRedisTemplate.opsForValue(); + // 缓存 + boolean cdHasKey = couponCVoRedisTemplate.hasKey(cdKey); + if (cdHasKey) { + // 从缓存获取券信息 + wxCouponCVo = cdOperations.get(cdKey); + } else { + // 券信息没有入缓存,需要从数据库中读取 + wxCouponCVo = wxCouponService.getVoById(order.getProductId()); + if (wxCouponCVo != null) { + // 券详情优化,进缓存 + couponCVoRedisTemplate.opsForValue().set(cdKey, wxCouponCVo, 3600, TimeUnit.SECONDS); + } + } + if(wxCouponCVo == null) { logger.error("券不存在:" + order.getProductId()); return new ResultData(ErrorCode.COUPON_IS_EMPTY); } @@ -93,21 +142,86 @@ public class WxPressOrderController extends BaseController { return new ResultData(ErrorCode.ORDER_HAD_CANCEL); } - if(order.getPressCurrentNum() + 1 > coupon.getPressLimitNum()) { + if(order.getPressCurrentNum() + 1 > wxCouponCVo.getPressLimitNum()) { logger.error("砍价已结束:" + orderId); return new ResultData(ErrorCode.COUPON_PRESS_HAD_FINISHED); } + long time = System.currentTimeMillis() + RedisLock.TIMEOUT; + String timeStr = String.valueOf(time); + if (!redisLock.lock(orderIdStr, timeStr)) { + logger.error("此砍价订单被锁定, orderId: " + orderIdStr); + return new ResultData(ErrorCode.TOO_MANY_REQUEST); + } + + Long cUserId = getUserId(); + // 检查此人是否已参与砍价 + boolean hadJoin = wxOrderPressService.checkCUserHasJoin(order, cUserId); + if (hadJoin) { + redisLock.unlock(orderIdStr, timeStr); + logger.error("用户已参与砍价"); + return new ResultData(ErrorCode.COUPON_PRESS_IS_EXIST); + } + try { - wxOrderPressService.pressCouponJoin(order, coupon, getUserId()); + WxOrderPress orderPress = wxOrderPressService.pressCouponJoin(order, wxCouponCVo, cUserId); + if (orderPress != null) { + // 更新砍价信息 + Integer index = order.getPressCurrentNum() + 1; + if(index < wxCouponCVo.getPressLimitNum()) { + // 未完成 + order.setId(order.getId()); + order.setPressCurrentNum(index); + order.setPressCurrentValue(order.getPressCurrentValue() - orderPress.getPressValue()); + order.setOrderStatus(EnumOrderStatus.ORDER_STATUS_PRESSING.getCode()); + order.setUpdateDate(new Date()); + orderRedisTemplate.opsForValue().set(key, order, 3600, TimeUnit.SECONDS); + updatePressOrderPressing(order, index); + } else { + order.setPressCurrentNum(index); + order.setPressCurrentValue(order.getPressCurrentValue() - orderPress.getPressValue()); + order.setOrderStatus(EnumOrderStatus.ORDER_STATUS_PRESS_COMPLETE.getCode()); + order.setUpdateDate(curDate); + orderRedisTemplate.opsForValue().set(key, order, 3600, TimeUnit.SECONDS); + updatePressOrderComplete(order, wxCouponCVo, index); + } + } } catch (MallinkException e) { + redisLock.unlock(orderIdStr, timeStr); logger.error(e.getMessage()); return new ResultData(e.getErrorCode(), e.getMessage()); } - + redisLock.unlock(orderIdStr, timeStr); return new ResultData(); } + private void updatePressOrderPressing(WxOrder order, Integer index) { + WxOrder orderUpdatePress = new WxOrder(); + orderUpdatePress.setId(order.getId()); + orderUpdatePress.setPressCurrentNum(index); + orderUpdatePress.setPressCurrentValue(order.getPressCurrentValue()); + orderUpdatePress.setOrderStatus(EnumOrderStatus.ORDER_STATUS_PRESSING.getCode()); + orderUpdatePress.setUpdateDate(new Date()); + // 保存订单 + wxOrderService.saveOrUpdate(orderUpdatePress); + } + + private void updatePressOrderComplete(WxOrder order, WxCouponCVo wxCouponCVo, Integer index) { + WxOrder orderUpdatePress = new WxOrder(); + orderUpdatePress.setId(order.getId()); + orderUpdatePress.setPressCurrentNum(index); + orderUpdatePress.setPressCurrentValue(order.getPressCurrentValue()); + orderUpdatePress.setOrderStatus(EnumOrderStatus.ORDER_STATUS_PRESS_COMPLETE.getCode()); + orderUpdatePress.setPayment(wxCouponCVo.getSalePrice()); + orderUpdatePress.setUpdateDate(new Date()); + // 保存订单 + wxOrderService.saveOrUpdate(orderUpdatePress); + // 发送砍价成功消息 + if(index.equals(wxCouponCVo.getPressLimitNum())) { + wxOrderPressService.sendPressComplateMsg(orderUpdatePress); + } + } + @ApiOperation(value = "砍价状态(1:我发起的砍价,2:未参与的砍价, 3:已参与的砍价)", notes = "") @GetMapping("getPressOrderStatus") @ApiImplicitParam(name = "orderId", value = "orderId", dataType = "String", paramType = "query", required = true) diff --git a/mallinkCApi/src/main/java/com/iformall/controller/WxUserGrantController.java b/mallinkCApi/src/main/java/com/iformall/controller/WxUserGrantController.java index b119869b7..56abf8d50 100755 --- a/mallinkCApi/src/main/java/com/iformall/controller/WxUserGrantController.java +++ b/mallinkCApi/src/main/java/com/iformall/controller/WxUserGrantController.java @@ -8,6 +8,7 @@ import cn.binarywang.wx.miniapp.util.crypt.WxMaCryptUtils; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.iformall.annotation.AuthIgnore; +import com.iformall.annotation.RedisCache; import com.iformall.common.ErrorCode; import com.iformall.common.Result; import com.iformall.common.ResultData; @@ -633,6 +634,7 @@ public class WxUserGrantController extends BaseController { return new ResultData(Result.SUCCESS, "是老用户,已完成手机号授权", resultMap); } + @RedisCache @ApiOperation("获取当前用户信息") @GetMapping("/userinfo") public ResultData getUserInfo() { diff --git a/mallinkCallback/pom.xml b/mallinkCallback/pom.xml index 328265111..261915bfe 100644 --- a/mallinkCallback/pom.xml +++ b/mallinkCallback/pom.xml @@ -13,8 +13,8 @@ mallinkCallback - 3.7.0 - 3.7.0 + 3.7.0.B + 3.7.0.B diff --git a/mallinkService/src/main/java/com/iformall/common/ErrorCode.java b/mallinkService/src/main/java/com/iformall/common/ErrorCode.java index bf3948edd..768ff112e 100644 --- a/mallinkService/src/main/java/com/iformall/common/ErrorCode.java +++ b/mallinkService/src/main/java/com/iformall/common/ErrorCode.java @@ -236,6 +236,7 @@ public enum ErrorCode{ COUPON_PASSWORD_NOT_FOUND(9501, "兑换码未找到"), COUPON_PASSWORD_HAD_USED(9502, "兑换码已使用"), COUPON_PASSWORD_IS_CANCELED(9503, "兑换码已作废"), + COUPON_PASSWORD_POSTPONE_ERR(9504, "卡密延期异常"), /** * 微信 diff --git a/mallinkService/src/main/java/com/iformall/domain/po/WxMerchant.java b/mallinkService/src/main/java/com/iformall/domain/po/WxMerchant.java index fee496f1e..23be5e82a 100644 --- a/mallinkService/src/main/java/com/iformall/domain/po/WxMerchant.java +++ b/mallinkService/src/main/java/com/iformall/domain/po/WxMerchant.java @@ -81,7 +81,7 @@ public class WxMerchant extends TenantEntity { } @TableField(exist = false) - @Excel(name="账户类型",width = 20,orderNum = "7",replace = {"_null","商户号_0","微信号_1"}) + @Excel(name="账户类型",width = 20,orderNum = "7",replace = {"_null","商户号_0","微信号_1","OPENID_3"}) @io.swagger.annotations.ApiModelProperty(value="账户类型",name="accountTypeValue") private Integer accountTypeValue; diff --git a/mallinkService/src/main/java/com/iformall/domain/vo/WxOrderPayExpVo.java b/mallinkService/src/main/java/com/iformall/domain/vo/WxOrderPayExpVo.java new file mode 100644 index 000000000..0c727dd52 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/domain/vo/WxOrderPayExpVo.java @@ -0,0 +1,67 @@ +package com.iformall.domain.vo; + +import com.iformall.domain.po.WxOrder; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Data +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public class WxOrderPayExpVo extends WxOrder { + + /** 发券商户信息 */ + @ApiModelProperty(value="商户名",name="merchantName") + private String merchantName; + @ApiModelProperty(value="b端用户姓名",name="bUserName") + private String bUserName; + @ApiModelProperty(value="b端用户手机号",name="bUserPhone") + private String bUserPhone; + + /** c端用户信息 */ + @ApiModelProperty(value="c用户绑定的手机号",name="cUserPhone") + private String cUserPhone; + @ApiModelProperty(value="c用户昵称",name="nickName") + private String nickName; + @ApiModelProperty(value="c用户名",name="cUserName") + private String cUserName; + + @ApiModelProperty(value ="支付订单ID", name = "payOrderId") + private Long payOrderId; + @ApiModelProperty(value ="微信支付订单ID", name = "transactionId") + private String transactionId; + + public static enum Field + { + Id_ASC("`id` ASC"),Id_DESC("`id` DESC") + ,OrderNumber_ASC("`order_number` ASC"),OrderNumber_DESC("`order_number` DESC") + ,TenantId_ASC("`tenant_id` ASC"),TenantId_DESC("`tenant_id` DESC") + ,CUserId_ASC("`c_user_id` ASC"),CUserId_DESC("`c_user_id` DESC") + ,CouponId_ASC("`product_id` ASC"),CouponId_DESC("`product_id` DESC") + ,PaymentType_ASC("`payment_type` ASC"),PaymentType_DESC("`payment_type` DESC") + ,Payment_ASC("`payment` ASC"),Payment_DESC("`payment` DESC") + ,PaymentTime_ASC("`payment_time` ASC"),PaymentTime_DESC("`payment_time` DESC") + ,OrderStatus_ASC("`order_status` ASC"),OrderStatus_DESC("`order_status` DESC") + ,CreateDate_ASC("`create_date` ASC"),CreateDate_DESC("`create_date` DESC") + ,UpdateDate_ASC("`update_date` ASC"),UpdateDate_DESC("`update_date` DESC") + ,Detail_ASC("`detail` ASC"),Detail_DESC("`detail` DESC") + ; + private String value; + Field(String value){ + this.value = value; + } + public String getValue() { + return value; + } + public void setCol(String value) { + this.value = value; + } + @Override + public String toString() { + return this.getValue(); + } + } + + +} diff --git a/mallinkService/src/main/java/com/iformall/domain/vo/WxOrderPayVo.java b/mallinkService/src/main/java/com/iformall/domain/vo/WxOrderPayVo.java index 461fa4235..e281c1bfa 100644 --- a/mallinkService/src/main/java/com/iformall/domain/vo/WxOrderPayVo.java +++ b/mallinkService/src/main/java/com/iformall/domain/vo/WxOrderPayVo.java @@ -1,6 +1,7 @@ package com.iformall.domain.vo; import com.iformall.domain.po.WxOrder; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; @@ -13,20 +14,19 @@ import java.util.List; public class WxOrderPayVo extends WxOrder { /**发券商户信息*/ - @io.swagger.annotations.ApiModelProperty(value="商户名",name="merchantName") + @ApiModelProperty(value="商户名",name="merchantName") private String merchantName; - @io.swagger.annotations.ApiModelProperty(value="b端用户姓名",name="bUserName") + @ApiModelProperty(value="b端用户姓名",name="bUserName") private String bUserName; - @io.swagger.annotations.ApiModelProperty(value="b端用户手机号",name="bUserPhone") + @ApiModelProperty(value="b端用户手机号",name="bUserPhone") private String bUserPhone; - @io.swagger.annotations.ApiModelProperty(value="c用户绑定的手机号",name="cUserPhone") + @ApiModelProperty(value="c用户绑定的手机号",name="cUserPhone") private String cUserPhone; - - @io.swagger.annotations.ApiModelProperty(value="c用户昵称",name="nickName") + @ApiModelProperty(value="c用户昵称",name="nickName") private String nickName; - @io.swagger.annotations.ApiModelProperty(value="c用户名",name="cUserName") + @ApiModelProperty(value="c用户名",name="cUserName") private String cUserName; public static enum Field diff --git a/mallinkService/src/main/java/com/iformall/mapper/WxCouponPasswordMapper.java b/mallinkService/src/main/java/com/iformall/mapper/WxCouponPasswordMapper.java index 8088ecaa4..973bc37d6 100644 --- a/mallinkService/src/main/java/com/iformall/mapper/WxCouponPasswordMapper.java +++ b/mallinkService/src/main/java/com/iformall/mapper/WxCouponPasswordMapper.java @@ -21,4 +21,6 @@ public interface WxCouponPasswordMapper extends CommonMapper tempList); + void updatePostpone(WxCouponPassword wxCouponPassword); + } diff --git a/mallinkService/src/main/java/com/iformall/mapper/WxOrderMapper.java b/mallinkService/src/main/java/com/iformall/mapper/WxOrderMapper.java index f2566be8c..4dbc72579 100644 --- a/mallinkService/src/main/java/com/iformall/mapper/WxOrderMapper.java +++ b/mallinkService/src/main/java/com/iformall/mapper/WxOrderMapper.java @@ -24,8 +24,10 @@ public interface WxOrderMapper extends CommonMapper { List findListOfCUser(WxOrder wxOrder); List selectDetailOfCUser(WxOrder wxOrder); + /** B端收银台(收款码支付) */ Map dayMicroPayAmountList(Map dateMap); List findListOfMicroPayOrderByDate(Map dateMap); + List findListOfExpMicroPayOrderByDate(Map dateMap); List queryForSceneRepotyHistory(HashMap params); diff --git a/mallinkService/src/main/java/com/iformall/mapper/WxPayOrderMapper.java b/mallinkService/src/main/java/com/iformall/mapper/WxPayOrderMapper.java index d48968637..59c5e1d21 100644 --- a/mallinkService/src/main/java/com/iformall/mapper/WxPayOrderMapper.java +++ b/mallinkService/src/main/java/com/iformall/mapper/WxPayOrderMapper.java @@ -12,4 +12,6 @@ public interface WxPayOrderMapper extends CommonMapper { List findListOfPaidOrderByDate(Map dateMap); List findListForUnPs(WxPayOrder wxPayOrder); + + List findExpListForMicroPay(WxPayOrder wxPayOrder); } diff --git a/mallinkService/src/main/java/com/iformall/pay/WxPayOrderQ.java b/mallinkService/src/main/java/com/iformall/pay/WxPayOrderQ.java index e00512413..10ee2ea5c 100644 --- a/mallinkService/src/main/java/com/iformall/pay/WxPayOrderQ.java +++ b/mallinkService/src/main/java/com/iformall/pay/WxPayOrderQ.java @@ -11,6 +11,7 @@ public class WxPayOrderQ { private String mch_id; // 商户号 private String nonce_str; // 随机字符串 private String sign; // 签名 + private String transaction_id; // 微信订单号 private String out_trade_no; // 商户订单号 @Override diff --git a/mallinkService/src/main/java/com/iformall/pay/WxPayOrderSQ.java b/mallinkService/src/main/java/com/iformall/pay/WxPayOrderSQ.java index 4143b8697..62e2cf1c0 100644 --- a/mallinkService/src/main/java/com/iformall/pay/WxPayOrderSQ.java +++ b/mallinkService/src/main/java/com/iformall/pay/WxPayOrderSQ.java @@ -14,6 +14,7 @@ public class WxPayOrderSQ { private String nonce_str; // 随机字符串 private String sign; // 签名 private String sign_type; // 签名类型 + private String transaction_id; // 微信订单号 private String out_trade_no; // 商户订单号 @Override @@ -26,6 +27,7 @@ public class WxPayOrderSQ { sb.append(", nonce_str='").append(nonce_str).append('\''); sb.append(", sign='").append(sign).append('\''); sb.append(", out_trade_no='").append(out_trade_no).append('\''); + sb.append(", transtion_id='").append(out_trade_no).append('\''); sb.append('}'); return sb.toString(); } diff --git a/mallinkService/src/main/java/com/iformall/service/ExcelService.java b/mallinkService/src/main/java/com/iformall/service/ExcelService.java index 720e2aea3..0116856b8 100644 --- a/mallinkService/src/main/java/com/iformall/service/ExcelService.java +++ b/mallinkService/src/main/java/com/iformall/service/ExcelService.java @@ -76,6 +76,7 @@ public class ExcelService { response.getOutputStream().write(new byte[] { (byte) 0xEF, (byte) 0xBB,(byte) 0xBF }); // csv 乱码问题 CsvExportUtil.exportCsv(exportParams, pojoClass, list, response.getOutputStream()); } catch (IOException e) { + logger.error("defaultExportCsv error ",e); throw new MallinkException(ErrorCode.EXCEL_EXPORT_ERROR.getCode(), e.getMessage()); } } diff --git a/mallinkService/src/main/java/com/iformall/service/RedisService.java b/mallinkService/src/main/java/com/iformall/service/RedisService.java new file mode 100644 index 000000000..d1bd09801 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/RedisService.java @@ -0,0 +1,23 @@ +package com.iformall.service; + +import java.util.Collection; +import java.util.List; +import java.util.Set; + +public interface RedisService { + + String KEY_HOT_API = "hotapi" ; + + /** + * 获取热点缓存接口列表 + * @return + */ + Collection hotApi() ; + + /** + * 清除指定key + * @param keys + * @return + */ + boolean delRedisKey(Collection keys) ; +} diff --git a/mallinkService/src/main/java/com/iformall/service/WxCouponPasswordService.java b/mallinkService/src/main/java/com/iformall/service/WxCouponPasswordService.java index 5f8006d66..6e99efbb3 100644 --- a/mallinkService/src/main/java/com/iformall/service/WxCouponPasswordService.java +++ b/mallinkService/src/main/java/com/iformall/service/WxCouponPasswordService.java @@ -70,4 +70,6 @@ public interface WxCouponPasswordService { PageInfo findCouponList(WxCouponPassword wxCouponPassword, Integer pageNum, Integer pageSize); List findList(WxCouponPassword wxCouponPassword); + + void postpone(WxCouponPassword wxCouponPassword); } diff --git a/mallinkService/src/main/java/com/iformall/service/WxOrderPressService.java b/mallinkService/src/main/java/com/iformall/service/WxOrderPressService.java index ab0313ec0..5c4b2133e 100644 --- a/mallinkService/src/main/java/com/iformall/service/WxOrderPressService.java +++ b/mallinkService/src/main/java/com/iformall/service/WxOrderPressService.java @@ -47,7 +47,7 @@ public interface WxOrderPressService { * @param coupon * @param cUserId */ - void pressCouponJoin(WxOrder order, WxCoupon coupon, Long cUserId); + WxOrderPress pressCouponJoin(WxOrder order, WxCoupon coupon, Long cUserId); /** * 检查用户砍价状态 @@ -55,6 +55,10 @@ public interface WxOrderPressService { * @param cUserId */ int pressCouponStatus(WxOrder order, Long cUserId); + + boolean checkCUserHasJoin(WxOrder order, Long cUserId); + + void sendPressComplateMsg(WxOrder orderUpdatePress); diff --git a/mallinkService/src/main/java/com/iformall/service/WxOrderService.java b/mallinkService/src/main/java/com/iformall/service/WxOrderService.java index 109325204..28ecccc3c 100644 --- a/mallinkService/src/main/java/com/iformall/service/WxOrderService.java +++ b/mallinkService/src/main/java/com/iformall/service/WxOrderService.java @@ -37,6 +37,14 @@ public interface WxOrderService { ResultData microPayListOnDateAsPage(Long bUserId, Integer type, String date, Integer pageIndex, Integer pageSize); + /** + * 根据日期 b用户查刷卡异常支付list + * + * @param bUserId B端用户) + */ + + ResultData microPayExpListOnDateAsPage(Long bUserId, Integer type, String date, Integer pageIndex, Integer pageSize); + /** * 付款码支付 * @param user @@ -106,6 +114,14 @@ public interface WxOrderService { * @return */ WxOrder getById(Long id); + + /** + * 根据Id获得实体 + * + * @param id + * @return + */ + WxOrder getPressOrderById(Long id); /** * 保存或更新实体 diff --git a/mallinkService/src/main/java/com/iformall/service/impl/RedisServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/RedisServiceImpl.java new file mode 100644 index 000000000..4d3a905ee --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/impl/RedisServiceImpl.java @@ -0,0 +1,46 @@ +package com.iformall.service.impl; + +import com.iformall.service.RedisService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.data.redis.core.RedisOperations; +import org.springframework.data.redis.core.SessionCallback; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.List; +import java.util.Set; + +@Slf4j +@Service +public class RedisServiceImpl implements RedisService { + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + @Override + public Collection hotApi() { + return stringRedisTemplate.opsForHash().keys(KEY_HOT_API); + } + + @Override + public boolean delRedisKey(Collection keys) { + if (CollectionUtils.isEmpty(keys)) { + return false; + } + boolean result = stringRedisTemplate.execute(new SessionCallback() { + @Override + public Boolean execute(RedisOperations redisOperations) throws DataAccessException { + redisOperations.multi(); + redisOperations.opsForValue().getOperations().delete(keys); + redisOperations.opsForHash().delete(KEY_HOT_API, keys.toArray()); + redisOperations.exec(); + return true ; + } + }); + return result; + } +} diff --git a/mallinkService/src/main/java/com/iformall/service/impl/WxCouponPasswordServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/WxCouponPasswordServiceImpl.java index 6c02b00b0..44aeebedb 100644 --- a/mallinkService/src/main/java/com/iformall/service/impl/WxCouponPasswordServiceImpl.java +++ b/mallinkService/src/main/java/com/iformall/service/impl/WxCouponPasswordServiceImpl.java @@ -167,6 +167,11 @@ public class WxCouponPasswordServiceImpl implements WxCouponPasswordService { return wxCouponPasswordMapper.findList(wxCouponPassword); } + @Override + public void postpone(WxCouponPassword wxCouponPassword) { + + } + /* public static void main(String[] args) { WxCouponPasswordServiceImpl ll = new WxCouponPasswordServiceImpl(); diff --git a/mallinkService/src/main/java/com/iformall/service/impl/WxOrderPressServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/WxOrderPressServiceImpl.java index 42dc0e54c..2eb8afc17 100644 --- a/mallinkService/src/main/java/com/iformall/service/impl/WxOrderPressServiceImpl.java +++ b/mallinkService/src/main/java/com/iformall/service/impl/WxOrderPressServiceImpl.java @@ -24,11 +24,14 @@ import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; +import java.util.concurrent.TimeUnit; @Service public class WxOrderPressServiceImpl implements WxOrderPressService { @@ -52,7 +55,6 @@ public class WxOrderPressServiceImpl implements WxOrderPressService { @Autowired MqBaseProducer mqBaseProducer; - @Override public PageInfo listAsPage(WxOrderPress record, Integer pageIndex, Integer pageSize) { return PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> wxOrderPressMapper.findList(record)); @@ -82,25 +84,12 @@ public class WxOrderPressServiceImpl implements WxOrderPressService { @Override - public void pressCouponJoin(WxOrder order, WxCoupon coupon, Long cUserId) { + public WxOrderPress pressCouponJoin(WxOrder order, WxCoupon coupon, Long cUserId) { final IdWorker idWorker = IdWorker.get(); Date curDate = new Date(); - // 检查此人是否已参与砍价 - WxOrderPress orderPressQ = new WxOrderPress(); - orderPressQ.setTenantId(order.getTenantId()); - orderPressQ.setOrderId(order.getId()); - orderPressQ.setUserId(cUserId); - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.setEntity(orderPressQ); - int count = wxOrderPressMapper.selectCount(queryWrapper); - if(count >= 1) { - logger.error("用户已参与砍价: " + cUserId); - throw new MallinkException(ErrorCode.COUPON_PRESS_IS_EXIST); - } // 添加 wx_order_press int total = coupon.getPrice() - coupon.getSalePrice(); - int left_total = order.getPressCurrentValue(); WxOrderPress orderPress = new WxOrderPress(); orderPress.setId(idWorker.nextId()); orderPress.setTenantId(order.getTenantId()); @@ -109,7 +98,7 @@ public class WxOrderPressServiceImpl implements WxOrderPressService { orderPress.setUserId(cUserId); orderPress.setCreateDate(curDate); orderPress.setFirst(EnumOrderPressType.NORMAL.getCode()); - orderPress.setPressValue(PressUtils.stateLessPressValue(total, left_total, coupon.getPressLimitNum(), order.getPressCurrentNum())); + orderPress.setPressValue(PressUtils.stateLessPressValue(total, order.getPressCurrentValue(), coupon.getPressLimitNum(), order.getPressCurrentNum())); try { // 保存订单 @@ -118,30 +107,20 @@ public class WxOrderPressServiceImpl implements WxOrderPressService { logger.error("保存砍价记录Error:" + e.getMessage()); throw new MallinkException(ErrorCode.DB_FAIL); } + return orderPress; + } - // 更新砍价信息 - Integer index = order.getPressCurrentNum() + 1; - WxOrder orderUpdatePress = new WxOrder(); - orderUpdatePress.setId(order.getId()); - orderUpdatePress.setPressCurrentNum(index); - orderUpdatePress.setPressCurrentValue(left_total - orderPress.getPressValue()); - if(index.equals(coupon.getPressLimitNum())) { - orderUpdatePress.setOrderStatus(EnumOrderStatus.ORDER_STATUS_PRESS_COMPLETE.getCode()); - orderUpdatePress.setPayment(coupon.getSalePrice()); + @Override + public boolean checkCUserHasJoin(WxOrder order, Long cUserId) { + WxOrderPress orderPressQ = new WxOrderPress(); + orderPressQ.setTenantId(order.getTenantId()); + orderPressQ.setOrderId(order.getId()); + orderPressQ.setUserId(cUserId); + int count = wxOrderPressMapper.selectCount(new QueryWrapper<>(orderPressQ)); + if(count >= 1) { + return true; } else { - orderUpdatePress.setOrderStatus(EnumOrderStatus.ORDER_STATUS_PRESSING.getCode()); - } - orderUpdatePress.setUpdateDate(new Date()); - try { - // 保存订单 - wxOrderMapper.updateById(orderUpdatePress); - } catch (RuntimeException e) { - logger.error("更新订单Error:" + e.getMessage()); - throw new MallinkException(ErrorCode.DB_FAIL); - } - // 发送砍价成功消息 - if(index.equals(coupon.getPressLimitNum())) { - sendPressComplateMsg(orderUpdatePress); + return false; } } @@ -167,7 +146,8 @@ public class WxOrderPressServiceImpl implements WxOrderPressService { * * @param */ - private void sendPressComplateMsg(WxOrder orderUpdatePress) { + @Override + public void sendPressComplateMsg(WxOrder orderUpdatePress) { // 1. get order info WxOrder order = wxOrderMapper.selectById(orderUpdatePress.getId()); if (order == null) { diff --git a/mallinkService/src/main/java/com/iformall/service/impl/WxOrderServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/WxOrderServiceImpl.java index e1839f4b0..fec3ae16c 100644 --- a/mallinkService/src/main/java/com/iformall/service/impl/WxOrderServiceImpl.java +++ b/mallinkService/src/main/java/com/iformall/service/impl/WxOrderServiceImpl.java @@ -201,6 +201,68 @@ public class WxOrderServiceImpl implements WxOrderService { return new ResultData(resultMap); } + @Override + public ResultData microPayExpListOnDateAsPage(Long bUserId, Integer type, String date, Integer pageIndex, Integer pageSize) { + WxMerchantBUser wxMerchantBUser = wxMerchantBUserMapper.selectById(bUserId.longValue()); + if (wxMerchantBUser == null) { + logger.error("B端用户不存在:" + bUserId); + throw new MallinkException(ErrorCode.MERCHANT_INFO_NOT_FOUND); + } + + WxMerchant wxMerchant = wxMerchantMapper.selectById(wxMerchantBUser.getMerchantId()); + if (wxMerchant == null) { + logger.error("商户不存在:" + bUserId); + throw new MallinkException(ErrorCode.MERCHANT_INFO_NOT_FOUND); + } + + SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd"); + String dateString; + Date startDate; + Date endDate; + + if (date == null) { + endDate = new Date(); + dateString = fmt.format(new Date()); + try { + startDate = fmt.parse(dateString); + } catch (ParseException e) { + return new ResultData(ErrorCode.SYS_PARAMETER_CAST_ERROR); + } + } else { + try { + startDate = fmt.parse(date); + } catch (ParseException e) { + return new ResultData(ErrorCode.SYS_PARAMETER_CAST_ERROR); + } + Calendar cal = Calendar.getInstance(); + cal.setTime(startDate); + cal.add(Calendar.DATE, 1); + endDate = cal.getTime(); + } + + Map dateMap = new HashMap(); + dateMap.put("startDate", startDate); + dateMap.put("endDate", endDate); + dateMap.put("merchantId", wxMerchant.getId()); + dateMap.put("type", type); + + Map resultMap = new HashMap(); + + if (pageIndex == null || pageSize == null) { + List list; + list = wxOrderMapper.findListOfExpMicroPayOrderByDate(dateMap); + logger.info("find " + list.size() + " order from " + startDate + " to " + new Date()); + int total_price = 0; + for (WxOrder order : list) { + total_price = total_price + order.getPayment(); + } + resultMap.put("amount", total_price); + } else { + resultMap.put("list", PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> wxOrderMapper.findListOfExpMicroPayOrderByDate(dateMap))); + } + return new ResultData(resultMap); + } + /** * 拼团数量 * @@ -1365,6 +1427,12 @@ public class WxOrderServiceImpl implements WxOrderService { return wxOrderMapper.selectById(id); } + @Override + public WxOrder getPressOrderById(Long id) { + + return wxOrderMapper.selectById(id); + } + @Override public void saveOrUpdate(WxOrder record) { if (record.getId() == null) { diff --git a/mallinkService/src/main/java/com/iformall/service/impl/WxPayOrderServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/WxPayOrderServiceImpl.java index febfcbcb9..a1a30978f 100644 --- a/mallinkService/src/main/java/com/iformall/service/impl/WxPayOrderServiceImpl.java +++ b/mallinkService/src/main/java/com/iformall/service/impl/WxPayOrderServiceImpl.java @@ -646,7 +646,11 @@ public class WxPayOrderServiceImpl implements WxPayOrderService { payOrderQ.setAppid(appInfo.getAppId()); payOrderQ.setMch_id(payAccount.getMchId()); payOrderQ.setNonce_str(noncestr); - payOrderQ.setOut_trade_no(record.getPayOrderNo()); + if (StringUtils.isNotBlank(record.getTransactionId())) { + payOrderQ.setTransaction_id(record.getTransactionId()); + } else { + payOrderQ.setOut_trade_no(record.getPayOrderNo()); + } try { Map map = BeanUtils.toStringMap(payOrderQ); @@ -668,7 +672,11 @@ public class WxPayOrderServiceImpl implements WxPayOrderService { payOrderSQ.setMch_id(payAccount.getMchId()); payOrderSQ.setSub_mch_id(payAccount.getSubMchId()); payOrderSQ.setNonce_str(noncestr); - payOrderSQ.setOut_trade_no(record.getPayOrderNo()); + if (StringUtils.isNotBlank(record.getTransactionId())) { + payOrderSQ.setTransaction_id(record.getTransactionId()); + } else { + payOrderSQ.setOut_trade_no(record.getPayOrderNo()); + } payOrderSQ.setSign_type("HMAC-SHA256"); try { @@ -764,14 +772,24 @@ public class WxPayOrderServiceImpl implements WxPayOrderService { return new ResultData(ErrorCode.PAY_ORDER_ERROR, returnMap); } } else { - String errMsg = ""; - JSONObject errObj = errorMapQuery.getJSONObject(result_code); - if (errObj != null) { - errMsg = errObj.toJSONString(); + String errCode = returnMap.get("err_code"); + String errCodeDes = returnMap.get("err_code_des"); + if (errCode.equalsIgnoreCase("ORDERNOTEXIST")) { + // 支付订单不存在, 订单失败 + WxOrder updateOrderForMicroPay = new WxOrder(); + updateOrderForMicroPay.setId(order.getId()); + updateOrderForMicroPay.setOrderStatus(EnumOrderStatus.ORDER_STATUS_OVERTIME_CANCEL.getCode()); + try { + wxOrderMapper.updateById(updateOrderForMicroPay); + } catch (Exception e) { + logger.error(e.getMessage()); + } + } + String errMsg = returnMap.get("return_msg"); + if (StringUtils.isNotBlank(errMsg)) { record.setFailReason(errMsg); } else { - errMsg = returnMap.get("return_msg"); - record.setFailReason(errMsg); + record.setFailReason(errCodeDes); } record.setUpdateTime(new Date()); try { @@ -783,8 +801,25 @@ public class WxPayOrderServiceImpl implements WxPayOrderService { return new ResultData(ErrorCode.PAY_ORDER_ERROR.getCode(), errMsg, returnMap); } } else { + String errCode = returnMap.get("err_code"); + String errCodeDes = returnMap.get("err_code_des"); + if (errCode.equalsIgnoreCase("ORDERNOTEXIST")) { + // 支付订单不存在, 订单失败 + WxOrder updateOrderForMicroPay = new WxOrder(); + updateOrderForMicroPay.setId(order.getId()); + updateOrderForMicroPay.setOrderStatus(EnumOrderStatus.ORDER_STATUS_OVERTIME_CANCEL.getCode()); + try { + wxOrderMapper.updateById(updateOrderForMicroPay); + } catch (Exception e) { + logger.error(e.getMessage()); + } + } String errMsg = returnMap.get("return_msg"); - record.setFailReason(errMsg); + if (StringUtils.isNotBlank(errMsg)) { + record.setFailReason(errMsg); + } else { + record.setFailReason(errCodeDes); + } record.setUpdateTime(new Date()); try { wxPayOrderMapper.updateById(record); diff --git a/mallinkService/src/main/java/com/iformall/utils/RedisLock.java b/mallinkService/src/main/java/com/iformall/utils/RedisLock.java index 67e2f388b..47b18bc17 100644 --- a/mallinkService/src/main/java/com/iformall/utils/RedisLock.java +++ b/mallinkService/src/main/java/com/iformall/utils/RedisLock.java @@ -55,6 +55,37 @@ public class RedisLock { return false; } + /** + * 加锁 ,设置过期时间 + * @param key productId - 商品的唯一标志 + * @param value 当前时间+超时时间 + * @return + */ + public boolean lock2(String key,String value){ + ValueOperations operations = stringRedisTemplate.opsForValue(); + //对应setnx命令,5s过期 + if(operations.setIfAbsent(key,value,5,TimeUnit.SECONDS)){ + //可以成功设置,也就是key不存在 + return true; + } + + //判断锁超时 - 防止原来的操作异常,没有运行解锁操作 防止死锁 + String currentValue = operations.get(key); + //如果锁过期 + if(!StringUtils.isEmpty(currentValue) && Long.parseLong(currentValue) < System.currentTimeMillis()){//currentValue不为空且小于当前时间 + //获取上一个锁的时间value + String oldValue =operations.getAndSet(key,value);//对应getset,如果key存在 + + //假设两个线程同时进来,key被占用了。获取的值currentValue=A(get取的旧的值肯定是一样的),两个线程的value都是B,key都是K.锁时间已经过期了。 + //而这里面的getAndSet一次只会一个执行,也就是一个执行之后,上一个的value已经变成了B。只有一个线程获取的上一个值会是A,另一个线程拿到的值是B。 + if(!StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue) ){ + //oldValue不为空且oldValue等于currentValue,也就是校验是不是上个对应的商品时间戳,也是防止并发 + return true; + } + } + return false; + } + /** * 解锁 diff --git a/mallinkService/src/main/resources/mapper/WxCouponPasswordMapper.xml b/mallinkService/src/main/resources/mapper/WxCouponPasswordMapper.xml index 6468f0672..390c35f9d 100644 --- a/mallinkService/src/main/resources/mapper/WxCouponPasswordMapper.xml +++ b/mallinkService/src/main/resources/mapper/WxCouponPasswordMapper.xml @@ -159,4 +159,10 @@ + + update wx_coupon_password + set expire_date=#{expireDate} + where tenant_id=#{tenantId} and coupon_id=#{couponId} and status=1 + + diff --git a/mallinkService/src/main/resources/mapper/WxOrderMapper.xml b/mallinkService/src/main/resources/mapper/WxOrderMapper.xml index 82bdaa62c..7e0e59b89 100644 --- a/mallinkService/src/main/resources/mapper/WxOrderMapper.xml +++ b/mallinkService/src/main/resources/mapper/WxOrderMapper.xml @@ -430,6 +430,69 @@ order by o.create_date desc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + o.`id`,o.`order_number`,o.`tenant_id`,o.`c_user_id`,o.`coupon_channel_id`,o.`product_id`,o.`type`, + o.`payment_type`,o.`payment`,o.`payment_time`,o.`order_status`,o.`create_date`,o.`update_date`,o.`detail`, + m.name as merchant_name, bu.name, bu.phone as bphone, + cu.phone, cu.nick_name, cubi.name c_user_name, + po.id as pay_order_id, po.transaction_id + + + + + + diff --git a/mallinkSysAdmin/pom.xml b/mallinkSysAdmin/pom.xml index 7f6f2ef0b..0ebdc1beb 100644 --- a/mallinkSysAdmin/pom.xml +++ b/mallinkSysAdmin/pom.xml @@ -13,8 +13,8 @@ mallinkSysAdmin - 3.7.0 - 3.7.0 + 3.7.0.B + 3.7.0.B diff --git a/mallinkSysAdmin/src/main/java/com/iformall/controller/micropay/MicropayController.java b/mallinkSysAdmin/src/main/java/com/iformall/controller/micropay/MicropayController.java new file mode 100644 index 000000000..d6507e5c0 --- /dev/null +++ b/mallinkSysAdmin/src/main/java/com/iformall/controller/micropay/MicropayController.java @@ -0,0 +1,91 @@ +package com.iformall.controller.micropay; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.iformall.common.ResultData; +import com.iformall.controller.base.BaseController; +import com.iformall.domain.po.WxMerchantBUser; +import com.iformall.domain.po.WxOrder; +import com.iformall.domain.po.WxPayOrder; +import com.iformall.enums.EnumOrderStatus; +import com.iformall.exception.MallinkException; +import com.iformall.mapper.WxMerchantBUserMapper; +import com.iformall.mapper.WxOrderMapper; +import com.iformall.mapper.WxPayOrderMapper; +import com.iformall.service.WxPayOrderService; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * 数据初始化 + */ +@Slf4j +@RestController +@RequestMapping("micropay") +public class MicropayController extends BaseController { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + WxOrderMapper orderMapper; + + @Autowired + WxPayOrderMapper payOrderMapper; + + @Autowired + WxMerchantBUserMapper merchantBUserMapper; + + @Autowired + WxPayOrderService payOrderService; + + @ApiOperation(value = "异常支付查询") + @PostMapping("/checkExp") + public void check() { + logger.info("queryMicopayOrder"); + + String tenantId = "1021"; + + WxOrder oq = new WxOrder(); + oq.setTenantId(tenantId); + oq.setType(1); + oq.setOrderStatus(0); + List orders = orderMapper.findList(oq); + log.info("EXP order num: {}", orders.size()); + for (WxOrder order: orders) { + WxMerchantBUser bUser = merchantBUserMapper.selectById(order.getProductId()); + WxPayOrder q = new WxPayOrder(); + q.setTenantId(tenantId); + q.setOrderId(order.getId()); + List payOrderList = payOrderMapper.selectList(new QueryWrapper<>(q)); + if (payOrderList.size() > 0) { + // 查询支付订单状态 + for (WxPayOrder payOrder : payOrderList) { + try { + ResultData resultData = payOrderService.payOrderQuery(bUser, payOrder); + logger.info(resultData.toString()); + } catch (MallinkException e) { + logger.error("payment wechat, order query error, req 2: " + payOrder.toString() + ", e:" + e.getMessage()); + } catch (Exception e) { + logger.error("payment wechat, order query error, req 3: " + payOrder.toString() + ", e:" + e.getMessage()); + } + } + } else { + // 无支付订单, 直接标记订单已取消 + WxOrder updateOrderForMicroPay = new WxOrder(); + updateOrderForMicroPay.setId(order.getId()); + updateOrderForMicroPay.setOrderStatus(EnumOrderStatus.ORDER_STATUS_OVERTIME_CANCEL.getCode()); + try { + orderMapper.updateById(updateOrderForMicroPay); + } catch (Exception e) { + logger.error("update Order: {} ", e.getMessage()); + } + } + } + } +} diff --git a/pom.xml b/pom.xml index 4756520c0..c423a0294 100644 --- a/pom.xml +++ b/pom.xml @@ -32,11 +32,11 @@ - 3.7.0 - 3.7.0 - 3.7.0 - 3.7.0 - 3.7.0 + 3.7.0.B + 3.7.0.B + 3.7.0.B + 3.7.0.B + 3.7.0.B 2.3.0