springcloud如何搭建支付宝pay-service微服务

小提示

  • 前提须知:支付宝开放平台及其SDK使用(没看此篇难懂以下讲解)
  • 支付宝开放平台链接:https://developers.alipay.com/platform/home.htm
  • 一个应用,包含一个公钥和一个密钥,也包含一个买家和一个卖家,只是沙箱模拟,有了公钥即可进行验签操作,本次演示有3处用到验签(1.同步回调,2.异步回调,3.将api生成的表单提交给支付宝网关)

逻辑图

  • 发起支付的时候需要传递6个参数(订单编号,付款金额,订单名称,商品描述,同步回调地址,异步回调地址) 给到支付宝api,然后支付宝会生成一个String类型的form表单(并且携带提交表单功能的js代码,此from表单不会显示在页面上看到,一生成就马上提交给支付宝网关了)返回,这个过程也称之为验签
  • 若此验签操作没问题后,则会在页面显示让你登陆你的支付宝账号和密码,随后输入支付密码进行支付
  • 支付成功后,则开始分别调用同步回调异步回调,两个回调方法内都会分别进行验签判断,确保是支付宝方来请求回调url才可进行后面的逻辑操作
  • 同步回调用来返回要显示的页面效果,异步回调用来做后台的逻辑操作(比如支付完后的订单,修改其状态)
  • 若要执行退款操作,则需要传递3个参数(交易订单号,退款金额,退款原因)给退款接口进行逻辑操作,退款成功则返回sucess
    在这里插入图片描述

配置

pom.xml

   <dependency>
            <groupId>com.alipay.sdk</groupId>
            <artifactId>alipay-sdk-java</artifactId>
            <version>4.10.170.ALL</version>
        </dependency>

pay-service-dev.yaml

  • 这个放在配置中心上
server:
  port: 8051
ribbon:
  eager-load:
    enabled: true
rocketmq:
  producer:
    group: pay-group
alipay:
  app_id : 支付宝开放平台应用的appId
  merchant_private_key : 私钥数据
  alipay_public_key : 公钥数据
  sign_type : RSA2
  charset : utf-8
  gatewayUrl : https://openapi.alipaydev.com/gateway.do

bootstrap.yml

  • 这个放在本地idea中,拉去配置中心上的配置
spring:
  application:
    name: pay-service
  cloud:
    nacos:
      config:
        server-addr: 192.168.8.12:8848 #nacos中心地址
        file-extension: yaml # 配置文件格式
        shared-configs:
          - data-id: nacos-discovery-config-dev.yaml
  profiles:
    active: dev # 环境标识
  • 其他服务,要传入同步回调和异步回调Url,给到支付宝微服务去进行回调
  • 所以其他服务为了解决硬编码问题,将同步和异步回调的url自定义配置在了yml配置更加美观
  • 其他需要用到支付宝微服务的服务的application.yml(做参考就行)
pay:
  returnUrl: 同步回调的接口url
  notifyUrl: 异步回调的接口url
  frontEndPayUrl: 同步回调方法里,要显示给用户页面的url路径

开搞

  • pay-service微服务架构图
    在这里插入图片描述

AlipayProperties

  • 通过@ConfigurationProperties(prefix = "alipay") 注入了yml配置文件对应的值给以下属性
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * Created by wolfcode-lanxw
 */
@Setter
@Getter
@Component
@ConfigurationProperties(prefix = "alipay")
public class AlipayProperties {
    //商品应用ID
    private String appId;
    // 商户私钥,您的PKCS8格式RSA2私钥
    private String merchantPrivateKey;
    // 支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
    private String alipayPublicKey;
    // 签名方式
    private String signType ;
    // 字符编码格式
    private String charset;
    // 支付宝网关
    private String gatewayUrl ;
}

AlipayConfig

  • 将此包含了公钥等数据(可用作验签)的支付宝AlipayClient对象交给spring管理
@Configuration
public class AlipayConfig {
    @Bean
    public AlipayClient alipayClient(AlipayProperties alipayProperties){
        return new DefaultAlipayClient(alipayProperties.getGatewayUrl(), alipayProperties.getAppId(), alipayProperties.getMerchantPrivateKey(), "json", alipayProperties.getCharset(), alipayProperties.getAlipayPublicKey(), alipayProperties.getSignType());
    }
}

控制器各接口代码演示

  • payOnline接口:作为支付接口,接收PayVo对象(6个参数),通过alipayClient对象(内包含公钥)操作返回一个String类型的表单(包含js提交表单操作功能,此表单直接提交数据给支付宝网关,也就是验签操作),这里也相当于验签操作,成功以后,用户浏览器则出现登陆支付宝账号和密码页面,即可输入支付密码完成支付(商家余额增加,用户余额减少)
  • rsaCheck接口:用作同步异步回调时候的验签判断操作,防止中途数据被篡改,保证是支付宝方来访问的回调url操作
  • refundOnline接口:用作退款接口,接收RefundVo对象(3个参数),通过alipayClient对象(包含公钥,给支付宝作验签确保是哪个用户的余额)操作,返回boolean类型代表退款是否成功
@RestController
@RequestMapping("/alipay")
public class AlipayController {
    @Autowired
    private AlipayClient alipayClient;
    @Autowired
    private AlipayProperties alipayProperties;

    @RequestMapping("/payOnline")
    Result<String> payOnline(@RequestBody PayVo payVo) throws AlipayApiException {
        //设置请求参数
        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
        alipayRequest.setReturnUrl(payVo.getReturnUrl());
        alipayRequest.setNotifyUrl(payVo.getNotifyUrl());

        //商户订单号,商户网站订单系统中唯一订单号,必填
        String out_trade_no = payVo.getOutTradeNo();
        //付款金额,必填
        String total_amount = payVo.getTotalAmount();
        //订单名称,必填
        String subject = payVo.getSubject();
        //商品描述,可空
        String body = payVo.getBody();

        alipayRequest.setBizContent("{\"out_trade_no\":\"" + out_trade_no + "\","
                + "\"total_amount\":\"" + total_amount + "\","
                + "\"subject\":\"" + subject + "\","
                + "\"body\":\"" + body + "\","
                + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");

        String result = alipayClient.pageExecute(alipayRequest).getBody();
        return Result.success(result);
    }

    @RequestMapping("/rsaCheck")
    Result<Boolean> rsaCheck(@RequestBody Map<String, String> params) throws AlipayApiException {
        boolean signVerified = AlipaySignature.rsaCheckV1(params,
                alipayProperties.getAlipayPublicKey(),
                alipayProperties.getCharset(),
                alipayProperties.getSignType()); //调用SDK验证签名
        return Result.success(signVerified);
    }

    @RequestMapping("/refundOnline")
    public Result<Boolean> refundOnline(@RequestBody RefundVo refundVo) throws AlipayApiException {

        //设置请求参数
        AlipayTradeRefundRequest alipayRequest = new AlipayTradeRefundRequest();

        //商户订单号,商户网站订单系统中唯一订单号
        String out_trade_no = refundVo.getOutTradeNo();
        //支付宝交易号
        String trade_no = "";
        //请二选一设置
        //需要退款的金额,该金额不能大于订单金额,必填
        String refund_amount = refundVo.getRefundAmount();
        //退款的原因说明
        String refund_reason = refundVo.getRefundReason();
        //标识一次退款请求,同一笔交易多次退款需要保证唯一,如需部分退款,则此参数必传
        String out_request_no = refundVo.getOutTradeNo();

        alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\","
                + "\"trade_no\":\""+ trade_no +"\","
                + "\"refund_amount\":\""+ refund_amount +"\","
                + "\"refund_reason\":\""+ refund_reason +"\","
                + "\"out_request_no\":\""+ out_request_no +"\"}");

        //请求
        AlipayTradeRefundResponse alipayTradeRefundResponse = alipayClient.execute(alipayRequest);
        return Result.success(alipayTradeRefundResponse.isSuccess());
    }
}

所对应的封装对象

PayVo支付接口参数对象

  • 用于传递给支付接口payOnline的参数对象
@Setter@Getter
public class PayVo {
    private String outTradeNo;//订单编号
    private String totalAmount; //付款金额,必填
    private String subject; //订单名称,必填
    private String body;//商品描述,可空
    private String returnUrl;//同步回调地址
    private String notifyUrl; //异步回调地址
}

RefundVo退款接口参数对象

@Setter@Getter
public class RefundVo implements Serializable {
    private String outTradeNo;//交易订单号
    private String refundAmount;//退款金额
    private String refundReason;//退款原因
}

Result返回封装对象

