支付宝微信支付服务端项目构建

支付宝微信支付服务端项目构建

添加pom依赖

在pom中添加一下信息

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>cn.org.pay.tools</groupId>
    <artifactId>pay_tools_server</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.2</version>
    </parent>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>


    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
            <version>2.3.4.RELEASE</version>
        </dependency>

        <!--微信支付sdk-->
        <dependency>
            <groupId>com.github.binarywang</groupId>
            <artifactId>weixin-java-pay</artifactId>
            <version>4.1.0</version>
        </dependency>
        <!--支付宝支付sdk-->
        <dependency>
            <groupId>com.alipay.sdk</groupId>
            <artifactId>alipay-sdk-java</artifactId>
            <version>4.13.70.ALL</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

</project>

在项目src.main.java目录下新增包路径cn.org.pay.tools
在tool包下,新建java 类 PayToolsApplication,并编写如下代码:

@SpringBootApplication
public class PayToolsApplication {

    public static void main(String[] args) {
        SpringApplication.run(PayToolsApplication.class);
    }
}

新建controller包,新建PayToolsIndexController,编写如下代码

@RestController
public class PayToolsIndexController {

    @GetMapping("/index")
    public String index() {
        return "hello payToolsIndex";
    }

}

PayToolsApplication中允许代码,可以看到一下信息输出:
image
项目启动成功。
在浏览器中输入127.0.0.1:8080/index可以看到hello payToolsIndex输出,
项目配置成功。

配置微信支付服务

打开微信开发平台,统一下单接口
必要参数:

  • 商品描述
  • 商户订单号
  • 总金额
  • 终端IP
  • 通知地址
  • 交易类型

我们使用weixin-java-pay可以快速创建下单请求,获取预支付交易会话标识等信息。

改造我们的工程

创建config配置包,在包中创建WxPayPropertiesWxPayConfiguration两个配置类:

WxPayProperties 代码如下:

@ConfigurationProperties(prefix = "wx.pay")
public class WxPayProperties {
    /**
     * 设置微信公众号或者小程序等的appId
     */
    private String appId;

    /**
     * 微信支付商户号
     */
    private String mchId;

    /**
     * 微信支付商户密钥
     */
    private String mchKey;

    /**
     * apiclient_cert.p12文件的绝对路径,或者如果放在项目中,请以classpath:开头指定
     */
    private String keyPath;
    /**
     * 回调URL
     */
    private String notifyUrl;

该信息主要配置微信支付相应参数和回调地址等信息。

WxPayConfiguration 类:

/**
 * 微信支付配置类
 */
@Configuration
@ConditionalOnClass(WxPayService.class)
@EnableConfigurationProperties(WxPayProperties.class)
public class WxPayConfiguration {

    private final WxPayProperties properties;

    @Autowired
    public WxPayConfiguration(WxPayProperties properties) {
        this.properties = properties;
    }

    @Bean
    @ConditionalOnMissingBean
    public WxPayService wxService() {
        WxPayConfig payConfig = new WxPayConfig();
        payConfig.setAppId(StringUtils.trimToNull(this.properties.getAppId()));
        payConfig.setMchId(StringUtils.trimToNull(this.properties.getMchId()));
        payConfig.setMchKey(StringUtils.trimToNull(this.properties.getMchKey()));
        payConfig.setKeyPath(StringUtils.trimToNull(this.properties.getKeyPath()));
        // 可以指定是否使用沙箱环境
        payConfig.setUseSandboxEnv(false);
        WxPayService wxPayService = new WxPayServiceImpl();
        wxPayService.setConfig(payConfig);
        return wxPayService;
    }

}

该类配置WxPayService实现类,通过配置,我们可以直接在Controller 中获取WxPayService的实例对象,进行调用。

controller包中创建WeCharPayController类,

代码如下:

/**
 * 微信支付请求服务端控制器
 */
@Slf4j
@RestController
public class WeCharPayController {
    @Resource
    private WxPayService wxPayService;
    @Resource
    private WxPayProperties wxPayProperties;

