新增JSAPI功能
This commit is contained in:
parent
b1bafbc6a3
commit
fe40966c0f
@ -0,0 +1,53 @@
|
||||
package ink.wgink.properties.wechat.pay.v3;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @ClassName: PayProperties
|
||||
* @Description: 支付配置
|
||||
* @Author: wanggeng
|
||||
* @Date: 2021/8/19 4:05 下午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "open-platform.wechat.pay")
|
||||
public class PayProperties {
|
||||
|
||||
private Boolean active;
|
||||
private String mchid;
|
||||
private String certificatePath;
|
||||
private String keyPath;
|
||||
|
||||
public Boolean getActive() {
|
||||
return active;
|
||||
}
|
||||
|
||||
public void setActive(Boolean active) {
|
||||
this.active = active;
|
||||
}
|
||||
|
||||
public String getMchid() {
|
||||
return mchid == null ? "" : mchid.trim();
|
||||
}
|
||||
|
||||
public void setMchid(String mchid) {
|
||||
this.mchid = mchid;
|
||||
}
|
||||
|
||||
public String getCertificatePath() {
|
||||
return certificatePath == null ? "" : certificatePath.trim();
|
||||
}
|
||||
|
||||
public void setCertificatePath(String certificatePath) {
|
||||
this.certificatePath = certificatePath;
|
||||
}
|
||||
|
||||
public String getKeyPath() {
|
||||
return keyPath == null ? "" : keyPath.trim();
|
||||
}
|
||||
|
||||
public void setKeyPath(String keyPath) {
|
||||
this.keyPath = keyPath;
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package ink.wgink.module.wechat.enums;
|
||||
|
||||
/**
|
||||
* @ClassName: AuthorizationTypeEnum
|
||||
* @Description: 认证类型
|
||||
* @Author: wanggeng
|
||||
* @Date: 2021/8/19 5:17 下午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public enum PayAuthorizationTypeEnum {
|
||||
|
||||
WECHATPAY2_SHA256_RSA2048("WECHATPAY2-SHA256-RSA2048");
|
||||
|
||||
private String value;
|
||||
|
||||
PayAuthorizationTypeEnum(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value == null ? "" : value.trim();
|
||||
}
|
||||
}
|
@ -9,8 +9,14 @@ package ink.wgink.module.wechat.enums;
|
||||
*/
|
||||
public enum PayErrorMsgEnum {
|
||||
|
||||
/**
|
||||
* 202 错误
|
||||
*/
|
||||
USERPAYING_200(202, "USERPAYING", "用户支付中,需要输入密码", "等待5秒,然后调用被扫订单结果查询API,查询当前订单的不同状态,决定下一步的操作"),
|
||||
|
||||
/**
|
||||
* 400 错误
|
||||
*/
|
||||
APPID_MCHID_NOT_MATCH_400(400, "APPID_MCHID_NOT_MATCH", "appid和mch_id不匹配", "请确认appid和mch_id是否匹配"),
|
||||
PARAM_ERROR_400(400, "PARAM_ERROR", "业务规则限制", "请根据接口返回的详细信息检查请求参数"),
|
||||
ORDER_CLOSED(400, "ORDER_CLOSED", "订单已关闭", "当前订单已关闭,请重新下单"),
|
||||
@ -29,8 +35,14 @@ public enum PayErrorMsgEnum {
|
||||
ORDERPAID_400(400, "ORDERPAID", "订单已支付", "请确认该订单号是否重复支付,如果是新单,请使用新订单号提交"),
|
||||
ORDERREVERSED_400(400, "ORDERREVERSED", "订单已撤销", "当前订单状态为“订单已撤销”,请提示用户重新支付"),
|
||||
|
||||
/**
|
||||
* 401 错误
|
||||
*/
|
||||
SIGN_ERROR_401(401, "SIGN_ERROR", "签名错误", "请检查签名参数和方法是否都符合签名算法要求"),
|
||||
|
||||
/**
|
||||
* 403 错误
|
||||
*/
|
||||
TRADE_ERROR_403(403, "TRADE_ERROR", "交易错误", "因业务原因交易失败,请查看接口返回的详细信息"),
|
||||
OUT_TRADE_NO_USED_403(403, "OUT_TRADE_NO_USED", "商户订单号重复", "请核实商户订单号是否重复提交"),
|
||||
ACCOUNT_ERROR_403(403, "ACCOUNT_ERROR", "账号异常", "用户账号异常,无需更多操作"),
|
||||
@ -46,6 +58,9 @@ public enum PayErrorMsgEnum {
|
||||
CONTRACT_NOT_CONFIRMED_403(403, "CONTRACT_NOT_CONFIRMED", "二级商户未开启手动提现权限", "二级商户号提现权限已关闭,无法发起提现"),
|
||||
ACCOUNT_NOT_VERIFIED_403(403, "ACCOUNT_NOT_VERIFIED", "二级商户下行打款未成功", "二级商户号结算银行卡信息有误,修改后重试"),
|
||||
|
||||
/**
|
||||
* 404 错误
|
||||
*/
|
||||
REFUND_NOT_EXISTS_404(404, "REFUND_NOT_EXISTS", "订单号错误或订单状态不正确", "请检查订单号是否有误以及订单状态是否正确,如:未支付、已支付未退款"),
|
||||
ORDER_NO_TEXIST_404(404, "ORDER_NO_TEXIST", "订单不存在", "请检查订单是否发起过交易"),
|
||||
ORDER_NOT_EXIST_404(404, "ORDER_NOT_EXIST", "请求的资源不存在", "请商户检查需要查询的id或者请求URL是否正确"),
|
||||
@ -55,10 +70,16 @@ public enum PayErrorMsgEnum {
|
||||
RESOURCE_NOT_EXISTS_404(404, "RESOURCE_NOT_EXISTS", "查询的资源不存在", "请检查查询资源的对应id是否填写正确"),
|
||||
NOT_FOUND_404(404, "NOT_FOUND", "请求的资源不存在", "请商户检查需要查询的id或者请求URL是否正确"),
|
||||
|
||||
/**
|
||||
* 429 错误
|
||||
*/
|
||||
FREQUENCY_LIMITED_429(429, "FREQUENCY_LIMITED", "频率超限", "请求量不要超过接口调用频率限制"),
|
||||
RATELIMIT_EXCEEDED_429(429, "RATELIMIT_EXCEEDED", "频率限制", "请降低频率后重试"),
|
||||
FREQUENCY_LIMIT_EXCEED_429(429, "FREQUENCY_LIMIT_EXCEED", "接口限频", "请降低调用频率"),
|
||||
|
||||
/**
|
||||
* 500 错误
|
||||
*/
|
||||
ERROR_500(500, "ERROR", "业务错误", "该错误都会返回具体的错误原因,请根据实际返回做相应处理"),
|
||||
OPENID_MISMATCH_500(500, "OPENID_MISMATCH", "openid和appid不匹配", "请确认openid和appid是否匹配"),
|
||||
BANK_ERROR_500(500, "BANK_ERROR", "银行系统异常", "银行系统异常,请用相同参数重新调用"),
|
||||
|
@ -0,0 +1,40 @@
|
||||
package ink.wgink.module.wechat.manager.pay.v3;
|
||||
|
||||
import ink.wgink.module.wechat.utils.pay.PayCertificateUtil;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
/**
|
||||
* @ClassName: PayMiniappManager
|
||||
* @Description: 支付管理
|
||||
* @Author: wanggeng
|
||||
* @Date: 2021/8/19 11:10 上午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class PayManager {
|
||||
|
||||
private static final PayManager PAY_MANAGER = PayMiniappManagerBuilder.payManager;
|
||||
private X509Certificate x509Certificate;
|
||||
|
||||
private PayManager() {
|
||||
}
|
||||
|
||||
public static PayManager getInstance() {
|
||||
return PAY_MANAGER;
|
||||
}
|
||||
|
||||
public X509Certificate getX509Certificate() {
|
||||
return x509Certificate;
|
||||
}
|
||||
|
||||
public void setX509Certificate(String certificatePath) throws FileNotFoundException {
|
||||
this.x509Certificate = PayCertificateUtil.getCertificate(new FileInputStream(certificatePath));
|
||||
}
|
||||
|
||||
private static class PayMiniappManagerBuilder {
|
||||
public static PayManager payManager = new PayManager();
|
||||
}
|
||||
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package ink.wgink.module.wechat.manager.pay.v3.miniapp;
|
||||
|
||||
/**
|
||||
* @ClassName: PayMiniappManager
|
||||
* @Description: 小程序支付管理
|
||||
* @Author: wanggeng
|
||||
* @Date: 2021/8/19 11:10 上午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class PayMiniappManager {
|
||||
|
||||
private static final PayMiniappManager payMiniappManager = PayMiniappManagerBuilder.payMiniappManager;
|
||||
|
||||
private PayMiniappManager() {
|
||||
}
|
||||
|
||||
public PayMiniappManager getInstance() {
|
||||
return payMiniappManager;
|
||||
}
|
||||
|
||||
private static class PayMiniappManagerBuilder {
|
||||
public static PayMiniappManager payMiniappManager = new PayMiniappManager();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
package ink.wgink.module.wechat.pojo.pay.v3;
|
||||
|
||||
/**
|
||||
* @ClassName: ErrorResponse
|
||||
* @Description: 错误返回
|
||||
* @Author: wanggeng
|
||||
* @Date: 2021/8/19 6:02 下午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class PayErrorResponse {
|
||||
|
||||
private String code;
|
||||
private String message;
|
||||
private Detail detail;
|
||||
|
||||
public String getCode() {
|
||||
return code == null ? "" : code.trim();
|
||||
}
|
||||
|
||||
public void setCode(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message == null ? "" : message.trim();
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public Detail getDetail() {
|
||||
return detail;
|
||||
}
|
||||
|
||||
public void setDetail(Detail detail) {
|
||||
this.detail = detail;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder("{");
|
||||
sb.append("\"code\":\"")
|
||||
.append(code).append('\"');
|
||||
sb.append(",\"message\":\"")
|
||||
.append(message).append('\"');
|
||||
sb.append(",\"detail\":")
|
||||
.append(detail);
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static class Detail {
|
||||
private String field;
|
||||
private String value;
|
||||
private String issue;
|
||||
private String location;
|
||||
|
||||
public String getField() {
|
||||
return field == null ? "" : field.trim();
|
||||
}
|
||||
|
||||
public void setField(String field) {
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value == null ? "" : value.trim();
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getIssue() {
|
||||
return issue == null ? "" : issue.trim();
|
||||
}
|
||||
|
||||
public void setIssue(String issue) {
|
||||
this.issue = issue;
|
||||
}
|
||||
|
||||
public String getLocation() {
|
||||
return location == null ? "" : location.trim();
|
||||
}
|
||||
|
||||
public void setLocation(String location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder("{");
|
||||
sb.append("\"field\":\"")
|
||||
.append(field).append('\"');
|
||||
sb.append(",\"value\":\"")
|
||||
.append(value).append('\"');
|
||||
sb.append(",\"issue\":\"")
|
||||
.append(issue).append('\"');
|
||||
sb.append(",\"location\":\"")
|
||||
.append(location).append('\"');
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package ink.wgink.module.wechat.pojo.bos.pay.v3;
|
||||
package ink.wgink.module.wechat.pojo.pay.v3.jsapi.pojo;
|
||||
|
||||
import ink.wgink.annotation.*;
|
||||
|
||||
@ -11,7 +11,7 @@ import java.util.List;
|
||||
* @Date: 2021/8/19 1:52 下午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class PlaceOrderBO {
|
||||
public class PayPlaceOrder {
|
||||
|
||||
@CheckEmptyAnnotation(name = "应用ID")
|
||||
private String appid;
|
||||
@ -395,6 +395,47 @@ public class PlaceOrderBO {
|
||||
* 商户端设备号
|
||||
*/
|
||||
private String deviceId;
|
||||
/**
|
||||
* 商户门店信息
|
||||
*/
|
||||
private StoreInfo storeInfo;
|
||||
|
||||
public String getPayerClientIp() {
|
||||
return payerClientIp == null ? "" : payerClientIp.trim();
|
||||
}
|
||||
|
||||
public void setPayerClientIp(String payerClientIp) {
|
||||
this.payerClientIp = payerClientIp;
|
||||
}
|
||||
|
||||
public String getDeviceId() {
|
||||
return deviceId == null ? "" : deviceId.trim();
|
||||
}
|
||||
|
||||
public void setDeviceId(String deviceId) {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
public StoreInfo getStoreInfo() {
|
||||
return storeInfo;
|
||||
}
|
||||
|
||||
public void setStoreInfo(StoreInfo storeInfo) {
|
||||
this.storeInfo = storeInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder("{");
|
||||
sb.append("\"payerClientIp\":\"")
|
||||
.append(payerClientIp).append('\"');
|
||||
sb.append(",\"deviceId\":\"")
|
||||
.append(deviceId).append('\"');
|
||||
sb.append(",\"storeInfo\":")
|
||||
.append(storeInfo);
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户门店信息
|
@ -0,0 +1,30 @@
|
||||
package ink.wgink.module.wechat.pojo.pay.v3.jsapi.pojo;
|
||||
|
||||
/**
|
||||
* @ClassName: Prepay
|
||||
* @Description: 预支付
|
||||
* @Author: wanggeng
|
||||
* @Date: 2021/8/19 5:38 下午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class PayPrepay {
|
||||
|
||||
private String prepayId;
|
||||
|
||||
public String getPrepayId() {
|
||||
return prepayId == null ? "" : prepayId.trim();
|
||||
}
|
||||
|
||||
public void setPrepayId(String prepayId) {
|
||||
this.prepayId = prepayId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder("{");
|
||||
sb.append("\"prepayId\":\"")
|
||||
.append(prepayId).append('\"');
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
@ -1,11 +1,22 @@
|
||||
package ink.wgink.module.wechat.utils.pay;
|
||||
package ink.wgink.module.wechat.request.pay.v3;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import ink.wgink.exceptions.base.SystemException;
|
||||
import ink.wgink.module.wechat.enums.PayAuthorizationTypeEnum;
|
||||
import ink.wgink.module.wechat.pojo.pay.v3.PayErrorResponse;
|
||||
import ink.wgink.module.wechat.utils.pay.PaySignAuthorizationUtil;
|
||||
import ink.wgink.properties.wechat.pay.v3.PayProperties;
|
||||
import ink.wgink.util.UUIDUtil;
|
||||
import ink.wgink.util.string.WStringUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
@ -13,6 +24,7 @@ import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.spec.GCMParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
@ -27,9 +39,11 @@ import java.util.Base64;
|
||||
* @Date: 2021/8/18 9:41 下午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public abstract class AbstractPayRequest {
|
||||
public abstract class AbstractPayRequest<RequestBody, Response> {
|
||||
|
||||
protected static final Logger LOG = LoggerFactory.getLogger(AbstractPayRequest.class);
|
||||
public static final String PAY_SERIAL = "Wechatpay-Serial";
|
||||
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
public AbstractPayRequest() {
|
||||
@ -39,7 +53,20 @@ public abstract class AbstractPayRequest {
|
||||
this.restTemplate = new RestTemplate(simpleClientHttpRequestFactory);
|
||||
}
|
||||
|
||||
public abstract void response(ResponseEntity<String> responseEntity);
|
||||
/**
|
||||
* bodys实体转json字符串
|
||||
*
|
||||
* @param requestBody
|
||||
* @return
|
||||
*/
|
||||
public abstract String bodyJsonString(RequestBody requestBody);
|
||||
|
||||
/**
|
||||
* 响应结果处理
|
||||
*
|
||||
* @param responseEntity
|
||||
*/
|
||||
public abstract Response response(ResponseEntity<String> responseEntity);
|
||||
|
||||
/**
|
||||
* GET 请求
|
||||
@ -48,10 +75,11 @@ public abstract class AbstractPayRequest {
|
||||
* @param authorization 授权信息
|
||||
* @param serialNumber 公钥证书序列号
|
||||
*/
|
||||
public void get(String url, String authorization, String serialNumber) {
|
||||
public Response get(String url, String authorization, String serialNumber) {
|
||||
HttpEntity<String> httpEntity = new HttpEntity(getHttpHeaders(authorization, serialNumber));
|
||||
ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class);
|
||||
response(responseEntity);
|
||||
checkResponseCode(responseEntity);
|
||||
return response(responseEntity);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -62,10 +90,11 @@ public abstract class AbstractPayRequest {
|
||||
* @param serialNumber 公钥证书序列号
|
||||
* @param jsonBody 请求参数
|
||||
*/
|
||||
public void post(String url, String authorization, String serialNumber, String jsonBody) {
|
||||
public Response post(String url, String authorization, String serialNumber, String jsonBody) {
|
||||
HttpEntity<String> httpEntity = new HttpEntity(jsonBody, getHttpHeaders(authorization, serialNumber));
|
||||
ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class);
|
||||
response(responseEntity);
|
||||
checkResponseCode(responseEntity);
|
||||
return response(responseEntity);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -76,10 +105,11 @@ public abstract class AbstractPayRequest {
|
||||
* @param serialNumber 公钥证书序列号
|
||||
* @param jsonBody 请求参数
|
||||
*/
|
||||
public void put(String url, String authorization, String serialNumber, String jsonBody) {
|
||||
public Response put(String url, String authorization, String serialNumber, String jsonBody) {
|
||||
HttpEntity<String> httpEntity = new HttpEntity(jsonBody, getHttpHeaders(authorization, serialNumber));
|
||||
ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.PUT, httpEntity, String.class);
|
||||
response(responseEntity);
|
||||
checkResponseCode(responseEntity);
|
||||
return response(responseEntity);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -89,10 +119,11 @@ public abstract class AbstractPayRequest {
|
||||
* @param authorization 授权信息
|
||||
* @param serialNumber 公钥证书序列号
|
||||
*/
|
||||
public void delete(String url, String authorization, String serialNumber) {
|
||||
public Response delete(String url, String authorization, String serialNumber) {
|
||||
HttpEntity<String> httpEntity = new HttpEntity(getHttpHeaders(authorization, serialNumber));
|
||||
ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.DELETE, httpEntity, String.class);
|
||||
response(responseEntity);
|
||||
checkResponseCode(responseEntity);
|
||||
return response(responseEntity);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -104,14 +135,34 @@ public abstract class AbstractPayRequest {
|
||||
* @param jsonData 请求参数
|
||||
* @param uploadFile 上传文件
|
||||
*/
|
||||
public void upload(String url, String authorization, String serialNumber, String jsonData, File uploadFile) {
|
||||
public Response upload(String url, String authorization, String serialNumber, String jsonData, File uploadFile) {
|
||||
FileSystemResource fileSystemResource = new FileSystemResource(uploadFile);
|
||||
MultiValueMap<String, Object> form = new LinkedMultiValueMap<>();
|
||||
form.add("file", fileSystemResource);
|
||||
form.add("meta", jsonData);
|
||||
HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(form, getUploadHeaders(authorization, serialNumber));
|
||||
ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class);
|
||||
response(responseEntity);
|
||||
checkResponseCode(responseEntity);
|
||||
return response(responseEntity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 认证头
|
||||
*
|
||||
* @param requestMethod
|
||||
* @param urlSuffix
|
||||
* @param payProperties
|
||||
* @param jsonBody
|
||||
* @param payAuthorizationTypeEnum
|
||||
* @return
|
||||
* @throws FileNotFoundException
|
||||
*/
|
||||
public String getAuthorization(RequestMethod requestMethod, String urlSuffix, String serialNumber, PayProperties payProperties, String jsonBody, PayAuthorizationTypeEnum payAuthorizationTypeEnum) throws Exception {
|
||||
String randomSubStr = WStringUtil.randomSubStr(UUIDUtil.get32UUID(), 10).toUpperCase();
|
||||
return PaySignAuthorizationUtil.buildAuthorization(requestMethod, urlSuffix,
|
||||
payProperties.getMchid(), serialNumber,
|
||||
payProperties.getKeyPath(), jsonBody, randomSubStr, System.currentTimeMillis(),
|
||||
payAuthorizationTypeEnum.getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -159,6 +210,20 @@ public abstract class AbstractPayRequest {
|
||||
return httpHeaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查返回状态码
|
||||
*
|
||||
* @param responseEntity
|
||||
*/
|
||||
private void checkResponseCode(ResponseEntity<String> responseEntity) {
|
||||
if (responseEntity.getStatusCode().value() == HttpStatus.OK.value()) {
|
||||
return;
|
||||
}
|
||||
LOG.error(responseEntity.getBody());
|
||||
PayErrorResponse payErrorResponse = JSONObject.parseObject(responseEntity.getBody(), PayErrorResponse.class);
|
||||
throw new SystemException(payErrorResponse.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Aes 解密
|
||||
*/
|
@ -0,0 +1,155 @@
|
||||
package ink.wgink.module.wechat.request.pay.v3.jsapi;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import ink.wgink.module.wechat.request.pay.v3.AbstractPayRequest;
|
||||
import ink.wgink.module.wechat.pojo.pay.v3.jsapi.pojo.PayPlaceOrder;
|
||||
import ink.wgink.module.wechat.pojo.pay.v3.jsapi.pojo.PayPrepay;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @ClassName: PlaceOrderPayRequest
|
||||
* @Description: 下单请求
|
||||
* @Author: wanggeng
|
||||
* @Date: 2021/8/19 3:22 下午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class PlaceOrderPayRequestImpl extends AbstractPayRequest<PayPlaceOrder, PayPrepay> {
|
||||
|
||||
@Override
|
||||
public String bodyJsonString(PayPlaceOrder payPlaceOrder) {
|
||||
JSONObject bodyObject = new JSONObject();
|
||||
bodyObject.put("appid", payPlaceOrder.getAppid());
|
||||
bodyObject.put("mchid", payPlaceOrder.getMchid());
|
||||
bodyObject.put("description", payPlaceOrder.getDescription());
|
||||
bodyObject.put("out_trade_no", payPlaceOrder.getOutTradeNo());
|
||||
bodyObject.put("time_expire", payPlaceOrder.getTimeExpire());
|
||||
bodyObject.put("attach", payPlaceOrder.getAttach());
|
||||
bodyObject.put("notify_url", payPlaceOrder.getNotifyUrl());
|
||||
bodyObject.put("goods_tag", payPlaceOrder.getGoodsTag());
|
||||
bodyObject.put("amount", getAmountJsonObject(payPlaceOrder.getAmount()));
|
||||
if (payPlaceOrder.getDetail() != null) {
|
||||
bodyObject.put("detail", payPlaceOrder.getDetail());
|
||||
}
|
||||
if (payPlaceOrder.getSceneInfo() != null) {
|
||||
bodyObject.put("scene_info", payPlaceOrder.getSceneInfo());
|
||||
}
|
||||
if (payPlaceOrder.getSettleInfo() != null) {
|
||||
bodyObject.put("settle_info", payPlaceOrder.getSettleInfo());
|
||||
}
|
||||
return bodyObject.toJSONString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PayPrepay response(ResponseEntity<String> responseEntity) {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单金额
|
||||
*
|
||||
* @param amount
|
||||
* @return
|
||||
*/
|
||||
private JSONObject getAmountJsonObject(PayPlaceOrder.Amount amount) {
|
||||
JSONObject amountJsonObject = new JSONObject();
|
||||
amountJsonObject.put("total", amount.getTotal());
|
||||
amountJsonObject.put("currency", amount.getCurrency());
|
||||
return amountJsonObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付者
|
||||
*
|
||||
* @param payer
|
||||
* @return
|
||||
*/
|
||||
private JSONObject getPayer(PayPlaceOrder.Payer payer) {
|
||||
JSONObject payerJsonObject = new JSONObject();
|
||||
payerJsonObject.put("openid", payer.getOpenid());
|
||||
return payerJsonObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* 优惠功能
|
||||
*
|
||||
* @param detail
|
||||
* @return
|
||||
*/
|
||||
private JSONObject getDetail(PayPlaceOrder.Detail detail) {
|
||||
JSONObject detailJsonObject = new JSONObject();
|
||||
detailJsonObject.put("cost_price", detail.getCostPrice());
|
||||
detailJsonObject.put("invoice_id", detail.getInvoiceId());
|
||||
if (detail.getGoodsDetail() != null || !detail.getGoodsDetail().isEmpty()) {
|
||||
detailJsonObject.put("goods_detail", listGoodsDetail(detail.getGoodsDetail()));
|
||||
}
|
||||
return detailJsonObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品列表
|
||||
*
|
||||
* @param goodsList
|
||||
* @return
|
||||
*/
|
||||
private JSONArray listGoodsDetail(List<PayPlaceOrder.Detail.Goods> goodsList) {
|
||||
JSONArray goodsDetailJsonArray = new JSONArray();
|
||||
for (PayPlaceOrder.Detail.Goods goods : goodsList) {
|
||||
JSONObject goodsJsonObject = new JSONObject();
|
||||
goodsJsonObject.put("merchant_goods_id", goods.getMerchantGoodsId());
|
||||
goodsJsonObject.put("wechatpay_goods_id", goods.getWechatpayGoodsId());
|
||||
goodsJsonObject.put("goods_name", goods.getGoodsName());
|
||||
goodsJsonObject.put("quantity", goods.getQuantity());
|
||||
goodsJsonObject.put("unit_price", goods.getUnitPrice());
|
||||
goodsDetailJsonArray.add(goodsJsonObject);
|
||||
}
|
||||
return goodsDetailJsonArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* 场景信息
|
||||
*
|
||||
* @param sceneInfo
|
||||
* @return
|
||||
*/
|
||||
private JSONObject getSceneInfo(PayPlaceOrder.SceneInfo sceneInfo) {
|
||||
JSONObject sceneInfoJsonObject = new JSONObject();
|
||||
sceneInfoJsonObject.put("payer_client_ip", sceneInfo.getPayerClientIp());
|
||||
sceneInfoJsonObject.put("device_id", sceneInfo.getDeviceId());
|
||||
if (sceneInfo.getStoreInfo() != null) {
|
||||
sceneInfoJsonObject.put("store_info", getStoreInfo(sceneInfo.getStoreInfo()));
|
||||
}
|
||||
return sceneInfoJsonObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户门店信息
|
||||
*
|
||||
* @param storeInfo
|
||||
* @return
|
||||
*/
|
||||
private JSONObject getStoreInfo(PayPlaceOrder.SceneInfo.StoreInfo storeInfo) {
|
||||
JSONObject storeInfoJsonObject = new JSONObject();
|
||||
storeInfoJsonObject.put("id", storeInfo.getId());
|
||||
storeInfoJsonObject.put("name", storeInfo.getName());
|
||||
storeInfoJsonObject.put("area_code", storeInfo.getAreaCode());
|
||||
storeInfoJsonObject.put("address", storeInfo.getAddress());
|
||||
return storeInfoJsonObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否指定分账
|
||||
*
|
||||
* @param settleInfo
|
||||
* @return
|
||||
*/
|
||||
private JSONObject getSettleInfo(PayPlaceOrder.SettleInfo settleInfo) {
|
||||
JSONObject settleJsonObject = new JSONObject();
|
||||
settleJsonObject.put("profit_sharing", settleInfo.getProfitSharing());
|
||||
return settleJsonObject;
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package ink.wgink.module.wechat.service.pay.v3.jsapi;
|
||||
|
||||
import ink.wgink.module.wechat.pojo.pay.v3.jsapi.pojo.PayPlaceOrder;
|
||||
|
||||
/**
|
||||
* @ClassName: IJsapiService
|
||||
* @Description: Jsapi业务
|
||||
@ -8,4 +10,13 @@ package ink.wgink.module.wechat.service.pay.v3.jsapi;
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public interface IJsapiService {
|
||||
|
||||
/**
|
||||
* 下单
|
||||
*
|
||||
* @param payPlaceOrder
|
||||
* @return 预支付交易会话标识,预支付交易会话标识。用于后续接口调用中使用,该值有效期为2小时
|
||||
*/
|
||||
String placeOrder(PayPlaceOrder payPlaceOrder) throws Exception;
|
||||
|
||||
}
|
||||
|
@ -1,8 +1,20 @@
|
||||
package ink.wgink.module.wechat.service.pay.v3.jsapi.impl;
|
||||
|
||||
import ink.wgink.common.base.DefaultBaseService;
|
||||
import ink.wgink.module.wechat.enums.PayAuthorizationTypeEnum;
|
||||
import ink.wgink.module.wechat.pojo.pay.v3.jsapi.pojo.PayPlaceOrder;
|
||||
import ink.wgink.module.wechat.request.pay.v3.jsapi.PlaceOrderPayRequestImpl;
|
||||
import ink.wgink.module.wechat.pojo.pay.v3.jsapi.pojo.PayPrepay;
|
||||
import ink.wgink.module.wechat.service.pay.v3.jsapi.IJsapiService;
|
||||
import ink.wgink.module.wechat.utils.pay.PayCertificateUtil;
|
||||
import ink.wgink.properties.wechat.pay.v3.PayProperties;
|
||||
import ink.wgink.util.BeanPropertyCheckUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
/**
|
||||
* @ClassName: JsapiServiceImpl
|
||||
@ -14,6 +26,24 @@ import org.springframework.stereotype.Service;
|
||||
@Service
|
||||
public class JsapiServiceImpl extends DefaultBaseService implements IJsapiService {
|
||||
|
||||
@Autowired
|
||||
private PayProperties payProperties;
|
||||
|
||||
@Override
|
||||
public String placeOrder(PayPlaceOrder payPlaceOrder) throws Exception {
|
||||
BeanPropertyCheckUtil.checkField(payPlaceOrder);
|
||||
String urlSuffix = "/v3/pay/transactions/jsapi";
|
||||
String url = "https://api.mch.weixin.qq.com" + urlSuffix;
|
||||
|
||||
// 获得证书
|
||||
X509Certificate certificate = PayCertificateUtil.getCertificate(new FileInputStream(payProperties.getCertificatePath()));
|
||||
String serialNumber = certificate.getSerialNumber().toString(16);
|
||||
|
||||
PlaceOrderPayRequestImpl placeOrderPayRequest = new PlaceOrderPayRequestImpl();
|
||||
String body = placeOrderPayRequest.bodyJsonString(payPlaceOrder);
|
||||
String authorization = placeOrderPayRequest.getAuthorization(RequestMethod.POST, urlSuffix, serialNumber, payProperties, body, PayAuthorizationTypeEnum.WECHATPAY2_SHA256_RSA2048);
|
||||
// 请求获得结果
|
||||
PayPrepay payPrepay = placeOrderPayRequest.post(url, authorization, serialNumber, body);
|
||||
return payPrepay.getPrepayId();
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,10 @@ package ink.wgink.module.wechat.startup;
|
||||
|
||||
import ink.wgink.module.wechat.manager.MiniappManager;
|
||||
import ink.wgink.module.wechat.manager.OfficialAccountAccessTokenManager;
|
||||
import ink.wgink.module.wechat.manager.pay.v3.PayManager;
|
||||
import ink.wgink.properties.wechat.miniapp.MiniappProperties;
|
||||
import ink.wgink.properties.wechat.official.account.OfficialAccountProperties;
|
||||
import ink.wgink.properties.wechat.pay.v3.PayProperties;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -29,9 +31,14 @@ public class WechatStartUp implements ApplicationRunner {
|
||||
private MiniappProperties miniAppProperties;
|
||||
@Autowired
|
||||
private OfficialAccountProperties officialAccountProperties;
|
||||
@Autowired
|
||||
private PayProperties payProperties;
|
||||
|
||||
@Override
|
||||
public void run(ApplicationArguments args) throws Exception {
|
||||
if (payProperties.getActive()) {
|
||||
PayManager.getInstance().setX509Certificate(payProperties.getCertificatePath());
|
||||
}
|
||||
new Thread(() -> {
|
||||
refreshOfficialAccountAccessToken();
|
||||
}).start();
|
||||
|
@ -42,7 +42,6 @@ public class PayPrivateKeyUtil {
|
||||
apiClientKeySB.append(line);
|
||||
}
|
||||
String originalKey = apiClientKeySB.toString();
|
||||
System.out.println(originalKey);
|
||||
String privateKey = originalKey
|
||||
.replace("-----BEGIN PRIVATE KEY-----", "")
|
||||
.replace("-----END PRIVATE KEY-----", "")
|
||||
|
Loading…
Reference in New Issue
Block a user