@Setter
@Getter
public class Result<T> implements Serializable {
    public static final int SUCCESS_CODE = 200;//成功码.
    public static final String SUCCESS_MESSAGE = "操作成功";//成功信息.
    public static final int ERROR_CODE = 500000;//错误码.
    public static final String ERROR_MESSAGE = "系统异常";//错误信息.
    private int code;
    private String msg;
    private T data;
    public Result(){}
    private Result(int code, String msg, T data){
        this.code = code;
        this.msg = msg;
        this.data = data;
    }
    public static <T> Result<T> success(T data){
        return new Result(SUCCESS_CODE,SUCCESS_MESSAGE,data);
    }
    public static <T> Result<T> success(String msg, T data){
        return new Result(SUCCESS_CODE,msg,data);
    }
    public static Result error(CodeMsg codeMsg){
        return new Result(codeMsg.getCode(),codeMsg.getMsg(),null);
    }
    public static Result defaultError(){
        return new Result(ERROR_CODE,ERROR_MESSAGE,null);
    }
    public boolean hasError(){
        //状态吗!=200 说明有错误.
        return this.code!=SUCCESS_CODE;
    }

}

同步和异步回调接口url

  • 这里演示定义同步和异步回调接口,是在另一个服务中定义的(可做参考)
  • 先注入yml配置类中所定义的同步回调所要显示的页面url路径
  • 在回调接口内进行验签判断,确保是支付宝发来的请求,避免中途被篡改了数据
 @Value("${pay.frontEndPayUrl}")
    private String frontEndPayUrl;

同步回调接口

    /**
     * 同步回调 显示数据 让他重新跳转到订单详情界面
     */
    @RequestMapping("/return_url")
    public void returnUrl(HttpServletResponse response, @RequestParam Map<String, String> params) throws IOException {
        System.out.println("同步回调");
        String orderNo = params.get("out_trade_no");
//            验签操作
        Result<Boolean> result = payFeignApi.rsaCheck(params);
        if (result.getData()) {
            response.sendRedirect(frontEndPayUrl + orderNo);
        } else {
            response.sendRedirect("localhost/50x.html");
        }
      response.sendRedirect(frontEndPayUrl + orderNo);
    }

异步回调接口

 /**
     * 异步回调
     */
    @RequestMapping("/notify_url")
    public void notify_url(@RequestParam Map<String, String> params, HttpServletResponse response) throws IOException {
        System.out.println("异步回调" + new Date());
        PrintWriter out = response.getWriter();

        Result<Boolean> result = payFeignApi.rsaCheck(params);
        if (result != null || !result.hasError()) {
            if (result.getData()) {
//                修改订单状态
                String orderNo = params.get("out_trade_no");
                orderInfoService.changePayStatus(orderNo);
                out.println("success");
            } else {
                out.println("fail");
            }
        } else {
            out.println("fail");
        }
    }
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
springcloud-netflix是一个基于Spring Cloud的微服务框架。它提供了一系列工具和组件来简化开发和管理分布式系统的任务。其中包括Eureka、Feign和Zuul等组件。 在搭建springcloud-netflix项目时,需要创建父工程和子工程。父工程是springcloud-netflix-parent,子工程可以是springcloud-netflix-eureka、springcloud-netflix-service-pay等。每个子工程都需要在pom.xml文件中导入相应的依赖。 对于springcloud-netflix-eureka,需要导入spring-cloud-starter-netflix-eureka-server和spring-cloud-starter-netflix-eureka-client等依赖。此外,还需要配置相关的类。 对于springcloud-netflix-service-pay,需要导入spring-cloud-starter-netflix-eureka-client、spring-boot-starter-web和spring-cloud-starter-openfeign等依赖。同样,也需要配置相关的类。 对于Zuul,它是一个API Gateway服务器,提供了动态路由、监控、弹性和安全等边缘服务的框架。在搭建Zuul时,需要导入spring-cloud-starter-netflix-eureka-client、spring-boot-starter-web和spring-cloud-starter-netflix-zuul等依赖。同时,需要配置开启Zuul。 总之,springcloud-netflix是一个基于Spring Cloud的微服务框架,包括了Eureka、Feign和Zuul等组件,可以帮助简化开发和管理分布式系统的任务。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [SpringCloudNetflix](https://blog.csdn.net/Exist_W/article/details/131867868)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值