feat(payment): 支付宝账号绑定
parent
8d04847cd2
commit
61ac03de38
|
@ -135,6 +135,11 @@
|
|||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.aliyun</groupId>
|
||||
<artifactId>aliyun-java-sdk-core</artifactId>
|
||||
|
|
|
@ -1,25 +1,20 @@
|
|||
package com.mcwl.web.controller.pay.AliPay;
|
||||
|
||||
import cn.hutool.core.lang.UUID;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.extra.qrcode.QrCodeUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alipay.easysdk.factory.Factory;
|
||||
import com.alipay.easysdk.kernel.Config;
|
||||
import com.alipay.easysdk.payment.common.models.AlipayTradeQueryResponse;
|
||||
import com.mcwl.common.JSONUtils;
|
||||
import com.mcwl.common.annotation.Anonymous;
|
||||
import com.mcwl.common.core.controller.BaseController;
|
||||
import com.mcwl.common.core.domain.AjaxResult;
|
||||
import com.mcwl.common.core.page.TableDataInfo;
|
||||
import com.mcwl.common.core.redis.RedisCache;
|
||||
import com.mcwl.common.domain.IdsParam;
|
||||
import com.mcwl.common.utils.SecurityUtils;
|
||||
import com.mcwl.common.utils.ShareCodeUtils;
|
||||
import com.mcwl.pay.domain.OrderTrade;
|
||||
import com.mcwl.pay.domain.OrderTradeDto;
|
||||
import com.mcwl.pay.service.AliPayService;
|
||||
import com.mcwl.pay.service.OrderTradeService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
|
@ -27,7 +22,6 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
|
@ -39,7 +33,7 @@ import java.util.Map;
|
|||
* @Date:2025/1/3 14:46
|
||||
*/
|
||||
|
||||
@RestController
|
||||
@Controller
|
||||
@RequestMapping("/ali/pay")
|
||||
@Validated
|
||||
public class AliPayController extends BaseController {
|
||||
|
@ -63,12 +57,13 @@ public class AliPayController extends BaseController {
|
|||
@GetMapping("/generateQrCode")
|
||||
public void generateQrCode(HttpServletResponse response) throws Exception {
|
||||
String scope = "auth_user"; // 需要获取用户信息
|
||||
String state = RandomUtil.randomString(3); // 防止CSRF攻击
|
||||
String appId = "2021005114616085";
|
||||
String state = ShareCodeUtils.idToCode(SecurityUtils.getUserId()); // 防止CSRF攻击
|
||||
|
||||
String encodedRedirectUri = URLEncoder.encode("https://3195d9a3.r27.cpolar.top/ali/pay/callback", "UTF-8");
|
||||
String authUrl = String.format(
|
||||
"https://openauth.alipay.com/oauth2/publicAppAuthorize.htm?app_id=%s&scope=%s&redirect_uri=%s&state=%s",
|
||||
"2021005114616085", scope, encodedRedirectUri, state
|
||||
appId, scope, encodedRedirectUri, state
|
||||
);
|
||||
|
||||
QrCodeUtil.generate(authUrl, 300, 300, "png", response.getOutputStream());
|
||||
|
@ -79,11 +74,15 @@ public class AliPayController extends BaseController {
|
|||
* @param authCode 授权码
|
||||
*/
|
||||
@GetMapping("/callback")
|
||||
public void callback(@RequestParam("auth_code") String authCode) {
|
||||
public String callback(@RequestParam("auth_code") String authCode, String state) {
|
||||
|
||||
System.out.println("authCode = " + authCode);
|
||||
aliPayService.bindingCallback(authCode);
|
||||
|
||||
String result = aliPayService.bindingCallback(authCode, state);
|
||||
if ("success".equals(result)) {
|
||||
return "binding-success";
|
||||
} else {
|
||||
return "binding-fail";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -110,14 +109,6 @@ public class AliPayController extends BaseController {
|
|||
QrCodeUtil.generate(qrUrl, 300, 300, "png", response.getOutputStream());
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看余额
|
||||
*/
|
||||
@GetMapping("/balance")
|
||||
public void balance() throws Exception {
|
||||
aliPayService.balance();
|
||||
}
|
||||
|
||||
/**
|
||||
* 提现接口
|
||||
*/
|
||||
|
@ -141,6 +132,7 @@ public class AliPayController extends BaseController {
|
|||
*/
|
||||
@Anonymous
|
||||
@PostMapping("/notify") // 注意这里必须是POST接口
|
||||
@ResponseBody
|
||||
public String payNotify(HttpServletRequest request) throws Exception {
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>绑定失败</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>支付宝账号绑定失败!</h1>
|
||||
<p>请检查您的网络或稍后重试。</p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>绑定成功</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>支付宝账号绑定成功!</h1>
|
||||
<p>您可以返回用户中心继续操作。</p>
|
||||
</body>
|
||||
</html>
|
|
@ -20,9 +20,17 @@ public class MyMetaObjectHandler implements MetaObjectHandler {
|
|||
|
||||
@Override
|
||||
public void insertFill(MetaObject metaObject) {
|
||||
this.strictInsertFill(metaObject, "createBy", String.class, SecurityUtils.getUsername());
|
||||
try {
|
||||
this.strictInsertFill(metaObject, "createBy", String.class, SecurityUtils.getUsername());
|
||||
} catch (Exception e) {
|
||||
this.strictInsertFill(metaObject, "createBy", String.class, "");
|
||||
}
|
||||
this.strictInsertFill(metaObject, "createTime", Date.class, new Date());
|
||||
this.strictInsertFill(metaObject, "tenantId", Long.class, SecurityUtils.getUserId());
|
||||
try {
|
||||
this.strictInsertFill(metaObject, "tenantId", Long.class, SecurityUtils.getUserId());
|
||||
} catch (Exception e) {
|
||||
this.strictInsertFill(metaObject, "tenantId", Long.class, -1L);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -130,7 +130,7 @@ public class SecurityConfig
|
|||
permitAllUrl.getUrls().forEach(url -> requests.antMatchers(url).permitAll());
|
||||
// 对于登录login 注册register 验证码captchaImage 允许匿名访问
|
||||
requests.antMatchers("/login", "/register", "/captchaImage","/ali/pay/doPay","/ali/pay/notify",
|
||||
"/ali/pay/generateQrCode","/ali/pay/callback").permitAll()
|
||||
"/ali/pay/callback").permitAll()
|
||||
// 静态资源,可匿名访问
|
||||
.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
|
||||
.antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
package com.mcwl.pay.service;
|
||||
|
||||
import com.alipay.api.AlipayApiException;
|
||||
import com.mcwl.common.core.domain.AjaxResult;
|
||||
import com.mcwl.pay.domain.OrderTradeDto;
|
||||
|
||||
public interface AliPayService {
|
||||
void bindingCallback(String authCode);
|
||||
String bindingCallback(String authCode, String state);
|
||||
|
||||
String memberPay(OrderTradeDto orderTradeDto) throws Exception;
|
||||
|
||||
String pointsPay(Double paymentAmount) throws Exception;
|
||||
|
||||
void balance() throws Exception;
|
||||
|
||||
String transfer(String outBizNo, String payerUserId, String payeeUserId, String amount) throws AlipayApiException;
|
||||
}
|
||||
|
|
|
@ -21,19 +21,25 @@ import com.alipay.easysdk.base.oauth.models.AlipaySystemOauthTokenResponse;
|
|||
import com.alipay.easysdk.factory.Factory;
|
||||
import com.alipay.easysdk.kernel.Config;
|
||||
import com.alipay.easysdk.payment.facetoface.models.AlipayTradePrecreateResponse;
|
||||
import com.mcwl.common.core.domain.AjaxResult;
|
||||
import com.mcwl.common.core.redis.RedisCache;
|
||||
import com.mcwl.common.exception.BusinessException;
|
||||
import com.mcwl.common.exception.ServiceException;
|
||||
import com.mcwl.common.utils.SecurityUtils;
|
||||
import com.mcwl.common.utils.ShareCodeUtils;
|
||||
import com.mcwl.memberCenter.domain.MemberLevel;
|
||||
import com.mcwl.memberCenter.service.MemberLevelService;
|
||||
import com.mcwl.pay.config.AliConfig;
|
||||
import com.mcwl.pay.domain.OrderTrade;
|
||||
import com.mcwl.pay.domain.OrderTradeDto;
|
||||
import com.mcwl.pay.service.AliPayService;
|
||||
import com.mcwl.system.domain.SysUserPayAccount;
|
||||
import com.mcwl.system.service.ISysUserPayAccountService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
@ -55,6 +61,9 @@ public class AliPayServiceImpl implements AliPayService {
|
|||
@Autowired
|
||||
private AliConfig aliConfig;
|
||||
|
||||
@Autowired
|
||||
private ISysUserPayAccountService sysUserPayAccountService;
|
||||
|
||||
|
||||
public AliPayServiceImpl(Config config) {
|
||||
Factory.setOptions(config);
|
||||
|
@ -183,10 +192,11 @@ public class AliPayServiceImpl implements AliPayService {
|
|||
|
||||
/**
|
||||
* 支付宝转账方法
|
||||
* @param outBizNo 外部业务单号
|
||||
*
|
||||
* @param outBizNo 外部业务单号
|
||||
* @param payerUserId 付款方用户ID
|
||||
* @param payeeUserId 收款方用户ID
|
||||
* @param amount 转账金额
|
||||
* @param amount 转账金额
|
||||
* @return 返回支付宝转账响应的内容
|
||||
*/
|
||||
@Override
|
||||
|
@ -238,53 +248,14 @@ public class AliPayServiceImpl implements AliPayService {
|
|||
} else {
|
||||
System.out.println("调用失败");
|
||||
// sdk版本是"4.38.0.ALL"及以上,可以参考下面的示例获取诊断链接
|
||||
String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(response);
|
||||
System.out.println(diagnosisUrl);
|
||||
String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(response);
|
||||
System.out.println(diagnosisUrl);
|
||||
}
|
||||
return response.getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看余额
|
||||
*/
|
||||
@Override
|
||||
public void balance() throws Exception {
|
||||
|
||||
AlipaySystemOauthTokenResponse token = Factory.Base.OAuth().getToken("code");
|
||||
|
||||
|
||||
// 初始化SDK
|
||||
AlipayClient alipayClient = new DefaultAlipayClient(getAlipayConfig());
|
||||
|
||||
// 构造请求参数以调用接口
|
||||
AlipayFundAccountQueryRequest request = new AlipayFundAccountQueryRequest();
|
||||
AlipayFundAccountQueryModel model = new AlipayFundAccountQueryModel();
|
||||
|
||||
// uid参数未来计划废弃,存量商户可继续使用,新商户请使用openid。请根据应用-开发配置-openid配置选择支持的字段。
|
||||
// model.setAlipayUserId("2088301409188095");
|
||||
|
||||
// 设置支付宝openId
|
||||
model.setAlipayOpenId("061P6NAblcWDWJoDRxSVvOYz-ufp-3wQaA4E_szQyMFTXse");
|
||||
|
||||
// 设置查询的账号类型
|
||||
model.setAccountType("ACCTRANS_ACCOUNT");
|
||||
|
||||
request.setBizModel(model);
|
||||
AlipayFundAccountQueryResponse response = alipayClient.execute(request);
|
||||
System.out.println(response.getBody());
|
||||
|
||||
if (response.isSuccess()) {
|
||||
System.out.println("调用成功");
|
||||
} else {
|
||||
System.out.println("调用失败");
|
||||
// sdk版本是"4.38.0.ALL"及以上,可以参考下面的示例获取诊断链接
|
||||
// String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(response);
|
||||
// System.out.println(diagnosisUrl);
|
||||
}
|
||||
}
|
||||
|
||||
private AlipayConfig getAlipayConfig() {
|
||||
String privateKey = aliConfig.getPrivateKey();
|
||||
String privateKey = aliConfig.getPrivateKey();
|
||||
String alipayPublicKey = aliConfig.getPublicKey();
|
||||
AlipayConfig alipayConfig = new AlipayConfig();
|
||||
alipayConfig.setServerUrl(aliConfig.getGatewayUrl());
|
||||
|
@ -297,25 +268,46 @@ public class AliPayServiceImpl implements AliPayService {
|
|||
return alipayConfig;
|
||||
}
|
||||
|
||||
//TODO 绑定回调,获取openId,保存到数据库
|
||||
@Override
|
||||
public void bindingCallback(String authCode) {
|
||||
public String bindingCallback(String authCode, String state) {
|
||||
try {
|
||||
Long userId = ShareCodeUtils.codeToId(state);
|
||||
if (Objects.isNull(userId)) {
|
||||
return "fail";
|
||||
}
|
||||
AlipayClient alipayClient = new DefaultAlipayClient(getAlipayConfig());
|
||||
AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();
|
||||
request.setCode(authCode);
|
||||
request.setGrantType("authorization_code");
|
||||
com.alipay.api.response.AlipaySystemOauthTokenResponse response = alipayClient.execute(request);
|
||||
if (response.isSuccess()) {
|
||||
String openId = response.getOpenId(); // 支付宝用户唯一ID
|
||||
// 将openId与当前商城用户绑定(保存到数据库)
|
||||
// 支付宝用户唯一ID
|
||||
String openId = response.getOpenId();
|
||||
// 判断是否已经绑定过
|
||||
SysUserPayAccount sysUserPayAccount = sysUserPayAccountService.lambdaQuery()
|
||||
.eq(SysUserPayAccount::getUserId, userId)
|
||||
.eq(SysUserPayAccount::getOpenId, openId)
|
||||
.eq(SysUserPayAccount::getType, 0)
|
||||
.one();
|
||||
if (Objects.nonNull(sysUserPayAccount)) {
|
||||
// 已经绑定过,直接返回
|
||||
return "success";
|
||||
}
|
||||
System.out.println("绑定成功!openId:" + openId);
|
||||
// 将openId与当前商城用户绑定(保存到数据库)
|
||||
SysUserPayAccount userPayAccount = new SysUserPayAccount();
|
||||
userPayAccount.setUserId(userId);
|
||||
userPayAccount.setOpenId(openId);
|
||||
userPayAccount.setType(0);
|
||||
sysUserPayAccountService.save(userPayAccount);
|
||||
return "success";
|
||||
} else {
|
||||
System.out.println("绑定失败:" + response.getSubMsg());
|
||||
return "fail";
|
||||
}
|
||||
|
||||
} catch (AlipayApiException e) {
|
||||
throw new RuntimeException(e);
|
||||
return "fail";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
package com.mcwl.system.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.mcwl.common.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 消息通知
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("sys_user_pay_account")
|
||||
public class SysUserPayAccount extends BaseEntity {
|
||||
|
||||
@TableId
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
private Long userId;
|
||||
/**
|
||||
* 账号唯一标识
|
||||
*/
|
||||
private String openId;
|
||||
/**
|
||||
* 账号类型 0 支付宝 1 微信 2 QQ
|
||||
*/
|
||||
private Integer type;
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package com.mcwl.system.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.mcwl.system.domain.SysUserPayAccount;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 用户支付账户
|
||||
*/
|
||||
@Mapper
|
||||
public interface SysUserPayAccountMapper extends BaseMapper<SysUserPayAccount> {
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.mcwl.system.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.mcwl.system.domain.SysUserPayAccount;
|
||||
|
||||
/**
|
||||
* 用户支付账户 服务层
|
||||
*
|
||||
* @author mcwl
|
||||
*/
|
||||
public interface ISysUserPayAccountService extends IService<SysUserPayAccount> {
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package com.mcwl.system.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.mcwl.system.domain.SysUserPayAccount;
|
||||
import com.mcwl.system.mapper.SysUserPayAccountMapper;
|
||||
import com.mcwl.system.service.ISysUserPayAccountService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户支付账户 业务层处理
|
||||
*/
|
||||
@Service
|
||||
public class SysUserPayAccountServiceImpl extends ServiceImpl<SysUserPayAccountMapper, SysUserPayAccount> implements ISysUserPayAccountService {
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue