fix(payment): 解决微信支付异常处理和SQL Runner配置问题
- 在application.yml中启用enable-sql-runner配置以解决SqlRunner删除操作报错 - 在application-ysb.yml中补充完整的mybatis-plus配置包括SQL Runner支持 - 修改ShopDealerWithdrawController中openid获取逻辑,统一使用小程序openid避免微信400错误 - 更新ShopDealerWithdrawMapper.xml中字段别名映射确保数据正确显示 - 在WxTransferService中增强ServiceException处理,提供更友好的错误信息 - 添加详细的异常转换方法toPaymentException解析微信API错误详情 - 补充必要的Gson依赖导入处理JSON响应数据
This commit is contained in:
86
com/wechat/pay/java/core/exception/ServiceException.java
Normal file
86
com/wechat/pay/java/core/exception/ServiceException.java
Normal file
@@ -0,0 +1,86 @@
|
||||
package com.wechat.pay.java.core.exception;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.wechat.pay.java.core.http.HttpRequest;
|
||||
import com.wechat.pay.java.core.util.GsonUtil;
|
||||
|
||||
/** 发送HTTP请求成功,返回异常时抛出。例如返回状态码小于200或大于等于300、返回体参数不完整。 */
|
||||
public class ServiceException extends WechatPayException {
|
||||
|
||||
private static final long serialVersionUID = -7174975090366956652L;
|
||||
|
||||
private final HttpRequest httpRequest;
|
||||
private final int httpStatusCode;
|
||||
private final String responseBody;
|
||||
private String errorCode;
|
||||
private String errorMessage;
|
||||
|
||||
/**
|
||||
* 返回状态码小于200或大于300调用
|
||||
*
|
||||
* @param httpRequest http请求
|
||||
* @param httpStatusCode http状态码
|
||||
* @param responseBody http返回体
|
||||
*/
|
||||
public ServiceException(HttpRequest httpRequest, int httpStatusCode, String responseBody) {
|
||||
super(
|
||||
String.format(
|
||||
"Wrong HttpStatusCode[%d]%nhttpResponseBody[%.1024s]\tHttpRequest[%s]",
|
||||
httpStatusCode, responseBody, httpRequest));
|
||||
this.httpRequest = httpRequest;
|
||||
this.httpStatusCode = httpStatusCode;
|
||||
this.responseBody = responseBody;
|
||||
if (responseBody != null && !responseBody.isEmpty()) {
|
||||
JsonObject jsonObject = GsonUtil.getGson().fromJson(responseBody, JsonObject.class);
|
||||
JsonElement code = jsonObject.get("code");
|
||||
JsonElement message = jsonObject.get("message");
|
||||
this.errorCode = code == null ? null : code.getAsString();
|
||||
this.errorMessage = message == null ? null : message.getAsString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取序列化版本UID
|
||||
*
|
||||
* @return UID
|
||||
*/
|
||||
public static long getSerialVersionUID() {
|
||||
return serialVersionUID;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取HTTP请求
|
||||
*
|
||||
* @return HTTP请求
|
||||
*/
|
||||
public HttpRequest getHttpRequest() {
|
||||
return httpRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取HTTP返回体
|
||||
*
|
||||
* @return HTTP返回体
|
||||
*/
|
||||
public String getResponseBody() {
|
||||
return responseBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取HTTP状态码
|
||||
*
|
||||
* @return HTTP状态码
|
||||
*/
|
||||
public int getHttpStatusCode() {
|
||||
return httpStatusCode;
|
||||
}
|
||||
|
||||
public String getErrorCode() {
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
public String getErrorMessage() {
|
||||
return errorMessage;
|
||||
}
|
||||
}
|
||||
151
com/wechat/pay/java/core/http/AbstractHttpClient.java
Normal file
151
com/wechat/pay/java/core/http/AbstractHttpClient.java
Normal file
@@ -0,0 +1,151 @@
|
||||
package com.wechat.pay.java.core.http;
|
||||
|
||||
import static com.wechat.pay.java.core.http.Constant.ACCEPT;
|
||||
import static com.wechat.pay.java.core.http.Constant.AUTHORIZATION;
|
||||
import static com.wechat.pay.java.core.http.Constant.OS;
|
||||
import static com.wechat.pay.java.core.http.Constant.REQUEST_ID;
|
||||
import static com.wechat.pay.java.core.http.Constant.USER_AGENT;
|
||||
import static com.wechat.pay.java.core.http.Constant.USER_AGENT_FORMAT;
|
||||
import static com.wechat.pay.java.core.http.Constant.VERSION;
|
||||
import static com.wechat.pay.java.core.http.Constant.WECHAT_PAY_SERIAL;
|
||||
import static java.net.HttpURLConnection.HTTP_MULT_CHOICE;
|
||||
import static java.net.HttpURLConnection.HTTP_OK;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.wechat.pay.java.core.auth.Credential;
|
||||
import com.wechat.pay.java.core.auth.Validator;
|
||||
import com.wechat.pay.java.core.exception.MalformedMessageException;
|
||||
import com.wechat.pay.java.core.exception.ServiceException;
|
||||
import com.wechat.pay.java.core.exception.ValidationException;
|
||||
import com.wechat.pay.java.core.http.HttpRequest.Builder;
|
||||
import java.io.InputStream;
|
||||
|
||||
/** 请求客户端抽象基类 */
|
||||
public abstract class AbstractHttpClient implements HttpClient {
|
||||
|
||||
protected final Credential credential;
|
||||
protected final Validator validator;
|
||||
|
||||
public AbstractHttpClient(Credential credential, Validator validator) {
|
||||
this.credential = requireNonNull(credential);
|
||||
this.validator = requireNonNull(validator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> HttpResponse<T> execute(HttpRequest httpRequest, Class<T> responseClass) {
|
||||
HttpRequest innerRequest =
|
||||
new Builder()
|
||||
.url(httpRequest.getUrl())
|
||||
.httpMethod(httpRequest.getHttpMethod())
|
||||
.headers(httpRequest.getHeaders())
|
||||
.addHeader(AUTHORIZATION, getAuthorization(httpRequest))
|
||||
.addHeader(USER_AGENT, getUserAgent())
|
||||
.addHeader(WECHAT_PAY_SERIAL, getWechatPaySerial())
|
||||
.body(httpRequest.getBody())
|
||||
.build();
|
||||
OriginalResponse originalResponse = innerExecute(innerRequest);
|
||||
validateResponse(originalResponse);
|
||||
return assembleHttpResponse(originalResponse, responseClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream download(String url) {
|
||||
HttpRequest originRequest =
|
||||
new HttpRequest.Builder().httpMethod(HttpMethod.GET).url(url).build();
|
||||
HttpRequest httpRequest =
|
||||
new HttpRequest.Builder()
|
||||
.url(url)
|
||||
.httpMethod(HttpMethod.GET)
|
||||
.addHeader(AUTHORIZATION, getAuthorization(originRequest))
|
||||
.addHeader(ACCEPT, "*/*")
|
||||
.addHeader(USER_AGENT, getUserAgent())
|
||||
.addHeader(WECHAT_PAY_SERIAL, getWechatPaySerial())
|
||||
.build();
|
||||
return innerDownload(httpRequest);
|
||||
}
|
||||
|
||||
protected abstract InputStream innerDownload(HttpRequest httpRequest);
|
||||
|
||||
protected abstract OriginalResponse innerExecute(HttpRequest httpRequest);
|
||||
|
||||
private void validateResponse(OriginalResponse originalResponse) {
|
||||
|
||||
if (isInvalidHttpCode(originalResponse.getStatusCode())) {
|
||||
throw new ServiceException(
|
||||
originalResponse.getRequest(),
|
||||
originalResponse.getStatusCode(),
|
||||
originalResponse.getBody());
|
||||
}
|
||||
|
||||
if (originalResponse.getBody() != null
|
||||
&& !originalResponse.getBody().isEmpty()
|
||||
&& !MediaType.APPLICATION_JSON.equalsWith(originalResponse.getContentType())) {
|
||||
throw new MalformedMessageException(
|
||||
String.format(
|
||||
"Unsupported content-type[%s]%nhttpRequest[%s]",
|
||||
originalResponse.getContentType(), originalResponse.getRequest()));
|
||||
}
|
||||
|
||||
if (!validator.validate(originalResponse.getHeaders(), originalResponse.getBody())) {
|
||||
String requestId = originalResponse.getHeaders().getHeader(REQUEST_ID);
|
||||
throw new ValidationException(
|
||||
String.format(
|
||||
"Validate response failed,the WechatPay signature is incorrect.%n"
|
||||
+ "Request-ID[%s]\tresponseHeader[%s]\tresponseBody[%.1024s]",
|
||||
requestId, originalResponse.getHeaders(), originalResponse.getBody()));
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isInvalidHttpCode(int httpCode) {
|
||||
return httpCode < HTTP_OK || httpCode >= HTTP_MULT_CHOICE;
|
||||
}
|
||||
|
||||
private <T> HttpResponse<T> assembleHttpResponse(
|
||||
OriginalResponse originalResponse, Class<T> responseClass) {
|
||||
return new HttpResponse.Builder<T>()
|
||||
.originalResponse(originalResponse)
|
||||
.serviceResponseType(responseClass)
|
||||
.build();
|
||||
}
|
||||
|
||||
private String getSignBody(RequestBody requestBody) {
|
||||
if (requestBody == null) {
|
||||
return "";
|
||||
}
|
||||
if (requestBody instanceof JsonRequestBody) {
|
||||
return ((JsonRequestBody) requestBody).getBody();
|
||||
}
|
||||
if (requestBody instanceof FileRequestBody) {
|
||||
return ((FileRequestBody) requestBody).getMeta();
|
||||
}
|
||||
throw new UnsupportedOperationException(
|
||||
String.format("Unsupported RequestBody Type[%s]", requestBody.getClass().getName()));
|
||||
}
|
||||
|
||||
private String getUserAgent() {
|
||||
return String.format(
|
||||
USER_AGENT_FORMAT,
|
||||
getClass().getPackage().getImplementationVersion(),
|
||||
OS,
|
||||
VERSION == null ? "Unknown" : VERSION,
|
||||
credential.getClass().getSimpleName(),
|
||||
validator.getClass().getSimpleName(),
|
||||
getHttpClientInfo());
|
||||
}
|
||||
|
||||
private String getWechatPaySerial() {
|
||||
return this.validator.getSerialNumber();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取http客户端信息,用于User-Agent。 格式:客户端名称/版本 示例:okhttp3/4.9.3
|
||||
*
|
||||
* @return 客户端信息
|
||||
*/
|
||||
protected abstract String getHttpClientInfo();
|
||||
|
||||
private String getAuthorization(HttpRequest request) {
|
||||
return credential.getAuthorization(
|
||||
request.getUri(), request.getHttpMethod().name(), getSignBody(request.getBody()));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user