Просмотр исходного кода

Merge tag 'refs/tags/jenkins-back-end-3310' into SiChuan

release
release_toaliyun_real
Stormeye Wu 6 лет назад
Родитель
Сommit
fc99170473
49 измененных файлов: 1280 добавлений и 100 удалений
  1. +2
    -2
      mallinkAdmin/pom.xml
  2. +24
    -4
      mallinkAdmin/src/main/java/com/iformall/controller/market/WxCouponPasswordController.java
  3. +1
    -1
      mallinkAdmin/src/main/java/com/iformall/log/TableOperateAspect.java
  4. +53
    -0
      mallinkBApi/src/main/java/com/iformall/annotation/RedisCache.java
  5. +158
    -0
      mallinkBApi/src/main/java/com/iformall/aop/RedisCacheAspect.java
  6. +10
    -0
      mallinkBApi/src/main/java/com/iformall/config/RedisConfig.java
  7. +3
    -0
      mallinkBApi/src/main/java/com/iformall/controller/WxCouponOrderController.java
  8. +4
    -1
      mallinkBApi/src/main/java/com/iformall/controller/WxDateAmountRecordController.java
  9. +2
    -0
      mallinkBApi/src/main/java/com/iformall/controller/WxMerchantBUserController.java
  10. +23
    -4
      mallinkBApi/src/main/java/com/iformall/controller/WxMerchantController.java
  11. +13
    -0
      mallinkBApi/src/main/java/com/iformall/controller/WxMicroPayController.java
  12. +53
    -0
      mallinkCApi/src/main/java/com/iformall/annotation/RedisCache.java
  13. +152
    -0
      mallinkCApi/src/main/java/com/iformall/aop/RedisCacheAspect.java
  14. +29
    -0
      mallinkCApi/src/main/java/com/iformall/config/RedisConfig.java
  15. +2
    -0
      mallinkCApi/src/main/java/com/iformall/controller/WxBusinessController.java
  16. +2
    -0
      mallinkCApi/src/main/java/com/iformall/controller/WxCampaignController.java
  17. +8
    -4
      mallinkCApi/src/main/java/com/iformall/controller/WxCarController.java
  18. +2
    -1
      mallinkCApi/src/main/java/com/iformall/controller/WxCouponChannelController.java
  19. +69
    -0
      mallinkCApi/src/main/java/com/iformall/controller/WxLiveController.java
  20. +21
    -9
      mallinkCApi/src/main/java/com/iformall/controller/WxMallController.java
  21. +122
    -8
      mallinkCApi/src/main/java/com/iformall/controller/WxPressOrderController.java
  22. +2
    -0
      mallinkCApi/src/main/java/com/iformall/controller/WxUserGrantController.java
  23. +2
    -2
      mallinkCallback/pom.xml
  24. +1
    -0
      mallinkService/src/main/java/com/iformall/common/ErrorCode.java
  25. +1
    -1
      mallinkService/src/main/java/com/iformall/domain/po/WxMerchant.java
  26. +67
    -0
      mallinkService/src/main/java/com/iformall/domain/vo/WxOrderPayExpVo.java
  27. +7
    -7
      mallinkService/src/main/java/com/iformall/domain/vo/WxOrderPayVo.java
  28. +2
    -0
      mallinkService/src/main/java/com/iformall/mapper/WxCouponPasswordMapper.java
  29. +2
    -0
      mallinkService/src/main/java/com/iformall/mapper/WxOrderMapper.java
  30. +2
    -0
      mallinkService/src/main/java/com/iformall/mapper/WxPayOrderMapper.java
  31. +1
    -0
      mallinkService/src/main/java/com/iformall/pay/WxPayOrderQ.java
  32. +2
    -0
      mallinkService/src/main/java/com/iformall/pay/WxPayOrderSQ.java
  33. +1
    -0
      mallinkService/src/main/java/com/iformall/service/ExcelService.java
  34. +23
    -0
      mallinkService/src/main/java/com/iformall/service/RedisService.java
  35. +2
    -0
      mallinkService/src/main/java/com/iformall/service/WxCouponPasswordService.java
  36. +5
    -1
      mallinkService/src/main/java/com/iformall/service/WxOrderPressService.java
  37. +16
    -0
      mallinkService/src/main/java/com/iformall/service/WxOrderService.java
  38. +46
    -0
      mallinkService/src/main/java/com/iformall/service/impl/RedisServiceImpl.java
  39. +5
    -0
      mallinkService/src/main/java/com/iformall/service/impl/WxCouponPasswordServiceImpl.java
  40. +19
    -39
      mallinkService/src/main/java/com/iformall/service/impl/WxOrderPressServiceImpl.java
  41. +68
    -0
      mallinkService/src/main/java/com/iformall/service/impl/WxOrderServiceImpl.java
  42. +44
    -9
      mallinkService/src/main/java/com/iformall/service/impl/WxPayOrderServiceImpl.java
  43. +31
    -0
      mallinkService/src/main/java/com/iformall/utils/RedisLock.java
  44. +6
    -0
      mallinkService/src/main/resources/mapper/WxCouponPasswordMapper.xml
  45. +63
    -0
      mallinkService/src/main/resources/mapper/WxOrderMapper.xml
  46. +11
    -0
      mallinkService/src/main/resources/mapper/WxPayOrderMapper.xml
  47. +2
    -2
      mallinkSysAdmin/pom.xml
  48. +91
    -0
      mallinkSysAdmin/src/main/java/com/iformall/controller/micropay/MicropayController.java
  49. +5
    -5
      pom.xml

