[fix]修改提现逻辑
This commit is contained in:
parent
a379e4b52f
commit
dfc5ae4a06
@ -25,11 +25,14 @@ import com.wzj.soopin.transaction.convert.WithdrawConvert;
|
||||
import com.wzj.soopin.transaction.domain.bo.ChargeBO;
|
||||
import com.wzj.soopin.transaction.domain.bo.WithdrawBO;
|
||||
import com.wzj.soopin.transaction.domain.entity.InitiateBatchTransferResponseNew;
|
||||
import com.wzj.soopin.transaction.domain.entity.WxAuthResponse;
|
||||
import com.wzj.soopin.transaction.domain.po.Withdraw;
|
||||
import com.wzj.soopin.transaction.enums.WithdrawType;
|
||||
import com.wzj.soopin.transaction.service.IAccountBillService;
|
||||
import com.wzj.soopin.transaction.service.IChargeService;
|
||||
import com.wzj.soopin.transaction.service.IWithdrawService;
|
||||
import com.wzj.soopin.transaction.service.impl.WxAuthService;
|
||||
import com.wzj.soopin.transaction.service.impl.WxPayService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@ -79,6 +82,8 @@ public class AppMemberController {
|
||||
private final IWithdrawService withdrawService;
|
||||
private final WithdrawConvert withdrawConvert;
|
||||
|
||||
private final WxAuthService wxAuthService;
|
||||
|
||||
@Operation(summary = "获取会员账户信息详细信息")
|
||||
@GetMapping(value = "/info")
|
||||
public R<MemberVO> getInfo(Long memberId) {
|
||||
@ -158,7 +163,7 @@ public class AppMemberController {
|
||||
throw new ServiceException("用户未登录");
|
||||
}
|
||||
Long memberId = loginUser.getUserId();
|
||||
|
||||
//
|
||||
ValidatorUtils.validate(loginBody);
|
||||
AuthResponse<AuthUser> response = SocialUtils.loginAuth(
|
||||
loginBody.getSource(), loginBody.getSocialCode(),
|
||||
@ -169,8 +174,9 @@ public class AppMemberController {
|
||||
|
||||
AuthUser authUserData = response.getData();
|
||||
|
||||
String unionId=authUserData.getToken().getUnionId();
|
||||
Member member = Member.builder().id(memberId).openId(unionId).build();
|
||||
// WxAuthResponse response1 = wxAuthService.getAccessTokenByCode(loginBody.getSocialCode());
|
||||
// String OpenId=response1.getOpenid();
|
||||
Member member = Member.builder().id(memberId).openId(authUserData.getUuid()).build();
|
||||
service.updateById(member);
|
||||
// 更新用户的微信信息
|
||||
// 返回给前端
|
||||
|
@ -272,7 +272,7 @@ wechat:
|
||||
private-key-path: "classpath:cert/apiclient_key.pem" # 商户私钥文件路径
|
||||
transfer-notify-url: https://wuzhongjie.com.cn/prod-api/api/transfer/callback # 转账回调地址
|
||||
app-id: wxebcdaea31881caab # 应用ID
|
||||
secret: your_wechat_secret # 应用密钥
|
||||
secret: 86fbcab880e4066ac5c75af6f4f003c2 # 应用密钥
|
||||
mini-program:
|
||||
# app-id: wx87a5db19138da60d
|
||||
# secret: 856ca8bae38ccaecc1353c9abedf6b41
|
||||
|
@ -272,7 +272,7 @@ wechat:
|
||||
private-key-path: "/java/cert/apiclient_key.pem" # 商户私钥文件路径
|
||||
transfer-notify-url: https://wuzhongjie.com.cn/prod-api/api/transfer/callback # 转账回调地址
|
||||
app-id: wxebcdaea31881caab # 应用ID
|
||||
secret: your_wechat_secret # 应用密钥
|
||||
secret: 71826d76bad096ec5407897c6ed1391f # 应用密钥
|
||||
mini-program:
|
||||
# app-id: wx87a5db19138da60d
|
||||
# secret: 856ca8bae38ccaecc1353c9abedf6b41
|
||||
|
@ -29,8 +29,7 @@ public class MQMessage {
|
||||
/**
|
||||
* 消息类型
|
||||
*/
|
||||
private MQMessageType
|
||||
messageType;
|
||||
private String messageType;
|
||||
/**
|
||||
* 消息内容
|
||||
*/
|
||||
|
@ -405,7 +405,7 @@ public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> impl
|
||||
|
||||
MQMessage mqMessage = new MQMessage();
|
||||
mqMessage.setTag(MessageActionEnum.INTERACTION_COMMENT.name());
|
||||
mqMessage.setMessageType(MQMessageType.IM);
|
||||
mqMessage.setMessageType(MQMessageType.IM.name());
|
||||
if (bo.getFatherCommentId() == 0L) {
|
||||
// 评论视频,通知视频作者
|
||||
if ( !String.valueOf(loginUser.getUserId()).equals(bo.getVlogerId())) {
|
||||
|
@ -76,7 +76,7 @@ public class VlogPushServiceImpl implements IVlogPushService {
|
||||
MQMessage message = MQMessage.builder()
|
||||
.topic("MEMBER_VLOG_MSG")
|
||||
.tag(HOT_VLOG_TAG)
|
||||
.messageType(MQMessageType.VLOG)
|
||||
.messageType(MQMessageType.VLOG.name())
|
||||
.data(vlogId)
|
||||
.source("vlog_service")
|
||||
.sendTime(LocalDateTime.now())
|
||||
@ -94,7 +94,7 @@ public class VlogPushServiceImpl implements IVlogPushService {
|
||||
MQMessage message = MQMessage.builder()
|
||||
.topic("MEMBER_VLOG_MSG")
|
||||
.tag(tag)
|
||||
.messageType(MQMessageType.VLOG)
|
||||
.messageType(MQMessageType.VLOG.name())
|
||||
.data(vlogId)
|
||||
.source("vlog_service")
|
||||
.sendTime(LocalDateTime.now())
|
||||
|
@ -151,7 +151,7 @@ public class VlogServiceImpl extends ServiceImpl<VlogMapper, Vlog> implements Vl
|
||||
|
||||
//发出mq消息,异步处理上传
|
||||
MQMessage message = MQMessage.builder()
|
||||
.messageType(MQMessageType.VLOG)
|
||||
.messageType(MQMessageType.VLOG.name())
|
||||
.data(vlog.getId())
|
||||
.source("app")
|
||||
.topic("VLOG_UPLOAD_TOPIC")
|
||||
@ -330,7 +330,7 @@ public class VlogServiceImpl extends ServiceImpl<VlogMapper, Vlog> implements Vl
|
||||
params.put("vlogId",vlog.getId());
|
||||
params.put("firstFrameImg",vlog.getFirstFrameImg());
|
||||
MQMessage mqMessage = new MQMessage();
|
||||
mqMessage.setMessageType(MQMessageType.IM);
|
||||
mqMessage.setMessageType(MQMessageType.IM.name());
|
||||
mqMessage.setTag(MessageActionEnum.INTERACTION_LIKE.name());
|
||||
mqMessage.setToUserId(Long.valueOf(vlog.getMemberId()));
|
||||
mqMessage.setData(params);
|
||||
|
@ -87,7 +87,7 @@ public class FansServiceImpl extends ServiceImpl<FansMapper, Fans> implements IF
|
||||
params.put("nickname", follower.getNickname() == null ? "" : follower.getNickname());
|
||||
params.put("faceUrl", vlogger.getAvatar() );
|
||||
MQMessage message = MQMessage.builder()
|
||||
.messageType(MQMessageType.IM)
|
||||
.messageType(MQMessageType.IM.name())
|
||||
.data(params)
|
||||
.tag(MessageActionEnum.NEW_FOUCS.name())
|
||||
.toUserId(vlogger.getId())
|
||||
|
@ -115,7 +115,7 @@ public class FeedbackServiceImpl extends ServiceImpl<FeedbackMapper, Feedback> i
|
||||
params.put("faceUrl", loginUser.getAvatar() );
|
||||
|
||||
MQMessage mqMessage = new MQMessage();
|
||||
mqMessage.setMessageType(MQMessageType.IM);
|
||||
mqMessage.setMessageType(MQMessageType.IM.name());
|
||||
mqMessage.setTag(MessageActionEnum.INTERACTION_LIKE.name());
|
||||
mqMessage.setToUserId(aim.getMemberId());
|
||||
mqMessage.setData(params);
|
||||
|
@ -250,7 +250,7 @@ public class AftersaleServiceImpl extends ServiceImpl<AftersaleMapper, Aftersale
|
||||
params.put("object", o);
|
||||
MQMessage mqMessage = new MQMessage();
|
||||
mqMessage.setTag(actionEnum.name());
|
||||
mqMessage.setMessageType(MQMessageType.IM);
|
||||
mqMessage.setMessageType(MQMessageType.IM.name());
|
||||
mqMessage.setToUserId(o.getMemberId());
|
||||
mqMessage.setData(params);
|
||||
return mqMessage;
|
||||
|
@ -523,7 +523,7 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
|
||||
params.put("account", MessageActionEnum.ORDER_PAY.getAccount());
|
||||
MQMessage mqMessage = new MQMessage();
|
||||
mqMessage.setTag(MessageActionEnum.ORDER_PAY.name());
|
||||
mqMessage.setMessageType(MQMessageType.IM);
|
||||
mqMessage.setMessageType(MQMessageType.IM.name());
|
||||
mqMessage.setToUserId(order.getMemberId());
|
||||
mqMessage.setData(params);
|
||||
MqUtil.sendIMMessage(mqMessage);
|
||||
|
@ -182,7 +182,7 @@ public class WxPayController {
|
||||
})
|
||||
public ResponseEntity<WxAuthResponse> getOpenId(@RequestParam String code) {
|
||||
try {
|
||||
WxAuthResponse response = wxAuthService.getOpenIdByCode(code);
|
||||
WxAuthResponse response = wxAuthService.getAccessTokenByCode(code);
|
||||
return new ResponseEntity<>(response, HttpStatus.OK);
|
||||
} catch (Exception e) {
|
||||
log.error("获取openid时发生异常: {}", e.getMessage());
|
||||
|
@ -13,4 +13,9 @@ public class WxAuthResponse {
|
||||
private String unionid;
|
||||
private String errcode;
|
||||
private String errmsg;
|
||||
private String access_token;
|
||||
private String expires_in;
|
||||
private String refresh_token;
|
||||
private String scope;
|
||||
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ public class ChargeServiceImpl extends ServiceImpl<ChargeMapper, Charge> impleme
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
MQMessage mqMessage = new MQMessage();
|
||||
mqMessage.setTag(MessageActionEnum.ORDER_RECHARGE.name());
|
||||
mqMessage.setMessageType(MQMessageType.IM);
|
||||
mqMessage.setMessageType(MQMessageType.IM.name());
|
||||
// 评论视频,通知视频作者
|
||||
params.put("orderID", charge.getId());
|
||||
params.put("amount", charge.getMoney());
|
||||
|
@ -547,7 +547,7 @@ public class EasypayServiceImpl implements IEasypayService {
|
||||
}
|
||||
MQMessage mqMessage = new MQMessage();
|
||||
mqMessage.setTag(MessageActionEnum.ORDER_PAY.name());
|
||||
mqMessage.setMessageType(MQMessageType.IM);
|
||||
mqMessage.setMessageType(MQMessageType.IM.name());
|
||||
mqMessage.setToUserId(order.getMemberId());
|
||||
mqMessage.setData(params);
|
||||
return mqMessage;
|
||||
|
@ -182,21 +182,9 @@ public class WithdrawServiceImpl extends ServiceImpl<WithdrawMapper, Withdraw> i
|
||||
withdraw.setCode(SnowFlake.createStr("TX"));
|
||||
save(withdraw);
|
||||
|
||||
BigDecimal newBalance = balance.subtract(withdraw.getMoney());
|
||||
//锁定用户余额
|
||||
memberAccountService.updateById(memberAccount.toBuilder().wallet(newBalance).build());
|
||||
|
||||
//生成账单
|
||||
AccountBill memberAccountChangeRecord = AccountBill.builder()
|
||||
.accountId(withdraw.getMemberId())
|
||||
.moneyBalance(newBalance)
|
||||
.beforeBalance(balance)
|
||||
.afterBalance(newBalance)
|
||||
.changeType(AccountBillChangeTypeEnum.OUT.getCode())
|
||||
.changeDesc("提现锁定")
|
||||
.source(AccountBillSourceEnum.WITHDRAW.getCode())
|
||||
.build();
|
||||
accountBillService.save(memberAccountChangeRecord);
|
||||
accountBillService.reduceMoney(withdraw.getMoney(),withdraw.getMemberId(),AccountBillSourceEnum.WITHDRAW,"");
|
||||
|
||||
|
||||
InitiateBatchTransferResponseNew response = null;
|
||||
try{
|
||||
|
@ -2,17 +2,31 @@ package com.wzj.soopin.transaction.service.impl;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.text.StrBuilder;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.wzj.soopin.transaction.domain.entity.WxAuthResponse;
|
||||
import com.wzj.soopin.transaction.config.WechatMiniProgramConfig;
|
||||
import com.wzj.soopin.transaction.domain.entity.WxAuthResponse;
|
||||
import com.wzj.soopin.transaction.wechat.WechatPayConfig;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.wzj.soopin.transaction.domain.entity.WxAuthResponse;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@ -26,23 +40,110 @@ public class WxAuthService {
|
||||
|
||||
private RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
|
||||
// Jackson 解析器(Spring 默认注入,替代 fastjson,减少第三方依赖)
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
/**
|
||||
* 网页-通过code获取openid
|
||||
*
|
||||
* @param code 授权码
|
||||
* @return 包含openid的响应对象
|
||||
* 通过 code 换取 OAuth2 access_token(优化后)
|
||||
* @param code 授权回调返回的 code
|
||||
* @return WxAuthResponse 解析后的响应
|
||||
*/
|
||||
public WxAuthResponse getOpenIdByCode(String code) {
|
||||
public WxAuthResponse getAccessTokenByCode(String code) {
|
||||
// 1. 核心:参数校验(解决 41002 错误的根本)
|
||||
validateParams(code);
|
||||
|
||||
// 2. 拼接 URL(脱敏日志,避免泄露 secret)
|
||||
String appId = wechatPayConfig.getAppId();
|
||||
String secret = wechatPayConfig.getSecret();
|
||||
String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";
|
||||
url = String.format(url, wechatPayConfig.getAppId(), wechatPayConfig.getSecret(), code);
|
||||
WxAuthResponse response = restTemplate.getForObject(url, WxAuthResponse.class);
|
||||
log.info("获取openid结果: {}", response);
|
||||
log.info("AppId为: {}", wechatPayConfig.getAppId());
|
||||
log.info("Secret为: {}", wechatPayConfig.getSecret());
|
||||
if (response == null || response.getOpenid() == null) {
|
||||
throw new RuntimeException("Failed to get openid from WeChat");
|
||||
// 格式化 URL
|
||||
String requestUrl = String.format(
|
||||
url,
|
||||
appId,
|
||||
secret,
|
||||
code
|
||||
);
|
||||
|
||||
log.info("调用微信 OAuth2 access_token 接口,脱敏URL:{}", requestUrl);
|
||||
|
||||
// 3. 发起 HTTP GET 请求(设置请求头,模拟浏览器,避免被拦截)
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36");
|
||||
HttpEntity<Void> requestEntity = new HttpEntity<>(headers);
|
||||
try {
|
||||
// 发起请求(RestTemplate 自动处理 URL 编码,避免特殊字符问题)
|
||||
ResponseEntity<String> responseEntity = restTemplate.exchange(
|
||||
requestUrl,
|
||||
HttpMethod.GET,
|
||||
requestEntity,
|
||||
String.class
|
||||
);
|
||||
|
||||
// 4. 校验响应状态码(非 200 直接抛异常)
|
||||
if (!responseEntity.getStatusCode().is2xxSuccessful()) {
|
||||
throw new ServiceException(
|
||||
);
|
||||
}
|
||||
String responseBody = responseEntity.getBody();
|
||||
log.info("微信 OAuth2 接口响应内容:{}", responseBody);
|
||||
|
||||
// 5. JSON 解析(用 Jackson 替代 fastjson,与 Spring 生态兼容,且异常可控)
|
||||
try {
|
||||
return objectMapper.readValue(responseBody, WxAuthResponse.class);
|
||||
} catch (Exception e) {
|
||||
throw new ServiceException(
|
||||
);
|
||||
}
|
||||
|
||||
} catch (ServiceException e) {
|
||||
// 捕获 HTTP 相关异常(连接超时、读取超时等)
|
||||
throw new ServiceException(
|
||||
"OAuth 接口 HTTP 请求失败"
|
||||
);
|
||||
} catch (Exception e) {
|
||||
// 捕获其他未知异常(兜底处理)
|
||||
throw new ServiceException(
|
||||
"获取 OAuth access_token 未知异常"
|
||||
);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. 参数校验(解决 appid/secret/code 缺失问题)
|
||||
*/
|
||||
private void validateParams(String code) {
|
||||
String appId = wechatMiniProgramConfig.getAppId();
|
||||
String secret = wechatMiniProgramConfig.getSecret();
|
||||
|
||||
// 校验 appid(非 null、非空字符串、非空白)
|
||||
if (!StringUtils.hasText(appId)) {
|
||||
throw new ServiceException("微信 OAuth 配置异常:appid 缺失(null/空字符串)");
|
||||
}
|
||||
// 校验 secret
|
||||
if (!StringUtils.hasText(secret)) {
|
||||
throw new ServiceException("微信 OAuth 配置异常:secret 缺失(null/空字符串)");
|
||||
}
|
||||
// 校验 code(授权回调返回的 code 不能为空)
|
||||
if (!StringUtils.hasText(code)) {
|
||||
throw new ServiceException("微信 OAuth 授权异常:code 缺失(null/空字符串)");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 2. 敏感信息脱敏(避免 secret 明文打印,符合安全规范)
|
||||
* 示例:secret=abcdefghijklmn → 脱敏后=abcdef****mn
|
||||
*/
|
||||
private String maskSensitiveInfo(String sensitiveStr) {
|
||||
if (!StringUtils.hasText(sensitiveStr)) {
|
||||
return "";
|
||||
}
|
||||
int length = sensitiveStr.length();
|
||||
if (length <= 6) {
|
||||
return sensitiveStr.substring(0, 2) + "****"; // 短字符串特殊处理
|
||||
}
|
||||
return sensitiveStr.substring(0, 6) + "****" + sensitiveStr.substring(length - 2);
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user