iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > PHP编程 >PHP 微信支付V3版本SDK使用整理汇总
  • 772
分享到

PHP 微信支付V3版本SDK使用整理汇总

php微信开发语言 2023-10-20 12:10:15 772人浏览 薄情痞子
摘要

最近项目中需要使用微信支付,决定使用微信官方V3 SDK版本接口 项目支持的环境如下: Guzzle 7.0,PHP >= 7.2.5Guzzle 6.5,PHP >= 7.1.2 安装 compos

最近项目中需要使用微信支付,决定使用微信官方V3 SDK版本接口

项目支持的环境如下:

  • Guzzle 7.0,PHP >= 7.2.5
  • Guzzle 6.5,PHP >= 7.1.2

安装

composer require wechatpay/wechatpay

开始

ℹ️ 以下是 微信支付 API v3 的指引。如果你是 api v2 的使用者,请看 README_APIv2

概念

  • 商户 API 证书,是用来证实商户身份的。证书中包含商户号、证书序列号、证书有效期等信息,由证书授权机构(Certificate Authority ,简称 CA)签发,以防证书被伪造或篡改。详情见 什么是商户API证书?如何获取商户API证书?

  • 商户 API 私钥。你申请商户 API 证书时,会生成商户私钥,并保存在本地证书文件夹的文件 apiclient_key.pem 中。为了证明 API 请求是由你发送的,你应使用商户 API 私钥对请求进行签名。

⚠️ 不要把私钥文件暴露在公共场合,如上传到 GitHub,写在 App 代码中等。

  • 微信支付平台证书。微信支付平台证书是指:由微信支付负责申请,包含微信支付平台标识、公钥信息的证书。你需使用微信支付平台证书中的公钥验证 API 应答和回调通知的签名。

ℹ️ 你需要先手工 下载平台证书 才能使用 SDK 发起请求。

  • 证书序列号。每个证书都有一个由 CA 颁发的唯一编号,即证书序列号。

获取微信支付平台证书(首次)

官方的

按官方文档使用各种报错,估计是因为有其他的库引起的