+ 2
- 2
mallinkAdmin/pom.xml Просмотреть файл

@@ -13,8 +13,8 @@
<artifactId>mallinkAdmin</artifactId>

<properties>
<weixin-java-mp.version>3.7.0</weixin-java-mp.version>
<weixin-java-open.version>3.7.0</weixin-java-open.version>
<weixin-java-mp.version>3.7.0.B</weixin-java-mp.version>
<weixin-java-open.version>3.7.0.B</weixin-java-open.version>
</properties>

<dependencies>


+ 24
- 4
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();
}


}

+ 1
- 1
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;


+ 53
- 0
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;
}

+ 158
- 0
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<String, String> 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);
}
}

+ 10
- 0
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<String, String> getStringValueOperations(RedisConnectionFactory connectionFactory) {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(connectionFactory);
template.afterPropertiesSet();
return template.opsForValue();
}
}

+ 3
- 0
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({


+ 4
- 1
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() {


+ 2
- 0
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() {


+ 23
- 4
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();


+ 13
- 0
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")


+ 53
- 0
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;
}

+ 152
- 0
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<String, String> 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);
}
}

+ 29
- 0
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<String, WxOrder> getPressOrderRedisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, WxOrder> template = new RedisTemplate<>();

Jackson2JsonRedisSerializer<WxOrder> 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<String, String> getStringValueOperations(RedisConnectionFactory connectionFactory) {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(connectionFactory);
template.afterPropertiesSet();
return template.opsForValue();
}
}

+ 2
- 0
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) {


+ 2
- 0
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({


+ 8
- 4
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);
}


+ 2
- 1
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) {


+ 69
- 0
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;
}

/**
* 获取直播房间回放数据信息.
* <p>
* 获取回放 (默认: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;
}
}

+ 21
- 9
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<Object> keys) {
return new ResultData(redisService.delRedisKey(keys));
}

}

+ 122
- 8
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<String, WxOrder> orderRedisTemplate;

@Autowired
@Qualifier("couponDetailRedisTemplate")
RedisTemplate<String, WxCouponCVo> 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<String, String> 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<String, WxOrder> 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<String, WxCouponCVo> 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)


+ 2
- 0
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() {


+ 2
- 2
mallinkCallback/pom.xml Просмотреть файл

@@ -13,8 +13,8 @@
<artifactId>mallinkCallback</artifactId>

<properties>
<weixin-java-mp.version>3.7.0</weixin-java-mp.version>
<weixin-java-open.version>3.7.0</weixin-java-open.version>
<weixin-java-mp.version>3.7.0.B</weixin-java-mp.version>
<weixin-java-open.version>3.7.0.B</weixin-java-open.version>
</properties>

<dependencies>


+ 1
- 0
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, "卡密延期异常"),

/**
* 微信


+ 1
- 1
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;



+ 67
- 0
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();
}
}


}

+ 7
- 7
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


+ 2
- 0
mallinkService/src/main/java/com/iformall/mapper/WxCouponPasswordMapper.java Просмотреть файл

@@ -21,4 +21,6 @@ public interface WxCouponPasswordMapper extends CommonMapper<WxCouponPassword, L

void updateStatus(List<WxCouponPassword> tempList);

void updatePostpone(WxCouponPassword wxCouponPassword);

}

+ 2
- 0
mallinkService/src/main/java/com/iformall/mapper/WxOrderMapper.java Просмотреть файл

@@ -24,8 +24,10 @@ public interface WxOrderMapper extends CommonMapper<WxOrder, Long> {
List<WxOrderCouponVo> findListOfCUser(WxOrder wxOrder);
List<WxOrderCouponVo> selectDetailOfCUser(WxOrder wxOrder);

/** B端收银台(收款码支付) */
Map dayMicroPayAmountList(Map dateMap);
List<WxOrderPayVo> findListOfMicroPayOrderByDate(Map dateMap);
List<WxOrderPayExpVo> findListOfExpMicroPayOrderByDate(Map dateMap);

