抽象基类通过模板方法统一验签与网络请求流程:定义getSignContent、getPublicKey等抽象方法由子类实现平台特异性逻辑,封装verifyNotify和execute等final方法提供共用流程,并保留Web入口、密钥加载、幂等性、异常处理等扩展点。

抽象基类统一处理验签逻辑
支付网关(如支付宝、微信、银联)的回调通知都要求服务端验签,但各平台签名算法、密钥格式、参数排序规则不同。抽象基类不实现具体验签,而是定义模板方法和钩子:
-
定义抽象方法:
protected abstract String getSignContent(Map<string string> params)</string>—— 由子类实现参数拼接规则(如微信按字典序+&拼接,支付宝用key=value格式) -
封装共用验签流程:
public final boolean verifyNotify(Map<string string> notifyParams, String sign)</string>内部调用getSignContent+getPublicKey()+doVerify(sign)(后者可委托给通用RSA/SM2工具类) -
让子类决定密钥来源:
protected abstract String getPublicKey()或protected abstract Certificate getCertificate(),适配不同平台证书或公钥字符串管理方式
网络请求能力通过模板方法下沉
发起支付下单、查询、退款等请求时,各网关的HTTP方法、URL构造、Header头(如微信需Authorization,银联需Signature)、body序列化格式(XML/JSON)各异。抽象基类聚焦“不变”部分:
-
统一执行入口:
public final <t> T execute(String apiPath, Map<string object> reqData, Class<t> responseType)</t></string></t> -
分步交由子类定制:
-
protected abstract String buildUrl(String apiPath)—— 拼接基础网关域名与路径 -
protected abstract Map<string string> buildHeaders(Map<string object> reqData)</string></string>—— 注入时间戳、随机串、签名头等 -
protected abstract String serializeRequestBody(Map<string object> reqData)</string>—— 返回JSON字符串或XML字符串 -
protected abstract <t> T parseResponse(String rawBody, Class<t> type)</t></t>—— 处理不同响应结构(微信返回XML需转Bean,支付宝返回JSON)
-
-
内置重试与日志:在
execute中统一加入OkHttp/Retrofit拦截器、失败重试策略、敏感字段脱敏日志(如过滤sign、privateKey)
子类只需关注平台特异性细节
以微信支付子类为例,它不用重复写HTTP发送或验签流程,只专注“微信怎么干”:
-
getSignContent实现:对notifyParams剔除sign键,按ASCII升序拼接key=value&并去掉末尾& -
buildUrl返回"https://api.mch.weixin.qq.com/v3/" + apiPath -
buildHeaders添加Authorization: WECHATPAY2-SHA256-RSA2048 ...及Accept: application/json -
serializeRequestBody使用Jackson将Map转JSON,并确保空值字段不输出(微信要求)
支付宝子类则对应调整签名拼接(去除空值、按字母序、key=value无&)、URL前缀、sign_type参数、响应JSON解析方式。
立即学习“Java免费学习笔记(深入)”;
避免抽象过度,保留扩展点
抽象基类不是越厚越好。以下情况应保持开放,不强行抽象:
-
异步通知的接收入口:Spring MVC的
@PostMapping("/wechat/notify")由子类自己声明,基类不耦合Web层 - 密钥/证书加载方式:支持从配置中心、本地文件、K8s Secret注入,由子类选择初始化策略
- 幂等性控制:是否查库校验重复通知、如何生成业务唯一键,交给上层业务或子类决定
-
异常分类处理:网络超时、验签失败、业务错误码(如微信
ORDERPAID)需子类提供isBusinessSuccess(String code)判断
这样既保证核心流程复用,又不约束业务集成的灵活性。


