composer exec CertificateDownloader.PHP -- -k ${apiV3key} -m ${mchId} -f ${mchPrivateKeyFilePath} -s ${mchSerialNo} -o ${outputFilePath}
接口调用
    public static function certificates()    {        $wxPayConfig = config('wx_pay_config');        $api_v3_key = $wxPayConfig['api_v3_key'] ?? '';     // 商户号        $result = self::wx_curl_query('v3/certificates','GET');        $result = JSON_decode($result, true);        $ciphertext = $result['data'][0]['encrypt_certificate']['ciphertext'] ?? '';        $nonce = $result['data'][0]['encrypt_certificate']['nonce'] ?? '';        $associated_data = $result['data'][0]['encrypt_certificate']['associated_data'] ?? '';        $decryptedMsg = AesGCm::decrypt($ciphertext, $api_v3_key, $nonce, $associated_data);        $result['decryptedMsg'] = ($decryptedMsg); //解密后的内容,就是证书内容        dump($result);    }    //get请求    public static function wx_curl_query($urlV3 = '', $Http_method = 'POST', $body = '')    {        $url = 'https://api.mch.weixin.qq.com/' . $urlV3;        $config = config('wx_pay_config');;        $mchId = $config['mchid'] ?? ''; // 商户ID        $serial_no = $config['cert_serial'] ?? ''; // 证书序列号        $certPath = 'file://' . ROOT_PATH . 'cert/wx/' . $mchId;        // 从本地文件中加载「商户API私钥」,「商户API私钥」会用来生成请求的签名        $merchantPrivateKeyFilePath = $certPath . '/apiclient_key.pem';        $mch_private_key = openssl_get_privatekey(file_get_contents($merchantPrivateKeyFilePath));;//私钥        if(is_array($body)){            $body = json_encode($body); // 接口参数        }        // 生成token 验签        $timestamp = time();//时间戳        $nonce = FORMatter::nonce(32);//随机串        $url_parts = parse_url($url);        $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));        //构造签名串        $message = $http_method . "\n" .            $canonical_url . "\n" .            $timestamp . "\n" .            $nonce . "\n" .            $body . "\n";//报文主体        //计算签名值        openssl_sign($message, $raw_sign, $mch_private_key, 'sha256WithRSAEncryption');        $sign = base64_encode($raw_sign);        //设置HTTP头        $token = sprintf('WECHATPAY2-SHA256-RSA2048 mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',            $mchId, $nonce, $timestamp, $serial_no, $sign);        $headers = [            'Accept: application/json',            'User-Agent: *    static function getCert()    {        // 设置参数        [$instance, $wxPayConfig] = self::init();        $api_v3_key = $wxPayConfig['api_v3_key'] ?? '';   // 「商户API证书」的「证书序列号」        // 发送请求        $resp = $instance->chain('v3/certificates')->get(//            ['debug' => true] // 调试模式,https://docs.guzzlephp.org/en/stable/request-options.html#debug        );        $result = json_decode($resp->getBody(), true);        $ciphertext = $result['data'][0]['encrypt_certificate']['ciphertext'] ?? '';        $nonce = $result['data'][0]['encrypt_certificate']['nonce'] ?? '';        $associated_data = $result['data'][0]['encrypt_certificate']['associated_data'] ?? '';        $decryptedMsg = AesGcm::decrypt($ciphertext, $api_v3_key, $nonce, $associated_data);        $result['ciphertext_msg'] = $decryptedMsg;        dump($result);    }  static $merchantPrivateKeyInstance;   // 从本地文件中加载「商户API私钥」,「商户API私钥」会用来生成请求的签名     public static function init()    {        // 设置参数        $wxPayConfig = config('wx_pay_config');        $mchId = $wxPayConfig['mchid'] ?? '';     // 商户号        $serial = $wxPayConfig['cert_serial'] ?? '';   // 「商户API证书」的「证书序列号」        $certPath = 'file://' . ROOT_PATH . 'cert/wx/' . $mchId;        // 从本地文件中加载「商户API私钥」,「商户API私钥」会用来生成请求的签名        $merchantPrivateKeyFilePath = $certPath . '/apiclient_key.pem';        self::$merchantPrivateKeyInstance = $merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);        // 从本地文件中加载「微信支付平台证书」,用来验证微信支付应答的签名        $platformCertificateFilePath = $certPath . '/cert.pem';        $platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);        // 从「微信支付平台证书」中获取「证书序列号」        $platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateFilePath);        // 构造一个 APIv3 客户端实例        $instance = Builder::factory([            'mchid' => $mchId,            'serial' => $serial,            'privateKey' => $merchantPrivateKeyInstance,            'certs' => [                $platformCertificateSerial => $platformPublicKeyInstance,            ],        ]);        return [$instance, $wxPayConfig];    }

app支付

    static function pay($payData = [], $notifyUrl = '')    {        $notifyUrl = $notifyUrl ?? (config('host_api') . '/v1/notify/wx_notify');        [$instance, $wxPayConfig] = self::init(); // 赋值给变量        $merchantId = $wxPayConfig['mchid'] ?? '';     // 商户号        $appid = $wxPayConfig['appid'] ?? '';     // 商户号        // 调用下单        $payJsonData = [            'mchid' => $merchantId,            'appid' => $appid,            'out_trade_no' => $payData['out_trade_no'] ?? 0,            'description' => $payData['description'] ?? 0,            'notify_url' => $notifyUrl,            'amount' => [                'total' => $payData['money'] ?? 0,  // 分                'currency' => 'CNY'            ],        ];        try {            $resp = $instance                ->chain('v3/pay/transactions/app')                ->post(['json' => $payJsonData]);            if ($resp->getStatusCode() == 200) {                $wo = json_decode($resp->getBody(), true); //prepay_id                $params = [                    'partnerId' => $appid,                    'timeStamp' => (string)Formatter::timestamp(),                    'nonceStr' => Formatter::nonce(),                    'prepayId' => $wo["prepay_id"],                ];                $params += ['sign' => Rsa::sign(                    Formatter::joinedByLineFeed(...array_values($params)),                    self::$merchantPrivateKeyInstance                )];                return [1, $params];            } else {                return [0, '微信支付失败'];            }        } catch (\Exception $e) {            $code = $e->getCode();            $data = '';            // 进行错误处理            if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {                $r = $e->getResponse();                $data = json_decode($r->getBody(), true);                LogHelperUtil::outLog("wx_pay_error", $data, "wx_pay");            }        }        return [$code, $data];        // end    }

app回调

    static function notify($header, $inBody)    {        $inWechatpaySignature = $header['wechatpay-signature'];        $inWechatpayTimestamp = $header['wechatpay-timestamp'];        $inWechatpaySerial = $header['wechatpay-serial'];        $inWechatpayNonce = $header['wechatpay-nonce'];        if (!$inWechatpaySignature or !$inWechatpayTimestamp or !$inWechatpaySerial or !$inWechatpayNonce) {            header("Location:/404.html");            exit;        }        $wxPayConfig = config('wx_pay_config');        $merchantId = $wxPayConfig['mchid'] ?? '';     // 商户号        $apiv3Key = $wxPayConfig['api_v3_key'] ?? '';// 在商户平台上设置的APIv3密钥        $certPath = 'file://' . ROOT_PATH . 'cert/wx/' . $merchantId;        // 从本地文件中加载「微信支付平台证书」,用来验证微信支付应答的签名        $platformCertificateFilePath = $certPath . '/cert.pem';        // 根据通知的平台证书序列号,查询本地平台证书文件,这里是自己生成的证书        $platformPublicKeyInstance = Rsa::from(file_get_contents($platformCertificateFilePath), Rsa::KEY_TYPE_PUBLIC);        // 检查通知时间偏移量,允许5分钟之内的偏移        $timeOffsetStatus = 300 >= abs(Formatter::timestamp() - (int)$inWechatpayTimestamp);        $verifiedStatus = Rsa::verify(        // 构造验签名串            Formatter::joinedByLineFeed($inWechatpayTimestamp, $inWechatpayNonce, $inBody),            $inWechatpaySignature,            $platformPublicKeyInstance        );        if ($timeOffsetStatus && $verifiedStatus) {            // 转换通知的JSON文本消息为PHP Array数组            $inBodyArray = (array)json_decode($inBody, true);            // 使用PHP7的数据解构语法,从Array中解构并赋值变量            ['resource' => [                'ciphertext' => $ciphertext,                'nonce' => $nonce,                'associated_data' => $aad            ]] = $inBodyArray;            // 加密文本消息解密            $inBodyResource = AesGcm::decrypt($ciphertext, $apiv3Key, $nonce, $aad);            // 把解密后的文本转换为PHP Array数组            return (array)json_decode($inBodyResource, true);        } else {            return ['trade_state' => 'FAIL'];        }    }

退款

        static function refundOrder($orderSn, $tradeNo, $refundMoney)    {        [$instance, $wxPayConfig] = self::init();        try {            $response = $instance                ->chain('v3/refund/domestic/refunds')                ->post([                    'json' => [                        'transaction_id' => $tradeNo,                        'out_refund_no' => $orderSn,                        'amount' => ['refund' => $refundMoney,'total' => $refundMoney,'currency' => 'CNY',                        ],                    ],                ]);            // 正常逻辑回调处理            $code = $response->getStatusCode();            $response = json_decode($response->getBody(), true);            $status = $response['status'] ?? '';            if ($code != 200) {                DingDingUtil::sendDingtalkText("微信退款未知原因!订单号:{$orderSn} 错误原因:" . json_encode($response));            }            return [1, $response];        } catch (\Exception $e) {            // 异常错误处理            if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {                $r = $e->getResponse();                $code = $r->getStatusCode();                $response = json_decode($r->getBody(), true);                $subCode = $response['code'] ?? '';                $subMsg = $response['message'] ?? '';                $listErrorCode = [                    'NOT_ENOUGH',  //余额不足',                    'MCH_NOT_EXISTS',  //MCHID不存在',                    'NO_AUTH',  //没有退款权限',                ];                if (in_array($subCode, $listErrorCode)) {                    DingDingUtil::sendDingtalkText("微信退款失败!\n订单号:{$orderSn} \n错误原因:" . $subMsg);                }                return [$code, $response];            }        }        return [0, '退款失败'];    }
封装PayWxUtil文件
namespace pay;use util\DingDingUtil;use util\LogHelperUtil;use WeChatPay\Builder;use WeChatPay\ClientJsonTrait;use WeChatPay\Crypto\AesGcm;use WeChatPay\Crypto\Rsa;use WeChatPay\Formatter;use WeChatPay\Util\PemUtil;class PayWxUtil{    static $merchantPrivateKeyInstance;   // 从本地文件中加载「商户API私钥」,「商户API私钥」会用来生成请求的签名        public static function init()    {        // 设置参数        $wxPayConfig = config('wx_pay_config');        $mchId = $wxPayConfig['mchid'] ?? '';     // 商户号        $serial = $wxPayConfig['cert_serial'] ?? '';   // 「商户API证书」的「证书序列号」        $certPath = 'file://' . ROOT_PATH . 'cert/wx/' . $mchId;        // 从本地文件中加载「商户API私钥」,「商户API私钥」会用来生成请求的签名        $merchantPrivateKeyFilePath = $certPath . '/apiclient_key.pem';        self::$merchantPrivateKeyInstance = $merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);        // 从本地文件中加载「微信支付平台证书」,用来验证微信支付应答的签名        $platformCertificateFilePath = $certPath . '/cert.pem';        $platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);        // 从「微信支付平台证书」中获取「证书序列号」        $platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateFilePath);        // 构造一个 APIv3 客户端实例        $instance = Builder::factory([            'mchid' => $mchId,            'serial' => $serial,            'privateKey' => $merchantPrivateKeyInstance,            'certs' => [                $platformCertificateSerial => $platformPublicKeyInstance,            ],        ]);        return [$instance, $wxPayConfig];    }        static function pay($payData = [], $notifyUrl = '')    {        $notifyUrl = $notifyUrl ?? (config('host_api') . '/v1/notify/wx_notify');        [$instance, $wxPayConfig] = self::init(); // 赋值给变量        $merchantId = $wxPayConfig['mchid'] ?? '';     // 商户号        $appid = $wxPayConfig['appid'] ?? '';     // 商户号        // 调用下单        $payJsonData = [            'mchid' => $merchantId,            'appid' => $appid,            'out_trade_no' => $payData['out_trade_no'] ?? 0,            'description' => $payData['description'] ?? 0,            'notify_url' => $notifyUrl,            'amount' => [                'total' => $payData['money'] ?? 0,  // 分                'currency' => 'CNY'            ],        ];        try {            $resp = $instance                ->chain('v3/pay/transactions/app')                ->post(['json' => $payJsonData]);            if ($resp->getStatusCode() == 200) {                $wo = json_decode($resp->getBody(), true); //prepay_id                $params = [                    'partnerId' => $appid,                    'timeStamp' => (string)Formatter::timestamp(),                    'nonceStr' => Formatter::nonce(),                    'prepayId' => $wo["prepay_id"],                ];                $params += ['sign' => Rsa::sign(                    Formatter::joinedByLineFeed(...array_values($params)),                    self::$merchantPrivateKeyInstance                )];                return [1, $params];            } else {                return [0, '微信支付失败'];            }        } catch (\Exception $e) {            $code = $e->getCode();            $data = '';            // 进行错误处理            if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {                $r = $e->getResponse();                $data = json_decode($r->getBody(), true);                LogHelperUtil::outLog("wx_pay_error", $data, "wx_pay");            }        }        return [$code, $data];        // end    }        static function refundOrder($orderSn, $tradeNo, $refundMoney)    {        [$instance, $wxPayConfig] = self::init();        try {            $response = $instance                ->chain('v3/refund/domestic/refunds')                ->post([                    'json' => [                        'transaction_id' => $tradeNo,                        'out_refund_no' => $orderSn,                        'amount' => ['refund' => $refundMoney,'total' => $refundMoney,'currency' => 'CNY',                        ],                    ],                ]);            // 正常逻辑回调处理            $code = $response->getStatusCode();            $response = json_decode($response->getBody(), true);            $status = $response['status'] ?? '';            if ($code != 200) {                DingDingUtil::sendDingtalkText("微信退款未知原因!订单号:{$orderSn} 错误原因:" . json_encode($response));            }            return [1, $response];        } catch (\Exception $e) {            // 异常错误处理            if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {                $r = $e->getResponse();                $code = $r->getStatusCode();                $response = json_decode($r->getBody(), true);                $subCode = $response['code'] ?? '';                $subMsg = $response['message'] ?? '';                $listErrorCode = [                    'NOT_ENOUGH',  //余额不足',                    'MCH_NOT_EXISTS',  //MCHID不存在',                    'NO_AUTH',  //没有退款权限',                ];                if (in_array($subCode, $listErrorCode)) {                    DingDingUtil::sendDingtalkText("微信退款失败!\n订单号:{$orderSn} \n错误原因:" . $subMsg);                }                return [$code, $response];            }        }        return [0, '退款失败'];    }        static function notify($header, $inBody)    {        $inWechatpaySignature = $header['wechatpay-signature'];        $inWechatpayTimestamp = $header['wechatpay-timestamp'];        $inWechatpaySerial = $header['wechatpay-serial'];        $inWechatpayNonce = $header['wechatpay-nonce'];        if (!$inWechatpaySignature or !$inWechatpayTimestamp or !$inWechatpaySerial or !$inWechatpayNonce) {            header("Location:/404.html");            exit;        }        $wxPayConfig = config('wx_pay_config');        $merchantId = $wxPayConfig['mchid'] ?? '';     // 商户号        $apiv3Key = $wxPayConfig['api_v3_key'] ?? '';// 在商户平台上设置的APIv3密钥        $certPath = 'file://' . ROOT_PATH . 'cert/wx/' . $merchantId;        // 从本地文件中加载「微信支付平台证书」,用来验证微信支付应答的签名        $platformCertificateFilePath = $certPath . '/cert.pem';        // 根据通知的平台证书序列号,查询本地平台证书文件,这里是自己生成的证书        $platformPublicKeyInstance = Rsa::from(file_get_contents($platformCertificateFilePath), Rsa::KEY_TYPE_PUBLIC);        // 检查通知时间偏移量,允许5分钟之内的偏移        $timeOffsetStatus = 300 >= abs(Formatter::timestamp() - (int)$inWechatpayTimestamp);        $verifiedStatus = Rsa::verify(        // 构造验签名串            Formatter::joinedByLineFeed($inWechatpayTimestamp, $inWechatpayNonce, $inBody),            $inWechatpaySignature,            $platformPublicKeyInstance        );        if ($timeOffsetStatus && $verifiedStatus) {            // 转换通知的JSON文本消息为PHP Array数组            $inBodyArray = (array)json_decode($inBody, true);            // 使用PHP7的数据解构语法,从Array中解构并赋值变量            ['resource' => [                'ciphertext' => $ciphertext,                'nonce' => $nonce,                'associated_data' => $aad            ]] = $inBodyArray;            // 加密文本消息解密            $inBodyResource = AesGcm::decrypt($ciphertext, $apiv3Key, $nonce, $aad);            // 把解密后的文本转换为PHP Array数组            return (array)json_decode($inBodyResource, true);        } else {            return ['trade_state' => 'FAIL'];        }    }        static function getCert()    {        // 设置参数        [$instance, $wxPayConfig] = self::init();        $api_v3_key = $wxPayConfig['api_v3_key'] ?? '';   // 「商户API证书」的「证书序列号」        // 发送请求        $resp = $instance->chain('v3/certificates')->get(//            ['debug' => true] // 调试模式,https://docs.guzzlephp.org/en/stable/request-options.html#debug        );        $result = json_decode($resp->getBody(), true);        $ciphertext = $result['data'][0]['encrypt_certificate']['ciphertext'] ?? '';        $nonce = $result['data'][0]['encrypt_certificate']['nonce'] ?? '';        $associated_data = $result['data'][0]['encrypt_certificate']['associated_data'] ?? '';        $decryptedMsg = AesGcm::decrypt($ciphertext, $api_v3_key, $nonce, $associated_data);        $result['ciphertext_msg'] = $decryptedMsg;        dump($result);    }        public static function certificates()    {        $wxPayConfig = config('wx_pay_config');        $api_v3_key = $wxPayConfig['api_v3_key'] ?? '';     // 商户号        $result = self::wx_curl_query('v3/certificates','GET');        $result = json_decode($result, true);        $ciphertext = $result['data'][0]['encrypt_certificate']['ciphertext'] ?? '';        $nonce = $result['data'][0]['encrypt_certificate']['nonce'] ?? '';        $associated_data = $result['data'][0]['encrypt_certificate']['associated_data'] ?? '';        $decryptedMsg = AesGcm::decrypt($ciphertext, $api_v3_key, $nonce, $associated_data);        $result['decryptedMsg'] = ($decryptedMsg); //解密后的内容,就是证书内容        dump($result);    }    //get请求    public static function wx_curl_query($urlV3 = '', $http_method = 'POST', $body = '')    {        $url = 'https://api.mch.weixin.qq.com/' . $urlV3;        $config = config('wx_pay_config');;        $mchId = $config['mchid'] ?? ''; // 商户ID        $serial_no = $config['cert_serial'] ?? ''; // 证书序列号        $certPath = 'file://' . ROOT_PATH . 'cert/wx/' . $mchId;        // 从本地文件中加载「商户API私钥」,「商户API私钥」会用来生成请求的签名        $merchantPrivateKeyFilePath = $certPath . '/apiclient_key.pem';        $mch_private_key = openssl_get_privatekey(file_get_contents($merchantPrivateKeyFilePath));;//私钥        if(is_array($body)){            $body = json_encode($body); // 接口参数        }        // 生成token 验签        $timestamp = time();//时间戳        $nonce = Formatter::nonce(32);//随机串        $url_parts = parse_url($url);        $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));        //构造签名串        $message = $http_method . "\n" .            $canonical_url . "\n" .            $timestamp . "\n" .            $nonce . "\n" .            $body . "\n";//报文主体        //计算签名值        openssl_sign($message, $raw_sign, $mch_private_key, 'sha256WithRSAEncryption');        $sign = base64_encode($raw_sign);        //设置HTTP头        $token = sprintf('WECHATPAY2-SHA256-RSA2048 mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',            $mchId, $nonce, $timestamp, $serial_no, $sign);        $headers = [            'Accept: application/json',            'User-Agent: */*',            'Content-Type: application/json; charset=utf-8',            'Authorization: ' . $token,            "Wechatpay-Serial:{$serial_no}"        ];        $info = curl_init();        curl_setopt($info, CURLOPT_RETURNTRANSFER, true);        curl_setopt($info, CURLOPT_HEADER, 0);        curl_setopt($info, CURLOPT_NOBODY, 0);        curl_setopt($info, CURLOPT_SSL_VERIFYPEER, false);        curl_setopt($info, CURLOPT_SSL_VERIFYHOST, false);        if ($http_method == 'POST') {            curl_setopt($info, CURLOPT_POST, 1);            curl_setopt($info, CURLOPT_POSTFIELDS, json_encode($body));        }        //设置header头        curl_setopt($info, CURLOPT_HTTPHEADER, $headers);        curl_setopt($info, CURLOPT_URL, $url);        $output = curl_exec($info);        curl_close($info);        return $output;    }}

服务端SDK

来源地址:https://blog.csdn.net/qq_23564667/article/details/132169681

--结束END--

本文标题: PHP 微信支付V3版本SDK使用整理汇总

本文链接: https://www.lsjlt.com/news/432979.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作