List<MarkingSceneDataVo> queryForSceneRepotyHistory(HashMap<String,Object> params);



+ 2
- 0
mallinkService/src/main/java/com/iformall/mapper/WxPayOrderMapper.java Просмотреть файл

@@ -12,4 +12,6 @@ public interface WxPayOrderMapper extends CommonMapper<WxPayOrder, Long> {
List<WxPayOrderVo> findListOfPaidOrderByDate(Map dateMap);

List<WxPayOrder> findListForUnPs(WxPayOrder wxPayOrder);

List<WxPayOrder> findExpListForMicroPay(WxPayOrder wxPayOrder);
}

+ 1
- 0
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


+ 2
- 0
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();
}


+ 1
- 0
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());
}
}


+ 23
- 0
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<Object> hotApi() ;

/**
* 清除指定key
* @param keys
* @return
*/
boolean delRedisKey(Collection<Object> keys) ;
}

+ 2
- 0
mallinkService/src/main/java/com/iformall/service/WxCouponPasswordService.java Просмотреть файл

@@ -70,4 +70,6 @@ public interface WxCouponPasswordService {
PageInfo<WxCouponPasswordCountInfoVO> findCouponList(WxCouponPassword wxCouponPassword, Integer pageNum, Integer pageSize);

List<WxCouponPassword> findList(WxCouponPassword wxCouponPassword);

void postpone(WxCouponPassword wxCouponPassword);
}

+ 5
- 1
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);


