步骤1:注册一个沙箱号
网站https://open.alipay.com/platform/home.htm
使用自己真实的支付宝扫描进去,进行注册沙箱支付宝
步骤2:下载密匙生成工具
下载完毕,解压,双击运行
网址:https://opendocs.alipay.com/mini/02c7i5
步骤3:生成支付宝公钥
进入沙箱,把生成的公钥放进就去,就会自动生成支付宝公钥了
步骤4:添加支付宝提供的支付相关坐标
接下来创建Java项目,在我们的pom.xml文件中添加支付宝提供的支付相关坐标
<!-- alipay-sdk-java 依赖 -->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.10.192.ALL</version>
</dependency>
步骤5:创建支付的Controller类
●将从Controller中进入支付宝支付,需完成支付宝提供的接口
●创建类,有如下代码,设置如下私有属性:
具体位置内容如下:
步骤6:在Controller类中创建点击支付跳转支付宝页面的方法
package top.qiudb.controller.alipay;
import com.alipay.api.AlipayApiException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import top.qiudb.service.pay.AlipayService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import top.qiudb.util.tools.ResultVO;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;
@Slf4j
@Controller
@RequestMapping("/alipay")
@Api(tags = "支付宝虚拟支付接口")
public class AlipayController {
private final AlipayService alipayService;
public AlipayController(AlipayService alipayService) {
this.alipayService = alipayService;
}
/*
https://qiustudy.utools.club/alipay/create?orderNo=10060&orderName=花卷商城-华为手机支付订单&payPrice=4000
*/
@ResponseBody
@PostMapping(value = "/create")
@ApiOperation("创建订单")
public String create(@ApiParam("订单号") @RequestParam("orderNo") String orderNo,
@ApiParam("订单名称") @RequestParam("orderName") String orderName,
@ApiParam("支付金额") @RequestParam("payPrice") String payPrice) {
//发起支付,调用封装好的方法(给支付宝接口发送请求)
return alipayService.create(orderNo, orderName, payPrice);
}
/*
https://qiustudy.utools.club/alipay/refund?orderNo=10060&payPrice=4000
*/
@ResponseBody
@PostMapping(value = "/refund")
@ApiOperation("订单退款")
public ResultVO refund(@ApiParam("订单号") @RequestParam("orderNo") String orderNo,
@ApiParam("退款金额") @RequestParam("payPrice") String payPrice) {
//发起支付
try {
alipayService.refund(orderNo, payPrice);
} catch (AlipayApiException e) {
log.error("【支付宝支付】退款失败 error={}", e.toString());
return ResultVO.error("退款失败");
}
return ResultVO.success("退款成功");
}
@GetMapping(value = "/paySuccess")
@ApiOperation("支付成功同步回调接口")
public void success(@RequestParam Map<String, String> map, HttpServletResponse response) {
try {
String tradeNo = map.get("out_trade_no");
System.out.println("订单号:" + tradeNo);
response.sendRedirect("/paySuccess");
} catch (IOException e) {
log.error("支付成功,但重定向失败 error={}", e.toString());
}
}
@ResponseBody
@PostMapping(value = "/payNotify")
@ApiOperation("支付成功异步回调接口")
public void payNotify(@RequestParam Map<String, String> map) {
String tradeStatus = map.get("trade_status");
if (tradeStatus.equals("TRADE_SUCCESS")) {
String payTime = map.get("gmt_payment");
String tradeNo = map.get("out_trade_no");
String tradeName = map.get("subject");
String payAmount = map.get("buyer_pay_amount");
log.info("[支付成功] {交易时间:{},订单号:{},订单名称:{},交易金额:{}}", payTime, tradeNo, tradeName, payAmount);
}
}
}
解释:在前端页面点击支付后,将跳转Controller的AlipayController( )方法
●AlipayController方法会接收一些前端的参数
●AlipayController方法中再调用alipayService方法,alipayService方法中有支付宝官方给出的接口,只需在其中提供一些参数(支付宝严格规定的参数)
alipayService方法
●除了需要提供之前设置好的私有属性(URL,公钥,私钥,网关等等)外,●还需要提供的参数
订单号,必须为String64位,不能为空且不能重复
支付金额,不能为空
订单名称,不能为空
商品描述,可以为空
上面三个必填参数很重要且必须遵守支付宝的规定,在扫码支付的时候能看到且有用
package top.qiudb.service.pay;
import com.alipay.api.AlipayApiException;
public interface AlipayService {
String create(String orderId, String orderName, String payPrice);
void refund(String orderId, String payPrice) throws AlipayApiException;
}
package top.qiudb.service.pay;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.domain.AlipayTradeWapPayModel;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import top.qiudb.config.AlipayConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class AlipayServiceImpl implements AlipayService {
//和支付宝签约的产品码 固定值
private static final String PRODUCTCODE = "QUICK_WAP_WAY";
//支付成功标识(可退款的签约是TRADE_SUCCESS,不可退款的签约是TRADE_FINISHED)
//private static final String TRADE_SUCCESS = "TRADE_SUCCESS";
@Override
public String create(String orderId,String orderName,String payPrice) {
AlipayClient client = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID, AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY,AlipayConfig.SIGNTYPE);
AlipayTradeWapPayRequest alipay_request=new AlipayTradeWapPayRequest();
// 封装请求支付信息
AlipayTradeWapPayModel model= new AlipayTradeWapPayModel();
//订单编号,不可重复
model.setOutTradeNo(orderId);
//订单名称
model.setSubject(orderName);
//订单金额
model.setTotalAmount(payPrice);
//产品码
model.setProductCode(PRODUCTCODE);
alipay_request.setBizModel(model);
//支付成功后跳转的地址
alipay_request.setReturnUrl(AlipayConfig.return_url);
//异步通知地址
alipay_request.setNotifyUrl(AlipayConfig.notify_url);
// form表单生产
String result = "";
try {
// 调用SDK生成表单
result = client.pageExecute(alipay_request).getBody();
} catch (AlipayApiException e) {
log.info("【支付宝支付】支付失败 error={}", e.toString());
}
return result;
}
@Override
public void refund(String orderId, String payPrice) throws AlipayApiException {
AlipayClient client = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID, AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, AlipayConfig.ZHIFUBAO_PUBLIC_KEY,AlipayConfig.SIGNTYPE);
AlipayTradeRefundRequest alipay_request = new AlipayTradeRefundRequest();
AlipayTradeRefundModel model=new AlipayTradeRefundModel();
//退款的订单Id,也可以设置流水号
model.setOutTradeNo(orderId);
//退款金额
model.setRefundAmount(payPrice);
alipay_request.setBizModel(model);
String alipay_response = client.execute(alipay_request).getBody();
log.info("[支付退款] response={}", alipay_response);
}
}
步骤7:写支付完成后同步回调的方法
●扫码(或输入密码)支付完成后,支付宝会自动调用我们之前设置好的return_url(其实是本机调用),所以这个地址可以是私网地址
同样,还是在Controller中完成