Appearance
第三方集成开发指南
概述
DSPlatform 采用驱动管理器模式集成各种第三方服务,包括支付、短信、文件存储、LBS、打印机等。通过统一的接口和配置管理,实现了第三方服务的可插拔式集成。
技术架构
核心组件
- BaseDriverManager: 驱动管理器基类
- Manager 类: 各种第三方服务的管理器
- Provider 类: 具体的第三方服务实现
- Base Provider: 各服务的基础实现类
目录结构
app/deshang/third_party/
├── base/
│ └── BaseDriverManager.php # 驱动管理器基类
├── trade/ # 支付服务
│ ├── TradeManager.php
│ └── providers/
│ ├── BaseTrade.php
│ ├── Wechat.php
│ └── Alipay.php
├── sms/ # 短信服务
│ ├── SmsManager.php
│ └── providers/
│ ├── BaseSms.php
│ ├── Aliyun.php
│ └── Tencent.php
├── upload/ # 文件上传服务
│ ├── UploadManager.php
│ └── providers/
│ ├── BaseUpload.php
│ ├── Aliyun.php
│ └── Local.php
├── lbs/ # 位置服务
│ ├── LbsManager.php
│ └── providers/
│ ├── BaseLbs.php
│ ├── Baidu.php
│ ├── Gaode.php
│ ├── Tencent.php
│ └── Tianditu.php
├── printer/ # 打印机服务
│ ├── PrinterManager.php
│ └── providers/
│ ├── BasePrinter.php
│ ├── Feie.php
│ ├── Jiabo.php
│ ├── Xinye.php
│ └── Yilian.php
├── express/ # 快递服务
│ ├── ExpressManager.php
│ └── providers/
│ ├── BaseExpress.php
│ ├── Kuaidi100.php
│ └── Kuaidiniao.php
└── waybill/ # 运单服务
└── README.md
驱动管理器基类
BaseDriverManager
php
// app/deshang/base/BaseDriverManager.php
abstract class BaseDriverManager
{
protected $namespace; // 驱动类命名空间
protected $driver; // 当前使用的驱动实例
protected $driverName; // 当前使用的驱动名称
protected $config; // 配置信息
protected $drivers = []; // 缓存的驱动实例
/**
* 构造函数
* @param string $driverName 驱动名称
* @param array $config 驱动配置
*/
public function __construct(string $driverName, array $config = [])
{
$this->driverName = ucfirst(strtolower($driverName)) ?: $this->getDefaultDriverName();
$this->config = $config;
$this->loadDriver();
}
/**
* 获取默认驱动名称
* @return string 默认驱动名称
*/
abstract protected function getDefaultDriverName(): string;
/**
* 加载驱动
*/
protected function loadDriver()
{
if (isset($this->drivers[$this->driverName])) {
$this->driver = $this->drivers[$this->driverName];
return;
}
if (empty($this->namespace)) {
throw new Exception("命名空间未定义");
}
$driverClass = $this->namespace . '\\' . $this->driverName;
if (!class_exists($driverClass)) {
throw new Exception("驱动类 {$driverClass} 不存在");
}
$this->driver = new $driverClass($this->config);
$this->drivers[$this->driverName] = $this->driver;
}
/**
* 动态调用驱动方法
* @param string $method 方法名
* @param array $arguments 参数
* @return mixed
*/
public function __call($method, $arguments)
{
if (!method_exists($this->driver, $method)) {
throw new Exception("方法 {$method} 不存在于驱动 {$this->driverName}");
}
return $this->driver->$method(...$arguments);
}
/**
* 获取当前使用的驱动名称
* @return string 当前使用的驱动名称
*/
public function getDriverName(): string
{
return $this->driverName;
}
}
第三方服务集成
1. 支付服务 (Trade)
TradeManager
php
// app/deshang/third_party/trade/TradeManager.php
class TradeManager extends BaseDriverManager
{
protected $namespace = 'app\deshang\third_party\trade\providers';
protected function getDefaultDriverName(): string
{
return config('trade.default', 'Yansongda');
}
}
微信支付实现
php
// app/deshang/third_party/trade/providers/Wechat.php
class Wechat extends BaseTrade
{
public function __construct(array $config)
{
$wechat_config = [
'wechat' => [
'default' => [
'mch_id' => $config['mch_id'],
'mch_secret_key' => $config['mch_secret_key'],
'mch_secret_cert' => $config['mch_secret_cert_path'],
'mch_public_cert_path' => $config['mch_public_cert_path'],
'notify_url' => $config['notify_url'],
'wechat_public_cert_path' => [
$config['wechat_public_cert_id'] => $config['wechat_public_cert_path'],
],
'mode' => Pay::MODE_NORMAL,
]
],
];
// 根据支付场景设置不同的 app_id
if ($config['trade_scene'] == TradePaymentConfigEnum::SCENE_WECHAT_OFFICIAL) {
$wechat_config['wechat']['default']['mp_app_id'] = $config['app_id'];
}
if ($config['trade_scene'] == TradePaymentConfigEnum::SCENE_WECHAT_MINI) {
$wechat_config['wechat']['default']['mini_app_id'] = $config['app_id'];
}
if ($config['trade_scene'] == TradePaymentConfigEnum::SCENE_APP) {
$wechat_config['wechat']['default']['app_id'] = $config['app_id'];
}
Pay::config($wechat_config);
}
// 小程序支付
public function mini(array $data)
{
$order = [
'out_trade_no' => $data['out_trade_no'],
'description' => $data['subject'],
'amount' => [
'total' => intval($data['total_amount'] * 100),
'currency' => 'CNY',
],
'payer' => [
'openid' => $data['openid'],
],
];
$result = Pay::wechat()->mini($order);
return $this->parseResponse($result);
}
// 扫码支付
public function scan(array $data)
{
$order = [
'out_trade_no' => $data['out_trade_no'],
'description' => $data['subject'],
'amount' => [
'total' => intval($data['total_amount'] * 100),
],
];
$result = Pay::wechat()->scan($order);
return $this->parseResponse($result);
}
// 退款
public function refund(array $data): bool
{
$order = [
'out_trade_no' => $data['out_trade_no'],
'out_refund_no' => $data['out_refund_no'],
'amount' => [
'refund' => intval($data['refund_amount'] * 100),
'total' => intval($data['total_amount'] * 100),
'currency' => 'CNY',
],
];
$result = $this->parseResponse(Pay::wechat()->refund($order));
return $result['status'] == 'SUCCESS' || $result['status'] == 'PROCESSING' ? true : false;
}
// 支付回调
public function callback()
{
$result = Pay::wechat()->callback();
$result = $this->parseResponse($result);
$ciphertext = $result['resource']['ciphertext'];
return [
'status' => 'success',
'buyer_id' => $ciphertext['payer']['openid'],
'seller_id' => $ciphertext['mchid'],
'trade_no' => $ciphertext['transaction_id'],
'out_trade_no' => $ciphertext['out_trade_no'],
'total_amount' => $ciphertext['amount']['total'] / 100,
];
}
// 确认回调
public function confirm()
{
return Pay::wechat()->success();
}
}
使用示例
php
// 创建支付管理器
$tradeManager = new TradeManager('Wechat', $config);
// 小程序支付
$result = $tradeManager->mini([
'out_trade_no' => 'order_123456',
'subject' => '商品购买',
'total_amount' => 100.00,
'openid' => 'user_openid'
]);
// 扫码支付
$result = $tradeManager->scan([
'out_trade_no' => 'order_123456',
'subject' => '商品购买',
'total_amount' => 100.00
]);
// 退款
$result = $tradeManager->refund([
'out_trade_no' => 'order_123456',
'out_refund_no' => 'refund_123456',
'refund_amount' => 50.00,
'total_amount' => 100.00
]);
2. 短信服务 (SMS)
SmsManager
php
// app/deshang/third_party/sms/SmsManager.php
class SmsManager extends BaseDriverManager
{
protected $namespace = 'app\deshang\third_party\sms\providers';
protected function getDefaultDriverName(): string
{
return 'Tencent';
}
}
阿里云短信实现
php
// app/deshang/third_party/sms/providers/Aliyun.php
class Aliyun extends BaseSms
{
protected $config;
public function __construct(array $config)
{
$this->config = $config;
}
/**
* 初始化阿里云客户端
*/
protected function initClient()
{
if (empty($this->config['access_key_id']) || empty($this->config['access_key_secret'])) {
throw new \Exception('阿里云短信配置不完整,缺少AccessKey');
}
$config = new Config([
'type' => 'access_key',
'accessKeyId' => $this->config['access_key_id'],
'accessKeySecret' => $this->config['access_key_secret'],
]);
$config->regionId = isset($this->config['region_id']) ? $this->config['region_id'] : 'cn-hangzhou';
$config->endpoint = 'dysmsapi.aliyuncs.com';
return new Dysmsapi($config);
}
/**
* 发送短信
*/
public function send(string $to, string $templateCode, array|string $templateParam = []): bool
{
$client = $this->initClient();
try {
if (empty($this->config['sign_name'])) {
throw new \Exception('阿里云短信配置不完整,缺少短信签名');
}
$sendSmsRequest = new SendSmsRequest([
'phoneNumbers' => $to,
'signName' => $this->config['sign_name'],
'templateCode' => $templateCode,
]);
if (!empty($templateParam)) {
if (is_array($templateParam)) {
$sendSmsRequest->templateParam = json_encode($templateParam, JSON_UNESCAPED_UNICODE);
} else {
$sendSmsRequest->templateParam = $templateParam;
}
}
$response = $client->sendSms($sendSmsRequest);
if (isset($response->body->Code) && $response->body->Code == 'OK') {
return true;
} else {
$error_msg = isset($response->body->Message) ? $response->body->Message : '未知错误';
return '阿里云短信发送失败:' . $error_msg;
}
} catch (TeaError $e) {
return '阿里云短信发送错误:' . $e->getMessage();
} catch (\Exception $e) {
throw $e;
}
}
}
使用示例
php
// 创建短信管理器
$smsManager = new SmsManager('Aliyun', $config);
// 发送短信
$result = $smsManager->send(
'13800138000',
'SMS_123456789',
['code' => '123456']
);
3. 文件上传服务 (Upload)
UploadManager
php
// app/deshang/third_party/upload/UploadManager.php
class UploadManager extends BaseDriverManager
{
protected $namespace = 'app\deshang\third_party\upload\providers';
protected function getDefaultDriverName(): string
{
return config('upload.default', 'Aliyun');
}
}
阿里云 OSS 实现
php
// app/deshang/third_party/upload/providers/Aliyun.php
class Aliyun extends BaseUpload
{
protected $config;
protected $ossClient;
protected $bucket;
public function __construct(array $config)
{
parent::__construct();
$this->config = $config;
$this->initClient();
}
/**
* 初始化阿里云 OSS 客户端
*/
protected function initClient()
{
if (empty($this->config['access_key_id']) || empty($this->config['access_key_secret'])) {
throw new \Exception('阿里云上传配置不完整,缺少AccessKey');
}
if (empty($this->config['endpoint']) || empty($this->config['bucket'])) {
throw new \Exception('阿里云上传配置不完整,缺少Endpoint或Bucket');
}
$this->ossClient = new OssClient(
$this->config['access_key_id'],
$this->config['access_key_secret'],
$this->config['endpoint']
);
$this->bucket = $this->config['bucket'];
}
/**
* 上传文件到阿里云 OSS
*/
public function upload($dir)
{
if (!$this->file) {
throw new Exception("文件未上传");
}
$this->randomSaveName();
$object = $dir . '/' . $this->save_name;
try {
$this->ossClient->uploadFile($this->bucket, $object, $this->fileInfo['realPath']);
return true;
} catch (OssException $e) {
throw new Exception("文件上传失败: " . $e->getMessage());
}
}
/**
* 删除阿里云 OSS 上的文件
*/
public function delete($path_list)
{
foreach ($path_list as $path) {
try {
$this->ossClient->deleteObject($this->bucket, $path);
} catch (OssException $e) {
throw new Exception("文件删除失败: " . $e->getMessage());
}
}
return true;
}
}
使用示例
php
// 创建上传管理器
$uploadManager = new UploadManager('Aliyun', $config);
// 上传文件
$result = $uploadManager->upload('images');
// 删除文件
$result = $uploadManager->delete(['images/file1.jpg', 'images/file2.jpg']);
4. LBS 位置服务
LbsManager
php
// app/deshang/third_party/lbs/LbsManager.php
class LbsManager extends BaseDriverManager
{
protected $namespace = 'app\deshang\third_party\lbs\providers';
protected function getDefaultDriverName(): string
{
return 'Tencent';
}
}
5. 打印机服务
PrinterManager
php
// app/deshang/third_party/printer/PrinterManager.php
class PrinterManager extends BaseDriverManager
{
protected $namespace = 'app\deshang\third_party\printer\providers';
protected function getDefaultDriverName(): string
{
return 'Feie';
}
}
6. 快递服务
ExpressManager
php
// app/deshang/third_party/express/ExpressManager.php
class ExpressManager extends BaseDriverManager
{
protected $namespace = 'app\deshang\third_party\express\providers';
protected function getDefaultDriverName(): string
{
return 'Kuaidi100';
}
}
依赖库
Composer 依赖
json
{
"require": {
"yansongda/pay": "~3.7.0",
"alibabacloud/dysmsapi-20170525": "3.1.2",
"aliyuncs/oss-sdk-php": "^2.7",
"w7corp/easywechat": "6.17",
"endroid/qr-code": "^4.8"
}
}
主要第三方服务
支付服务
- 微信支付 (yansongda/pay)
- 支付宝支付 (yansongda/pay)
短信服务
- 阿里云短信 (alibabacloud/dysmsapi-20170525)
- 腾讯云短信
文件存储
- 阿里云 OSS (aliyuncs/oss-sdk-php)
- 本地存储
微信服务
- 微信公众号 (w7corp/easywechat)
- 微信小程序 (w7corp/easywechat)
二维码生成
- QR Code (endroid/qr-code)
配置管理
环境变量配置
env
# 支付配置
WECHAT_MCH_ID=your_mch_id
WECHAT_MCH_SECRET_KEY=your_secret_key
WECHAT_NOTIFY_URL=https://your-domain.com/pay/notify
# 短信配置
ALIYUN_SMS_ACCESS_KEY_ID=your_access_key_id
ALIYUN_SMS_ACCESS_KEY_SECRET=your_access_key_secret
ALIYUN_SMS_SIGN_NAME=your_sign_name
# 文件存储配置
ALIYUN_OSS_ACCESS_KEY_ID=your_access_key_id
ALIYUN_OSS_ACCESS_KEY_SECRET=your_access_key_secret
ALIYUN_OSS_ENDPOINT=your_endpoint
ALIYUN_OSS_BUCKET=your_bucket
配置文件结构
php
// config/trade.php
return [
'default' => 'Wechat',
'wechat' => [
'mch_id' => env('WECHAT_MCH_ID'),
'mch_secret_key' => env('WECHAT_MCH_SECRET_KEY'),
'notify_url' => env('WECHAT_NOTIFY_URL'),
],
];
// config/sms.php
return [
'default' => 'Aliyun',
'aliyun' => [
'access_key_id' => env('ALIYUN_SMS_ACCESS_KEY_ID'),
'access_key_secret' => env('ALIYUN_SMS_ACCESS_KEY_SECRET'),
'sign_name' => env('ALIYUN_SMS_SIGN_NAME'),
],
];
// config/upload.php
return [
'default' => 'Aliyun',
'aliyun' => [
'access_key_id' => env('ALIYUN_OSS_ACCESS_KEY_ID'),
'access_key_secret' => env('ALIYUN_OSS_ACCESS_KEY_SECRET'),
'endpoint' => env('ALIYUN_OSS_ENDPOINT'),
'bucket' => env('ALIYUN_OSS_BUCKET'),
],
];
使用示例
支付服务使用
php
use app\deshang\third_party\trade\TradeManager;
// 创建支付管理器
$config = [
'mch_id' => 'your_mch_id',
'mch_secret_key' => 'your_secret_key',
'mch_secret_cert_path' => '/path/to/cert.pem',
'mch_public_cert_path' => '/path/to/public_cert.pem',
'wechat_public_cert_id' => 'your_cert_id',
'wechat_public_cert_path' => '/path/to/wechat_cert.pem',
'notify_url' => 'https://your-domain.com/pay/notify',
'app_id' => 'your_app_id',
'trade_scene' => TradePaymentConfigEnum::SCENE_WECHAT_MINI,
];
$tradeManager = new TradeManager('Wechat', $config);
// 小程序支付
$result = $tradeManager->mini([
'out_trade_no' => 'order_' . time(),
'subject' => '商品购买',
'total_amount' => 100.00,
'openid' => 'user_openid'
]);
短信服务使用
php
use app\deshang\third_party\sms\SmsManager;
// 创建短信管理器
$config = [
'access_key_id' => 'your_access_key_id',
'access_key_secret' => 'your_access_key_secret',
'sign_name' => 'your_sign_name',
];
$smsManager = new SmsManager('Aliyun', $config);
// 发送验证码短信
$result = $smsManager->send(
'13800138000',
'SMS_123456789',
['code' => '123456']
);
文件上传使用
php
use app\deshang\third_party\upload\UploadManager;
// 创建上传管理器
$config = [
'access_key_id' => 'your_access_key_id',
'access_key_secret' => 'your_access_key_secret',
'endpoint' => 'your_endpoint',
'bucket' => 'your_bucket',
];
$uploadManager = new UploadManager('Aliyun', $config);
// 上传文件
$result = $uploadManager->upload('images');
扩展开发
添加新的第三方服务
- 创建管理器类
php
// app/deshang/third_party/newservice/NewServiceManager.php
class NewServiceManager extends BaseDriverManager
{
protected $namespace = 'app\deshang\third_party\newservice\providers';
protected function getDefaultDriverName(): string
{
return 'DefaultProvider';
}
}
- 创建基础提供者类
php
// app/deshang/third_party/newservice/providers/BaseNewService.php
abstract class BaseNewService
{
protected $config;
public function __construct(array $config)
{
$this->config = $config;
}
abstract public function method1();
abstract public function method2();
}
- 创建具体实现
php
// app/deshang/third_party/newservice/providers/DefaultProvider.php
class DefaultProvider extends BaseNewService
{
public function method1()
{
// 具体实现
}
public function method2()
{
// 具体实现
}
}
添加新的驱动
- 在现有管理器中添加新驱动
php
// app/deshang/third_party/sms/providers/NewSmsProvider.php
class NewSmsProvider extends BaseSms
{
public function send(string $to, string $templateCode, array|string $templateParam = []): bool
{
// 新短信服务商的具体实现
}
}
- 更新配置文件
php
// config/sms.php
return [
'default' => 'NewSmsProvider',
'new_sms_provider' => [
'api_key' => env('NEW_SMS_API_KEY'),
'api_secret' => env('NEW_SMS_API_SECRET'),
],
];
错误处理
异常处理机制
php
try {
$result = $tradeManager->mini($data);
} catch (\Exception $e) {
// 记录错误日志
writeSysAccessLog([
'error' => $e->getMessage(),
'data' => $data,
'driver' => $tradeManager->getDriverName()
]);
// 返回错误信息
return ds_json_error('支付失败:' . $e->getMessage());
}
常见错误类型
配置错误
- 缺少必要的配置参数
- 配置格式不正确
网络错误
- 第三方服务不可用
- 网络超时
业务错误
- 参数验证失败
- 业务逻辑错误
权限错误
- API 密钥无效
- 权限不足
监控和日志
日志记录
php
// 记录第三方服务调用日志
writeSysAccessLog([
'service' => 'trade',
'driver' => 'Wechat',
'method' => 'mini',
'request' => $data,
'response' => $result,
'duration' => $duration,
'status' => 'success'
]);
性能监控
php
$start_time = microtime(true);
$result = $tradeManager->mini($data);
$end_time = microtime(true);
$duration = round(($end_time - $start_time) * 1000, 2);
// 记录性能数据
if ($duration > 5000) { // 超过5秒
writeSysAccessLog([
'warning' => 'slow_response',
'service' => 'trade',
'duration' => $duration
]);
}
最佳实践
1. 配置管理
- 使用环境变量存储敏感信息
- 不同环境使用不同配置
- 定期轮换 API 密钥
2. 错误处理
- 实现统一的错误处理机制
- 记录详细的错误日志
- 提供友好的错误提示
3. 性能优化
- 使用连接池
- 实现请求缓存
- 监控响应时间
4. 安全考虑
- 验证回调签名
- 使用 HTTPS 传输
- 限制 API 调用频率
5. 测试策略
- 单元测试各个驱动
- 集成测试第三方服务
- 模拟测试环境
最后更新:2024-01-20
维护者:DSPlatform技术团队