实习期间我负责的项目需要支付功能,为了能实现这个功能
支付的逻辑几乎每个第三方的API逻辑都大差不差,第一步就是调用第三方支付的下单接口,一般在调用支付接口的时候,会有一个参数被称为 回调url,这个参数一般需要填一个自己的后台接口,这时候,第三方API就会收到一个下单的请求,返回值一般是会有一个用户支付的url,我们需要将这个url返给前端,引导用户跳转去支付,接着第三方API会从参数中找到回调url,对我们自己的接口进行一个调用,这个调用一般会告诉我们用户是否支付成功等。支付成功就需要执行相应的业务逻辑,并设法告诉用户支付成功!
支付第一步 下单!
一般的支付都是需要调用支付的第三方的API,首先需要找到需要合适的支付第三方,例如支付宝支付,微信支付等,本次用的dreamo9 API,一个国外的支付API。 https://www.showdoc.com.cn/dreamo9/10967763922846220 链接为API文档
如图就是一个第三方支付

编写自己的业务逻辑下单代码
这是service的代码,主要逻辑是先构建订单信息,并存入自己的数据库,然后调用自定义函数去发请求,调用第三方支付接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public String createPaymentOrder(GoodsReqBO req) {
if (req.getUserInfoPO().isCharged() && req.getGoodId() == 0) { log.error("[createOrderAndGetRedirectUrl] not charge again , req is {}", JSONUtil.toJsonStr(req)); throw BizException.of(BizCode.HAS_CHARGED); } GoodsInfoPO goodsInfo = goodsInfoService.lambdaQuery() .eq(GoodsInfoPO::getGoodId, req.getGoodId()) .one(); if (Objects.isNull(goodsInfo)) { log.error("[createOrderAndGetRedirectUrl] not exist , req is {}", JSONUtil.toJsonStr(req)); throw BizException.of(BizCode.DATA_NOT_EXIST, req.getGoodId()); } GoodsOrderPO paymentOrder = goodsOrderService.createGoodsOrder(goodsInfo, req.getUserInfoPO()); String payurl = this.createPayment(paymentOrder, req); return payurl; }
|
这是根据第三方支付的api文档中编写的请求体,根据文档中payData是支付路径,最后通过浏览器打开支付路径
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| private String createPayment(GoodsOrderPO paymentOrder, GoodsReqBO req) { Map<String, Object> params = new HashMap<>(); params.put("mchNo", "M1744790674"); params.put("appId", "A1744790727"); params.put("mchOrderNo", paymentOrder.getOrderId()); params.put("amount", 2222); params.put("currency", "SAR"); params.put("clientIp", req.getUserInfoPO().getRegistryIP()); params.put("uid", req.getUserInfoPO().getUuid()); params.put("customerName", req.getUserInfoPO().getName()); params.put("customerEmail", req.getUserInfoPO().getEmail()); params.put("customerPhone", "8197220658"); params.put("notifyUrl", req.getRedirectUrl()); params.put("reqTime", System.currentTimeMillis());
String sign = Dreamo9Sign.getSign(params, "3V32ODHkXzPh2swrE1qpe9orXiTTwwQaymsFDFpkGVsr8jcob7K2nyZVjBEB5j7sT6nLjxgeet6KWVjyksi8N7rLJ1XqFDDNvPzOzsEPwmZIUDHK7c3fqb9eNtdxqfel"); params.put("sign", sign);
RestTemplate restTemplate = new RestTemplate();
String url = "https://live.dreamo9.com/api/payment";
HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(params, headers);
ResponseEntity<Object> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, Object.class);
ObjectMapper objectMapper = new ObjectMapper(); Map<String, Object> res= objectMapper.convertValue(response.getBody(), Map.class); if (!res.get("code").equals(0)){ System.out.println("这个表示失败了"); throw new RuntimeException("下单失败"); } return (String) res.get("payData");
}
|
这是支付路径打开后的结果,由于这只是测试环境,正常线上用户在这里支付成功后就会进行回调接口

回调测试
当我们下单逻辑成功后,第三方支付api就会对我们的接口进行回调,但是我们首先需要将服务部署到线上才可以,因为第三方是调不通内网的,所以需要部署到服务器上,用域名进行访问
- 首先需要通过api文档,来看第三方支付回调携带的参数有哪些,根据参数可以判断出是否支付成功和订单号等。通过这些参数信息去执行我们的业务逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @PostMapping("/Dreamo9/success") public CommonResult<String> Dreamo9SuccessPay(@RequestParam Map<String, String> params) { log.info("Method starts execution"); log.info("Dreamo9SuccessPay params:{}", params); String state = params.get("state"); log.info("Dreamo9SuccessPay state:{}", state); String mchOrderNo = params.get("mchOrderNo"); log.info("Dreamo9SuccessPay mchOrderNo:{}", mchOrderNo); if (Integer.parseInt(state)==2){ paypalBiz.payDreamo9Success(params); log.info("Dreamo9SuccessPay paySuccess"); } return success; }
|
项目部署
因为第三方是根本调不通内网的,要么内网穿透,要么将项目部署到线上,通过公网访问
解析域名
项目上线是需要域名,我们需要一个域名,域名指定的ip为服务器的ip即可。
项目部署
这个项目是部署到AWS服务器上的.
- 连接服务器
通过ssh 连接服务器,需要管理员添加密钥,不然连接不上 - 将springboot项目的jar上传到服务器上的指定文件夹中
1
| scp build/libs/backend-0.0.1-SNAPSHOT.jar ubuntu@40.172.61.245:/usr/myproject/
|
然后sudo apt install openjdk-17-jre-headless 下载环境 中途选择 y
直接 java -jar jar包名字.jar 运行jar包
这样项目正常启动就说明部署好了
这样只是部署好了,但是仍然会无法访问,需要配置nginx或者caddy 进行路由转发
配置Caddy
一、静态页面的部署
1.将静态页面上传到服务器实例机器中
2.下载Caddy(官网有命令)
3.编写Caddy,进行反代和记载静态页面
sudo setcap cap_net_bind_service=+ep $(which caddy)
1 2 3 4 5 6 7 8 9 10 11
| 域名 { reverse_proxy 127.0.0.1:18080 将这个域名反代到了本地18080端口 } 域名 { root * /myproject 去这里的文件夹中找静态页面 file_server 启动静态页面的管理 @api { path /api/* 代理api } reverse_proxy @api 127.0.0.1:18080 将静态页面的请求进行反代 }
|
结语
从请求回调的问题 发现需要部署项目到线上,又到发现项目部署了,但是访问不到,一直报502错误,发现需要配置Caddy。到这里本地已经可以模拟回调成功了,但是仍不能第三方调通,测了好多次最后发现是 第三方API发的请求发错了,文档里写的POST 结果发来是GET!