    @PostMapping("/getWeCharPay")
    public WxPayAppOrderResult weChatPay(@RequestBody Map<String, String> data) {
        try {
            WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
            request.setBody(data.get("orderName"));
            request.setOutTradeNo(data.get("getOrderNo"));
            request.setFeeType("CNY");
            request.setTotalFee(Integer.valueOf(data.get("price")));//单位分
            request.setSpbillCreateIp("127.0.0.1");
            request.setNotifyUrl(wxPayProperties.getNotifyUrl());
            request.setSignType(WxPayConstants.SignType.MD5);
            request.setTradeType(WxPayConstants.TradeType.APP);
            log.info("WxPayUnifiedOrderRequest request is {}", request);
            WxPayAppOrderResult wxPayAppOrderResult = wxPayService.createOrder(request);
            log.info("封装返回参数:" + wxPayAppOrderResult.toString());
            return wxPayAppOrderResult;
        } catch (Exception e) {
            log.error("微信支付失败!订单号:" + data.get("getOrderNo") + ",原因:" + e.getMessage());
        }
        return null;
    }
}

增加配置信息:
resources资源文件下创建application.yml文件,文件增加以下信息:


wx:
  pay:
    appId: xxxx #微信公众号或者小程序等的appid
    mchId: xxxx #微信支付商户号
    mchKey: xxxxx #微信支付商户密钥
    keyPath: /usr/dev/tomcat8/webapps/cert/apiclient_cert.p12
    notifyUrl : xxxx

重新启动工程,测试预支付请求是否OK;该接口为Post请求类型,测试时候使用PostMan或者其他客户端测试工具。

{
    "orderName":"购买mbp16G1T",
    "getOrderNo":"DJ-12345654321",
    "price":"1"
}

可以看到我们已经获取了预支付ID
image

微信支付回调接口

WeCharPayController类中创建微信支付回调接口,增加以下信息

    @RequestMapping("/callBack")
    public String weChatPayCallBack(@RequestBody String notifyResult) {
        log.info("weChatPayCallBack notifyResult is {}", notifyResult);
        try {
            final WxPayOrderNotifyResult wxPayOrderNotifyResult = wxPayService.parseOrderNotifyResult(notifyResult);
            log.info("weChatPayCallBack data is {}", JSON.toJSONString(wxPayOrderNotifyResult));
            //这里是存储我们发起支付时订单号的信息,所以取出来
            
            return WxPayNotifyResponse.success("回调成功!");
        } catch (WxPayException e) {
            e.printStackTrace();
            log.error("weChatPayCallBack is fail !", e);
            return WxPayNotifyResponse.fail("回调有误!");
        }
    }

OK,到此微信支付服务端已经OK。是不是很简单呢。

支付宝服务端构建

我们首先看下支付宝对接的官方文档
我们这里主要对接了app支付接口2.0,同样我们分析下这个接口的必填项。

  • total_amount 订单金额
  • subject 订单标题
  • out_trade_no 商户订单号

其他信息都是可选参数。

我们开始编写代码。

创建配置对象

config包中,我们创建支付宝支付的配置类AlipayConfigAliPayConfiguration;

AlipayConfig 配置类内容如下:

/**
 * 支付宝支付配置类
 */
@Data
@ConfigurationProperties(prefix = "alipay.pay")
public class AlipayConfig {
    /**
     * APPID
     */
    public String appId;
    /**
     * 私钥存储路径
     */
    @JSONField(serialize = false)
    public String privateKeyPath;
    /**
     * 应用私钥
     */
    @JSONField(serialize = false)
    public String privateKey;
    /**
     * 服务器异步回调地址,必须外网可以正常访问
     */
    public String notifyUrl;
    /**
     * 支付宝同步回调地址,必须外网可以正常访问
     */
    public String returnUrl;
    /**
     * 请求网关地址(这里用的是沙箱环境的支付测试接口)
     */
    public String gateway = "https://openapi.alipaydev.com/gateway.do";
    /**
     * 应用证书
     */
    public String appCertPath;
    /**
     * 支付宝证书
     */
    public String alipayCertPath;
    /**
     * 支付宝根证书路径
     */
    public String alipayRootCertPath;