+ 16
- 0
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);
/**
* 保存或更新实体


+ 46
- 0
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<Object> hotApi() {
return stringRedisTemplate.opsForHash().keys(KEY_HOT_API);
}

@Override
public boolean delRedisKey(Collection<Object> keys) {
if (CollectionUtils.isEmpty(keys)) {
return false;
}
boolean result = stringRedisTemplate.execute(new SessionCallback<Boolean>() {
@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;
}
}

+ 5
- 0
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();


+ 19
- 39
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<WxOrderPress> 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<WxOrderPress> 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) {


+ 68
- 0
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<WxOrderPayExpVo> 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) {


+ 44
- 9
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);


+ 31
- 0
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<String, String> 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;
}


/**
* 解锁


+ 6
- 0
mallinkService/src/main/resources/mapper/WxCouponPasswordMapper.xml Просмотреть файл

@@ -159,4 +159,10 @@
</foreach>
</update>

<update id="updatePostpone">
update wx_coupon_password
set expire_date=#{expireDate}
where tenant_id=#{tenantId} and coupon_id=#{couponId} and status=1
</update>

</mapper>

+ 63
- 0
mallinkService/src/main/resources/mapper/WxOrderMapper.xml Просмотреть файл

@@ -430,6 +430,69 @@
order by o.create_date desc
</select>

<resultMap id="PayExpVoResultMap" type="com.iformall.domain.vo.WxOrderPayExpVo">
<id column="id" jdbcType="BIGINT" property="id"/>
<result column="order_number" jdbcType="BIGINT" property="orderNumber"/>
<result column="tenant_id" jdbcType="VARCHAR" property="tenantId"/>
<result column="c_user_id" jdbcType="BIGINT" property="cUserId"/>
<result column="coupon_channel_id" jdbcType="BIGINT" property="couponChannelId"/>
<result column="product_id" jdbcType="BIGINT" property="productId"/>
<result column="type" jdbcType="TINYINT" property="type"/>
<result column="payment_type" jdbcType="INTEGER" property="paymentType"/>
<result column="payment" jdbcType="INTEGER" property="payment"/>
<result column="payment_time" jdbcType="TIMESTAMP" property="paymentTime"/>
<result column="order_status" jdbcType="INTEGER" property="orderStatus"/>
<result column="create_date" jdbcType="TIMESTAMP" property="createDate"/>
<result column="update_date" jdbcType="TIMESTAMP" property="updateDate"/>
<result column="detail" jdbcType="VARCHAR" property="detail"/>

<result column="merchant_name" jdbcType="VARCHAR" property="merchantName" />
<result column="name" jdbcType="VARCHAR" property="bUserName" />
<result column="bphone" jdbcType="VARCHAR" property="bUserPhone" />
<result column="phone" jdbcType="VARCHAR" property="cUserPhone" />
<result column="nick_name" jdbcType="VARCHAR" property="nickName" />
<result column="c_user_name" jdbcType="VARCHAR" property="cUserName" />

<result column="pay_order_id" jdbcType="BIGINT" property="payOrderId"/>
<result column="transaction_id" jdbcType="VARCHAR" property="transactionId"/>
</resultMap>

<sql id="allExpPayOrderColumns">
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
</sql>

<select id="findListOfExpMicroPayOrderByDate" parameterType="map" resultMap="PayExpVoResultMap">
select
<include refid="allExpPayOrderColumns"/>
from wx_order o
inner join wx_merchant_b_user bu on bu.id = o.product_id
inner join wx_merchant m on m.id = bu.merchant_id
left join wx_pay_order po on po.order_id = o.id
LEFT JOIN wx_c_user cu on cu.id = o.c_user_id
LEFT JOIN wx_c_user_basic_info cubi on cubi.id = o.c_user_id
where o.order_status = '0' and o.`type` = 1
<if test=" null != tenantId ">
and o.`tenant_id` = #{tenantId}
</if>
<if test=" null != merchantId ">
and bu.`merchant_id` = #{merchantId}
</if>
<if test=" null != bUserId ">
and bu.`id` = #{bUserId}
</if>
<if test="startDate != null">
AND o.create_date &gt; #{startDate,jdbcType=TIMESTAMP}
</if>
<if test="endDate != null">
AND o.create_date &lt; #{endDate,jdbcType=TIMESTAMP}
</if>
order by o.create_date desc
</select>

<select id="queryForSceneRepotyHistory" resultType="com.iformall.domain.vo.MarkingSceneDataVo" parameterType="hashmap">
select DATE_FORMAT(o.create_date,'%Y-%m-%d') xTime, count(o.id) triggerCount
from wx_order o


+ 11
- 0
mallinkService/src/main/resources/mapper/WxPayOrderMapper.xml Просмотреть файл

@@ -159,6 +159,17 @@
and tenant_id in (select tenant_id from wx_pay_account where share =1) and tenant_id != '789' and tenant_id != '1000' ;
</select>

<select id="findExpListForMicroPay" parameterType="com.iformall.domain.po.WxPayOrder" resultMap="BaseResultMap">
select
<include refid="allColumns"/>
from wx_pay_order
where 1=1
<if test=" null != tenantId "> and `tenant_id` = #{tenantId} </if>
and order_id in (
select id from wx_order where `tenant_id` = #{tenantId} and type = 1 and order_status = 0
);
</select>

<resultMap id="VBaseResultMap" type="com.iformall.domain.vo.WxPayOrderVo">
<id column="id" jdbcType="BIGINT" property="id"/>
<result column="tenant_id" jdbcType="VARCHAR" property="tenantId"/>


+ 2
- 2
mallinkSysAdmin/pom.xml Просмотреть файл

@@ -13,8 +13,8 @@
<artifactId>mallinkSysAdmin</artifactId>

<properties>
<weixin-java-mp.version>3.7.0</weixin-java-mp.version>
<weixin-java-open.version>3.7.0</weixin-java-open.version>
<weixin-java-mp.version>3.7.0.B</weixin-java-mp.version>
<weixin-java-open.version>3.7.0.B</weixin-java-open.version>
</properties>

<dependencies>


+ 91
- 0
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<WxOrder> 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<WxPayOrder> 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());
}
}
}
}
}

+ 5
- 5
pom.xml Просмотреть файл

@@ -32,11 +32,11 @@
</parent>

<properties>
<weixin-java-common.version>3.7.0</weixin-java-common.version>
<weixin-java-mp.version>3.7.0</weixin-java-mp.version>
<weixin-java-miniapp.version>3.7.0</weixin-java-miniapp.version>
<weixin-java-pay.version>3.7.0</weixin-java-pay.version>
<weixin-java-open.version>3.7.0</weixin-java-open.version>
<weixin-java-common.version>3.7.0.B</weixin-java-common.version>
<weixin-java-mp.version>3.7.0.B</weixin-java-mp.version>
<weixin-java-miniapp.version>3.7.0.B</weixin-java-miniapp.version>
<weixin-java-pay.version>3.7.0.B</weixin-java-pay.version>
<weixin-java-open.version>3.7.0.B</weixin-java-open.version>
<quartz.version>2.3.0</quartz.version>
</properties>



Загрузка…
Отмена
Сохранить