mirror of https://github.com/macrozheng/mall
添加支付功能
parent
9b4343e436
commit
b3bc051e79
|
@ -41,6 +41,13 @@
|
|||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-amqp</artifactId>
|
||||
</dependency>
|
||||
<!--支付宝支付Java SDK-->
|
||||
<dependency>
|
||||
<groupId>com.alipay.sdk</groupId>
|
||||
<artifactId>alipay-sdk-java</artifactId>
|
||||
<version>${alipay-sdk.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package com.macro.mall.portal.config;
|
||||
|
||||
import com.alipay.api.AlipayClient;
|
||||
import com.alipay.api.DefaultAlipayClient;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @auther macrozheng
|
||||
* @description 支付宝请求客户端配置
|
||||
* @date 2023/9/8
|
||||
* @github https://github.com/macrozheng
|
||||
*/
|
||||
@Configuration
|
||||
public class AlipayClientConfig {
|
||||
|
||||
@Bean
|
||||
public AlipayClient alipayClient(AlipayConfig config){
|
||||
return new DefaultAlipayClient(config.getGatewayUrl(),config.getAppId(),config.getAppPrivateKey(), config.getFormat(),config.getCharset(),config.getAlipayPublicKey(),config.getSignType());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package com.macro.mall.portal.config;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @auther macrozheng
|
||||
* @description 支付宝支付相关配置
|
||||
* @date 2023/9/8
|
||||
* @github https://github.com/macrozheng
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "alipay")
|
||||
public class AlipayConfig {
|
||||
/**
|
||||
* 支付宝网关
|
||||
*/
|
||||
private String gatewayUrl;
|
||||
/**
|
||||
* 应用ID
|
||||
*/
|
||||
private String appId;
|
||||
/**
|
||||
* 应用私钥
|
||||
*/
|
||||
private String appPrivateKey;
|
||||
/**
|
||||
* 支付宝公钥
|
||||
*/
|
||||
private String alipayPublicKey;
|
||||
/**
|
||||
* 用户确认支付后,支付宝调用的页面返回路径
|
||||
* 开发环境为:http://localhost:8060/#/pages/money/paySuccess
|
||||
*/
|
||||
private String returnUrl;
|
||||
/**
|
||||
* 支付成功后,支付宝服务器主动通知商户服务器里的异步通知回调(需要公网能访问)
|
||||
* 开发环境为:http://localhost:8085/alipay/notify
|
||||
*/
|
||||
private String notifyUrl;
|
||||
/**
|
||||
* 参数返回格式,只支持JSON
|
||||
*/
|
||||
private String format = "JSON";
|
||||
/**
|
||||
* 请求使用的编码格式
|
||||
*/
|
||||
private String charset = "UTF-8";
|
||||
/**
|
||||
* 生成签名字符串所使用的签名算法类型
|
||||
*/
|
||||
private String signType = "RSA2";
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package com.macro.mall.portal.controller;
|
||||
|
||||
import com.macro.mall.common.api.CommonResult;
|
||||
import com.macro.mall.portal.config.AlipayConfig;
|
||||
import com.macro.mall.portal.domain.AliPayParam;
|
||||
import com.macro.mall.portal.service.AlipayService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @auther macrozheng
|
||||
* @description 支付宝支付Controller
|
||||
* @date 2023/9/8
|
||||
* @github https://github.com/macrozheng
|
||||
*/
|
||||
@Controller
|
||||
@Api(tags = "AlipayController")
|
||||
@Tag(name = "AlipayController", description = "支付宝支付相关接口")
|
||||
@RequestMapping("/alipay")
|
||||
public class AlipayController {
|
||||
|
||||
@Autowired
|
||||
private AlipayConfig alipayConfig;
|
||||
@Autowired
|
||||
private AlipayService alipayService;
|
||||
|
||||
@ApiOperation("支付宝电脑网站支付")
|
||||
@RequestMapping(value = "/pay", method = RequestMethod.GET)
|
||||
public void pay(AliPayParam aliPayParam, HttpServletResponse response) throws IOException {
|
||||
response.setContentType("text/html;charset=" + alipayConfig.getCharset());
|
||||
response.getWriter().write(alipayService.pay(aliPayParam));
|
||||
response.getWriter().flush();
|
||||
response.getWriter().close();
|
||||
}
|
||||
|
||||
@ApiOperation("支付宝手机网站支付")
|
||||
@RequestMapping(value = "/webPay", method = RequestMethod.GET)
|
||||
public void webPay(AliPayParam aliPayParam, HttpServletResponse response) throws IOException {
|
||||
response.setContentType("text/html;charset=" + alipayConfig.getCharset());
|
||||
response.getWriter().write(alipayService.webPay(aliPayParam));
|
||||
response.getWriter().flush();
|
||||
response.getWriter().close();
|
||||
}
|
||||
|
||||
@ApiOperation(value = "支付宝异步回调",notes = "必须为POST请求,执行成功返回success,执行失败返回failure")
|
||||
@RequestMapping(value = "/notify", method = RequestMethod.POST)
|
||||
public String notify(HttpServletRequest request){
|
||||
Map<String, String> params = new HashMap<>();
|
||||
Map<String, String[]> requestParams = request.getParameterMap();
|
||||
for (String name : requestParams.keySet()) {
|
||||
params.put(name, request.getParameter(name));
|
||||
}
|
||||
return alipayService.notify(params);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "支付宝统一收单线下交易查询",notes = "订单支付成功返回:TRADE_SUCCESS")
|
||||
@RequestMapping(value = "/query", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public CommonResult<String> query(String outTradeNo, String tradeNo){
|
||||
return CommonResult.success(alipayService.query(outTradeNo,tradeNo));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.macro.mall.portal.domain;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* @auther macrozheng
|
||||
* @description 支付宝支付请求参数
|
||||
* @date 2023/9/8
|
||||
* @github https://github.com/macrozheng
|
||||
*/
|
||||
@Data
|
||||
public class AliPayParam {
|
||||
/**
|
||||
* 商户订单号,商家自定义,保持唯一性
|
||||
*/
|
||||
private String outTradeNo;
|
||||
/**
|
||||
* 商品的标题/交易标题/订单标题/订单关键字等
|
||||
*/
|
||||
private String subject;
|
||||
/**
|
||||
* 订单总金额,单位为元,精确到小数点后两位
|
||||
*/
|
||||
private BigDecimal totalAmount;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package com.macro.mall.portal.service;
|
||||
|
||||
|
||||
import com.macro.mall.portal.domain.AliPayParam;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @auther macrozheng
|
||||
* @description 支付宝支付Service
|
||||
* @date 2023/9/8
|
||||
* @github https://github.com/macrozheng
|
||||
*/
|
||||
public interface AlipayService {
|
||||
/**
|
||||
* 根据提交参数生成电脑支付页面
|
||||
*/
|
||||
String pay(AliPayParam aliPayParam);
|
||||
|
||||
/**
|
||||
* 支付宝异步回调处理
|
||||
*/
|
||||
String notify(Map<String, String> params);
|
||||
|
||||
/**
|
||||
* @param outTradeNo 商户订单编号
|
||||
* @param tradeNo 支付宝交易编号
|
||||
* @return 支付宝交易状态
|
||||
*/
|
||||
String query(String outTradeNo, String tradeNo);
|
||||
|
||||
/**
|
||||
* 根据提交参数生成手机支付页面
|
||||
*/
|
||||
String webPay(AliPayParam aliPayParam);
|
||||
}
|
|
@ -67,4 +67,10 @@ public interface OmsPortalOrderService {
|
|||
* 用户根据订单ID删除订单
|
||||
*/
|
||||
void deleteOrder(Long orderId);
|
||||
|
||||
/**
|
||||
* 根据orderSn来实现的支付成功逻辑
|
||||
*/
|
||||
@Transactional
|
||||
void paySuccessByOrderSn(String orderSn, Integer payType);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,160 @@
|
|||
package com.macro.mall.portal.service.impl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alipay.api.AlipayApiException;
|
||||
import com.alipay.api.AlipayClient;
|
||||
import com.alipay.api.internal.util.AlipaySignature;
|
||||
import com.alipay.api.request.AlipayTradePagePayRequest;
|
||||
import com.alipay.api.request.AlipayTradeQueryRequest;
|
||||
import com.alipay.api.request.AlipayTradeWapPayRequest;
|
||||
import com.alipay.api.response.AlipayTradeQueryResponse;
|
||||
import com.macro.mall.mapper.OmsOrderMapper;
|
||||
import com.macro.mall.portal.config.AlipayConfig;
|
||||
import com.macro.mall.portal.domain.AliPayParam;
|
||||
import com.macro.mall.portal.service.AlipayService;
|
||||
import com.macro.mall.portal.service.OmsPortalOrderService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @auther macrozheng
|
||||
* @description 支付宝支付Service实现类
|
||||
* @date 2023/9/8
|
||||
* @github https://github.com/macrozheng
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class AlipayServiceImpl implements AlipayService {
|
||||
@Autowired
|
||||
private AlipayConfig alipayConfig;
|
||||
@Autowired
|
||||
private AlipayClient alipayClient;
|
||||
@Autowired
|
||||
private OmsOrderMapper orderMapper;
|
||||
@Autowired
|
||||
private OmsPortalOrderService portalOrderService;
|
||||
@Override
|
||||
public String pay(AliPayParam aliPayParam) {
|
||||
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
|
||||
if(StrUtil.isNotEmpty(alipayConfig.getNotifyUrl())){
|
||||
//异步接收地址,公网可访问
|
||||
request.setNotifyUrl(alipayConfig.getNotifyUrl());
|
||||
}
|
||||
if(StrUtil.isNotEmpty(alipayConfig.getReturnUrl())){
|
||||
//同步跳转地址
|
||||
request.setReturnUrl(alipayConfig.getReturnUrl());
|
||||
}
|
||||
//******必传参数******
|
||||
JSONObject bizContent = new JSONObject();
|
||||
//商户订单号,商家自定义,保持唯一性
|
||||
bizContent.put("out_trade_no", aliPayParam.getOutTradeNo());
|
||||
//支付金额,最小值0.01元
|
||||
bizContent.put("total_amount", aliPayParam.getTotalAmount());
|
||||
//订单标题,不可使用特殊符号
|
||||
bizContent.put("subject", aliPayParam.getSubject());
|
||||
//电脑网站支付场景固定传值FAST_INSTANT_TRADE_PAY
|
||||
bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");
|
||||
request.setBizContent(bizContent.toString());
|
||||
String formHtml = null;
|
||||
try {
|
||||
formHtml = alipayClient.pageExecute(request).getBody();
|
||||
} catch (AlipayApiException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return formHtml;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String notify(Map<String, String> params) {
|
||||
String result = "failure";
|
||||
boolean signVerified = false;
|
||||
try {
|
||||
//调用SDK验证签名
|
||||
signVerified = AlipaySignature.rsaCheckV1(params, alipayConfig.getAlipayPublicKey(), alipayConfig.getCharset(), alipayConfig.getSignType());
|
||||
} catch (AlipayApiException e) {
|
||||
log.error("支付回调签名校验异常!",e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (signVerified) {
|
||||
String tradeStatus = params.get("trade_status");
|
||||
if("TRADE_SUCCESS".equals(tradeStatus)){
|
||||
result = "success";
|
||||
log.info("notify方法被调用了,tradeStatus:{}",tradeStatus);
|
||||
String outTradeNo = params.get("out_trade_no");
|
||||
portalOrderService.paySuccessByOrderSn(outTradeNo,1);
|
||||
}else{
|
||||
log.warn("订单未支付成功,trade_status:{}",tradeStatus);
|
||||
}
|
||||
} else {
|
||||
log.warn("支付回调签名校验失败!");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String query(String outTradeNo, String tradeNo) {
|
||||
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
|
||||
//******必传参数******
|
||||
JSONObject bizContent = new JSONObject();
|
||||
//设置查询参数,out_trade_no和trade_no至少传一个
|
||||
if(StrUtil.isNotEmpty(outTradeNo)){
|
||||
bizContent.put("out_trade_no",outTradeNo);
|
||||
}
|
||||
if(StrUtil.isNotEmpty(tradeNo)){
|
||||
bizContent.put("trade_no",tradeNo);
|
||||
}
|
||||
//交易结算信息: trade_settle_info
|
||||
String[] queryOptions = {"trade_settle_info"};
|
||||
bizContent.put("query_options", queryOptions);
|
||||
request.setBizContent(bizContent.toString());
|
||||
AlipayTradeQueryResponse response = null;
|
||||
try {
|
||||
response = alipayClient.execute(request);
|
||||
} catch (AlipayApiException e) {
|
||||
log.error("查询支付宝账单异常!",e);
|
||||
}
|
||||
if(response.isSuccess()){
|
||||
log.info("查询支付宝账单成功!");
|
||||
portalOrderService.paySuccessByOrderSn(outTradeNo,1);
|
||||
} else {
|
||||
log.error("查询支付宝账单失败!");
|
||||
}
|
||||
//交易状态:WAIT_BUYER_PAY(交易创建,等待买家付款)、TRADE_CLOSED(未付款交易超时关闭,或支付完成后全额退款)、TRADE_SUCCESS(交易支付成功)、TRADE_FINISHED(交易结束,不可退款)
|
||||
return response.getTradeStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String webPay(AliPayParam aliPayParam) {
|
||||
AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest ();
|
||||
if(StrUtil.isNotEmpty(alipayConfig.getNotifyUrl())){
|
||||
//异步接收地址,公网可访问
|
||||
request.setNotifyUrl(alipayConfig.getNotifyUrl());
|
||||
}
|
||||
if(StrUtil.isNotEmpty(alipayConfig.getReturnUrl())){
|
||||
//同步跳转地址
|
||||
request.setReturnUrl(alipayConfig.getReturnUrl());
|
||||
}
|
||||
//******必传参数******
|
||||
JSONObject bizContent = new JSONObject();
|
||||
//商户订单号,商家自定义,保持唯一性
|
||||
bizContent.put("out_trade_no", aliPayParam.getOutTradeNo());
|
||||
//支付金额,最小值0.01元
|
||||
bizContent.put("total_amount", aliPayParam.getTotalAmount());
|
||||
//订单标题,不可使用特殊符号
|
||||
bizContent.put("subject", aliPayParam.getSubject());
|
||||
//手机网站支付默认传值FAST_INSTANT_TRADE_PAY
|
||||
bizContent.put("product_code", "QUICK_WAP_WAY");
|
||||
request.setBizContent(bizContent.toString());
|
||||
String formHtml = null;
|
||||
try {
|
||||
formHtml = alipayClient.pageExecute(request).getBody();
|
||||
} catch (AlipayApiException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return formHtml;
|
||||
}
|
||||
}
|
|
@ -419,6 +419,20 @@ public class OmsPortalOrderServiceImpl implements OmsPortalOrderService {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paySuccessByOrderSn(String orderSn, Integer payType) {
|
||||
OmsOrderExample example = new OmsOrderExample();
|
||||
example.createCriteria()
|
||||
.andOrderSnEqualTo(orderSn)
|
||||
.andStatusEqualTo(0)
|
||||
.andDeleteStatusEqualTo(0);
|
||||
List<OmsOrder> orderList = orderMapper.selectByExample(example);
|
||||
if(CollUtil.isNotEmpty(orderList)){
|
||||
OmsOrder order = orderList.get(0);
|
||||
paySuccess(order.getId(),payType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成18位订单编号:8位日期+2位平台号码+2位支付方式+6位以上自增id
|
||||
*/
|
||||
|
|
|
@ -42,3 +42,11 @@ logstash:
|
|||
host: localhost
|
||||
enableInnerLog: false
|
||||
|
||||
alipay:
|
||||
gatewayUrl: https://openapi-sandbox.dl.alipaydev.com/gateway.do
|
||||
appId: your appId
|
||||
alipayPublicKey: your alipayPublicKey
|
||||
appPrivateKey: your appPrivateKey
|
||||
returnUrl: http://localhost:8060/#/pages/money/paySuccess
|
||||
notifyUrl:
|
||||
|
||||
|
|
|
@ -50,3 +50,11 @@ logging:
|
|||
logstash:
|
||||
host: logstash
|
||||
|
||||
alipay:
|
||||
gatewayUrl: https://openapi-sandbox.dl.alipaydev.com/gateway.do
|
||||
appId: your appId
|
||||
alipayPublicKey: your alipayPublicKey
|
||||
appPrivateKey: your appPrivateKey
|
||||
returnUrl: http://192.168.3.101:8060/#/pages/money/paySuccess
|
||||
notifyUrl:
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ secure:
|
|||
- /home/**
|
||||
- /product/**
|
||||
- /brand/**
|
||||
- /alipay/**
|
||||
|
||||
# 自定义redis key
|
||||
redis:
|
||||
|
|
15
pom.xml
15
pom.xml
|
@ -46,6 +46,7 @@
|
|||
<spring-data-commons.version>2.7.5</spring-data-commons.version>
|
||||
<jjwt.version>0.9.1</jjwt.version>
|
||||
<aliyun-oss.version>2.5.0</aliyun-oss.version>
|
||||
<alipay-sdk.version>4.38.61.ALL</alipay-sdk.version>
|
||||
<logstash-logback.version>7.2</logstash-logback.version>
|
||||
<minio.version>8.4.5</minio.version>
|
||||
<jaxb-api.version>2.3.1</jaxb-api.version>
|
||||
|
@ -257,4 +258,18 @@
|
|||
</pluginManagement>
|
||||
</build>
|
||||
|
||||
<!--使用aliyun的Maven镜像源提升下载速度-->
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>aliyunmaven</id>
|
||||
<name>aliyun</name>
|
||||
<url>https://maven.aliyun.com/repository/public</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>central2</id>
|
||||
<name>central2</name>
|
||||
<url>https://repo1.maven.org/maven2/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
</project>
|
Loading…
Reference in New Issue