    public String charset = "UTF-8";
    // 返回格式
    public String format = "json";
    // 日志记录目录
    public String logPath = "/log";
    // RSA2
    public String signType = "RSA2";
}

该类的主要作用是从配置文件中读取相应的配置信息。

配置文件信息如下:

alipay:
  pay:
    appId: 商户编号
    notifyUrl: aliPayCallBack
    returnUrl: callBack
    gateway: https://openapi.alipaydev.com/gateway.do
    appCertPath: /支付宝开放平台开发助手/CSR/appCertPublicKey_2021002150657287.crt
    alipayCertPath: /支付宝开放平台开发助手/CSR/alipayCertPublicKey_RSA2.crt
    alipayRootCertPath: /支付宝开放平台开发助手/CSR/alipayRootCert.crt
    privateKeyPath: privateKey路径

AliPayConfiguration 代码如下:

@Slf4j
@Configuration
@EnableConfigurationProperties(AlipayConfig.class)
public class AliPayConfiguration {

    private final AlipayConfig alipayConfig;

    @Autowired
    public AliPayConfiguration(AlipayConfig alipayConfig) {
        this.alipayConfig = alipayConfig;
    }

    @Bean
    public AlipayConfig alipayConfig() {
        return alipayConfig;
    }

    @Bean
    public AlipayClient alipayClient() throws AlipayApiException {
        log.info("AlipayConfig is {}", JSON.toJSONString(alipayConfig));
        //构造client
        CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
        //设置网关地址
        certAlipayRequest.setServerUrl(alipayConfig.getGateway());
        //设置应用Id
        certAlipayRequest.setAppId(alipayConfig.getAppId());
        //设置应用私钥
        certAlipayRequest.setPrivateKey(alipayConfig.getPrivateKey());
        //设置请求格式,固定值json
        certAlipayRequest.setFormat(alipayConfig.getFormat());
        //设置字符集
        certAlipayRequest.setCharset(alipayConfig.getCharset());
        //设置签名类型
        certAlipayRequest.setSignType(alipayConfig.getSignType());
        //设置应用公钥证书路径
        certAlipayRequest.setCertPath(alipayConfig.getAppCertPath());
        //设置支付宝公钥证书路径
        certAlipayRequest.setAlipayPublicCertPath(alipayConfig.getAlipayCertPath());
        //设置支付宝根证书路径
        certAlipayRequest.setRootCertPath(alipayConfig.getAlipayRootCertPath());
        return new DefaultAlipayClient(certAlipayRequest);
    }
}

初始化支付宝支付客户端对象,供后面我们直接调用。

配置类创建完成后,编写Controller;

@Slf4j
@RestController
public class AlipayController {
    @Resource
    private AlipayConfig alipayConfig;
    @Resource
    private AlipayClient alipayClient;

    @PostMapping("/alipay")
    public String aliPay(@RequestBody Map<String, String> data) throws AlipayApiException {
        log.info("alipay request is {}", JSON.toJSONString(data));
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        Map<String, String> map = new HashMap<>();
        map.put("total_amount", data.get("price"));
        map.put("subject", data.get("orderName"));
        map.put("out_trade_no", data.get("getOrderNo"));
        request.setNotifyUrl(alipayConfig.getNotifyUrl());
        request.setBizContent(JSON.toJSONString(map));
        AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
        if (response.isSuccess()) {
            log.info("response.getBody() is {}", response.getBody());
            return response.getBody();
        } else {
            log.error("aliPay is error,[{}]", JSON.toJSONString(request));
            return null;
        }
    }
    
     @RequestMapping("/aliPayCallBack")
    public String aliPayCallBack(HttpServletRequest request) throws AlipayApiException {
        //获取支付宝POST过来反馈信息
        Map<String, String> params = new HashMap<>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iterator = requestParams.keySet().iterator(); iterator.hasNext(); ) {
            String name = iterator.next();
            String[] values = requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            params.put(name, valueStr);
        }
        log.info("aliPayCallBack param is {}", JSON.toJSONString(params));
        boolean flag = AlipaySignature.rsaCertCheckV1(params,
                alipayConfig.getAlipayCertPath(), alipayConfig.getCharset(), alipayConfig.getSignType());
        if (flag) {
            //做我们需要做的操作。
            return "success";
        }
        return "fail";
    }

}

和微信支付请求相同,这里不演示附加信息。

通过客户端PostMan发送支付请求,可以看到正常返回请求字符串。支付宝服务端研发完成。

image

更多内容请查看 Julywhj的博客期待您的光顾。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Julywhj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值