1. 添加模拟交易接口
2. 完善支付完成通知接口业务逻辑 3. 新增支付完成通知自定义处理业务接口 4. 添加小程序支付签名生成 5. 完善Jsapi支付预处理逻辑 6. 完善支付业务结构封装
This commit is contained in:
parent
e263433ec7
commit
226483602d
@ -0,0 +1,57 @@
|
|||||||
|
package ink.wgink.module.wechat.controller.app.miniapp;
|
||||||
|
|
||||||
|
import ink.wgink.interfaces.consts.ISystemConstant;
|
||||||
|
import ink.wgink.module.wechat.pojo.pay.v3.PaySign;
|
||||||
|
import ink.wgink.module.wechat.pojo.pay.v3.jsapi.pojo.PayPlaceOrder;
|
||||||
|
import ink.wgink.module.wechat.service.pay.v3.jsapi.IJsapiService;
|
||||||
|
import ink.wgink.pojo.result.ErrorResult;
|
||||||
|
import ink.wgink.util.OrderUtil;
|
||||||
|
import io.swagger.annotations.*;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestHeader;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ClassName: MiniappPayAppController
|
||||||
|
* @Description: 小程序支付
|
||||||
|
* @Author: wanggeng
|
||||||
|
* @Date: 2021/8/20 5:48 下午
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
@Api(tags = ISystemConstant.API_TAGS_APP_PREFIX + "小程序用户")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(ISystemConstant.APP_PREFIX + "/miniapp/pay")
|
||||||
|
public class MiniappPayAppController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IJsapiService jsapiService;
|
||||||
|
|
||||||
|
@ApiOperation(value = "下订单测试", notes = "下订单测试接口")
|
||||||
|
@ApiImplicitParams({
|
||||||
|
@ApiImplicitParam(name = "token", value = "token", paramType = "header")
|
||||||
|
})
|
||||||
|
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
|
||||||
|
@PostMapping("save-place-order-demo")
|
||||||
|
public PaySign savePlaceOrderDemo(@RequestHeader("token") String token) throws Exception {
|
||||||
|
String atomicOrder = OrderUtil.getAtomicOrder("0001");
|
||||||
|
System.out.println("订单号:" + atomicOrder);
|
||||||
|
|
||||||
|
PayPlaceOrder payPlaceOrder = new PayPlaceOrder();
|
||||||
|
payPlaceOrder.setDescription("测试商品");
|
||||||
|
payPlaceOrder.setOutTradeNo(atomicOrder);
|
||||||
|
payPlaceOrder.setNotifyUrl("https://www.wgink.ink/study/wechat/pay/notice");
|
||||||
|
|
||||||
|
PayPlaceOrder.Amount amount = new PayPlaceOrder.Amount();
|
||||||
|
amount.setTotal(1);
|
||||||
|
payPlaceOrder.setAmount(amount);
|
||||||
|
|
||||||
|
PayPlaceOrder.Payer payer = new PayPlaceOrder.Payer();
|
||||||
|
payer.setOpenid("");
|
||||||
|
payPlaceOrder.setPayer(payer);
|
||||||
|
|
||||||
|
return jsapiService.placeOrder(payPlaceOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
package ink.wgink.module.wechat.controller.wechat.pay.v3;
|
||||||
|
|
||||||
|
import ink.wgink.annotation.CheckRequestBodyAnnotation;
|
||||||
|
import ink.wgink.common.base.DefaultBaseController;
|
||||||
|
import ink.wgink.interfaces.consts.ISystemConstant;
|
||||||
|
import ink.wgink.module.wechat.pojo.pay.v3.PayErrorResponse;
|
||||||
|
import ink.wgink.module.wechat.pojo.pay.v3.PayNotice;
|
||||||
|
import ink.wgink.module.wechat.service.pay.v3.IPayService;
|
||||||
|
import io.swagger.annotations.*;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ClassName: PayController
|
||||||
|
* @Description: 微信支付
|
||||||
|
* @Author: wanggeng
|
||||||
|
* @Date: 2021/8/19 9:36 下午
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
@Api(tags = ISystemConstant.API_TAGS_WECHAT_PREFIX + "微信公众号")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(ISystemConstant.WECHAT_PREFIX + "/pay")
|
||||||
|
public class PayController extends DefaultBaseController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IPayService payService;
|
||||||
|
|
||||||
|
@ApiOperation(value = "通知支付结果", notes = "有微信支付主动发起的支付结果通知接口")
|
||||||
|
@ApiImplicitParams({
|
||||||
|
@ApiImplicitParam(name = "Wechatpay-Signature", value = "来自微信的签名值", paramType = "header")
|
||||||
|
})
|
||||||
|
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = PayErrorResponse.class)})
|
||||||
|
@PostMapping("notice")
|
||||||
|
@CheckRequestBodyAnnotation
|
||||||
|
public void notice(HttpServletRequest request, HttpServletResponse response,
|
||||||
|
@RequestHeader("Wechatpay-Signature") String wechatpaySignature, @RequestBody PayNotice payNotice) {
|
||||||
|
payService.notice(request, response, wechatpaySignature, payNotice);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -52,6 +52,10 @@ public class OfficialAccountAccessTokenManager {
|
|||||||
this.officialAccountAccessToken = officialAccountAccessToken;
|
this.officialAccountAccessToken = officialAccountAccessToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public OfficialAccountAccessToken getAccessToken() {
|
||||||
|
return officialAccountAccessToken;
|
||||||
|
}
|
||||||
|
|
||||||
private static class AccessTokenManagerFactory {
|
private static class AccessTokenManagerFactory {
|
||||||
public static OfficialAccountAccessTokenManager officialAccountAccessTokenManager = new OfficialAccountAccessTokenManager();
|
public static OfficialAccountAccessTokenManager officialAccountAccessTokenManager = new OfficialAccountAccessTokenManager();
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,168 @@
|
|||||||
|
package ink.wgink.module.wechat.pojo.pay.v3;
|
||||||
|
|
||||||
|
import ink.wgink.annotation.CheckBeanAnnotation;
|
||||||
|
import ink.wgink.annotation.CheckEmptyAnnotation;
|
||||||
|
import ink.wgink.annotation.CheckNumberAnnotation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ClassName: PayNotice
|
||||||
|
* @Description: 支付通知
|
||||||
|
* @Author: wanggeng
|
||||||
|
* @Date: 2021/8/20 8:07 上午
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
public class PayNotice {
|
||||||
|
|
||||||
|
@CheckEmptyAnnotation(name = "通知ID")
|
||||||
|
private String id;
|
||||||
|
@CheckEmptyAnnotation(name = "通知创建时间")
|
||||||
|
private String create_time;
|
||||||
|
@CheckEmptyAnnotation(name = "通知类型")
|
||||||
|
private String event_type;
|
||||||
|
@CheckEmptyAnnotation(name = "通知数据类型")
|
||||||
|
private String resource_type;
|
||||||
|
@CheckNumberAnnotation(name = "通知数据")
|
||||||
|
@CheckBeanAnnotation
|
||||||
|
private Resource resource;
|
||||||
|
@CheckEmptyAnnotation(name = "回调摘要")
|
||||||
|
private String summary;
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id == null ? "" : id.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCreate_time() {
|
||||||
|
return create_time == null ? "" : create_time.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreate_time(String create_time) {
|
||||||
|
this.create_time = create_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEvent_type() {
|
||||||
|
return event_type == null ? "" : event_type.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEvent_type(String event_type) {
|
||||||
|
this.event_type = event_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getResource_type() {
|
||||||
|
return resource_type == null ? "" : resource_type.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResource_type(String resource_type) {
|
||||||
|
this.resource_type = resource_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Resource getResource() {
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResource(Resource resource) {
|
||||||
|
this.resource = resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSummary() {
|
||||||
|
return summary == null ? "" : summary.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSummary(String summary) {
|
||||||
|
this.summary = summary;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
final StringBuilder sb = new StringBuilder("{");
|
||||||
|
sb.append("\"id\":\"")
|
||||||
|
.append(id).append('\"');
|
||||||
|
sb.append(",\"create_time\":\"")
|
||||||
|
.append(create_time).append('\"');
|
||||||
|
sb.append(",\"event_type\":\"")
|
||||||
|
.append(event_type).append('\"');
|
||||||
|
sb.append(",\"resource_type\":\"")
|
||||||
|
.append(resource_type).append('\"');
|
||||||
|
sb.append(",\"resource\":")
|
||||||
|
.append(resource);
|
||||||
|
sb.append(",\"summary\":\"")
|
||||||
|
.append(summary).append('\"');
|
||||||
|
sb.append('}');
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Resource {
|
||||||
|
@CheckEmptyAnnotation(name = "加密算法类型")
|
||||||
|
private String algorithm;
|
||||||
|
@CheckEmptyAnnotation(name = "数据密文")
|
||||||
|
private String ciphertext;
|
||||||
|
/**
|
||||||
|
* 附加数据
|
||||||
|
*/
|
||||||
|
private String original_type;
|
||||||
|
@CheckEmptyAnnotation(name = "原始类型")
|
||||||
|
private String associated_data;
|
||||||
|
@CheckEmptyAnnotation(name = "随机")
|
||||||
|
private String nonce;
|
||||||
|
|
||||||
|
public String getAlgorithm() {
|
||||||
|
return algorithm == null ? "" : algorithm.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAlgorithm(String algorithm) {
|
||||||
|
this.algorithm = algorithm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCiphertext() {
|
||||||
|
return ciphertext == null ? "" : ciphertext.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCiphertext(String ciphertext) {
|
||||||
|
this.ciphertext = ciphertext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOriginal_type() {
|
||||||
|
return original_type == null ? "" : original_type.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOriginal_type(String original_type) {
|
||||||
|
this.original_type = original_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAssociated_data() {
|
||||||
|
return associated_data == null ? "" : associated_data.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAssociated_data(String associated_data) {
|
||||||
|
this.associated_data = associated_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNonce() {
|
||||||
|
return nonce == null ? "" : nonce.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNonce(String nonce) {
|
||||||
|
this.nonce = nonce;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
final StringBuilder sb = new StringBuilder("{");
|
||||||
|
sb.append("\"algorithm\":\"")
|
||||||
|
.append(algorithm).append('\"');
|
||||||
|
sb.append(",\"ciphertext\":\"")
|
||||||
|
.append(ciphertext).append('\"');
|
||||||
|
sb.append(",\"original_type\":\"")
|
||||||
|
.append(original_type).append('\"');
|
||||||
|
sb.append(",\"associated_data\":\"")
|
||||||
|
.append(associated_data).append('\"');
|
||||||
|
sb.append(",\"nonce\":\"")
|
||||||
|
.append(nonce).append('\"');
|
||||||
|
sb.append('}');
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,590 @@
|
|||||||
|
package ink.wgink.module.wechat.pojo.pay.v3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ClassName: PayNoticeCiphertext
|
||||||
|
* @Description: 支付通知密文
|
||||||
|
* @Author: wanggeng
|
||||||
|
* @Date: 2021/8/20 3:02 下午
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
public class PayNoticeCiphertext {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用ID
|
||||||
|
*/
|
||||||
|
private String appId;
|
||||||
|
/**
|
||||||
|
* 商户号
|
||||||
|
*/
|
||||||
|
private String mchid;
|
||||||
|
/**
|
||||||
|
* 商户订单号
|
||||||
|
*/
|
||||||
|
private String out_trade_no;
|
||||||
|
/**
|
||||||
|
* 微信支付订单号
|
||||||
|
*/
|
||||||
|
private String transaction_id;
|
||||||
|
/**
|
||||||
|
* 交易类型
|
||||||
|
*/
|
||||||
|
private String trade_type;
|
||||||
|
/**
|
||||||
|
* 交易状态
|
||||||
|
*/
|
||||||
|
private String trade_state;
|
||||||
|
/**
|
||||||
|
* 交易状态描述
|
||||||
|
*/
|
||||||
|
private String trade_state_desc;
|
||||||
|
/**
|
||||||
|
* 付款银行
|
||||||
|
*/
|
||||||
|
private String bank_type;
|
||||||
|
/**
|
||||||
|
* 附加数据
|
||||||
|
*/
|
||||||
|
private String attach;
|
||||||
|
/**
|
||||||
|
* 支付完成时间
|
||||||
|
*/
|
||||||
|
private String success_time;
|
||||||
|
/**
|
||||||
|
* 支付者
|
||||||
|
*/
|
||||||
|
private Payer payer;
|
||||||
|
/**
|
||||||
|
* 订单金额
|
||||||
|
*/
|
||||||
|
private Amount amount;
|
||||||
|
/**
|
||||||
|
* 场景信息
|
||||||
|
*/
|
||||||
|
private SceneInfo scene_info;
|
||||||
|
/**
|
||||||
|
* 优惠功能
|
||||||
|
*/
|
||||||
|
private PromotionDetail promotion_detail;
|
||||||
|
|
||||||
|
public String getAppId() {
|
||||||
|
return appId == null ? "" : appId.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAppId(String appId) {
|
||||||
|
this.appId = appId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMchid() {
|
||||||
|
return mchid == null ? "" : mchid.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMchid(String mchid) {
|
||||||
|
this.mchid = mchid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOut_trade_no() {
|
||||||
|
return out_trade_no == null ? "" : out_trade_no.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOut_trade_no(String out_trade_no) {
|
||||||
|
this.out_trade_no = out_trade_no;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTransaction_id() {
|
||||||
|
return transaction_id == null ? "" : transaction_id.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTransaction_id(String transaction_id) {
|
||||||
|
this.transaction_id = transaction_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTrade_type() {
|
||||||
|
return trade_type == null ? "" : trade_type.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTrade_type(String trade_type) {
|
||||||
|
this.trade_type = trade_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTrade_state() {
|
||||||
|
return trade_state == null ? "" : trade_state.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTrade_state(String trade_state) {
|
||||||
|
this.trade_state = trade_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTrade_state_desc() {
|
||||||
|
return trade_state_desc == null ? "" : trade_state_desc.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTrade_state_desc(String trade_state_desc) {
|
||||||
|
this.trade_state_desc = trade_state_desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBank_type() {
|
||||||
|
return bank_type == null ? "" : bank_type.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBank_type(String bank_type) {
|
||||||
|
this.bank_type = bank_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAttach() {
|
||||||
|
return attach == null ? "" : attach.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAttach(String attach) {
|
||||||
|
this.attach = attach;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSuccess_time() {
|
||||||
|
return success_time == null ? "" : success_time.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSuccess_time(String success_time) {
|
||||||
|
this.success_time = success_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Payer getPayer() {
|
||||||
|
return payer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPayer(Payer payer) {
|
||||||
|
this.payer = payer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Amount getAmount() {
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAmount(Amount amount) {
|
||||||
|
this.amount = amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SceneInfo getScene_info() {
|
||||||
|
return scene_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScene_info(SceneInfo scene_info) {
|
||||||
|
this.scene_info = scene_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PromotionDetail getPromotion_detail() {
|
||||||
|
return promotion_detail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPromotion_detail(PromotionDetail promotion_detail) {
|
||||||
|
this.promotion_detail = promotion_detail;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
final StringBuilder sb = new StringBuilder("{");
|
||||||
|
sb.append("\"appId\":\"")
|
||||||
|
.append(appId).append('\"');
|
||||||
|
sb.append(",\"mchid\":\"")
|
||||||
|
.append(mchid).append('\"');
|
||||||
|
sb.append(",\"out_trade_no\":\"")
|
||||||
|
.append(out_trade_no).append('\"');
|
||||||
|
sb.append(",\"transaction_id\":\"")
|
||||||
|
.append(transaction_id).append('\"');
|
||||||
|
sb.append(",\"trade_type\":\"")
|
||||||
|
.append(trade_type).append('\"');
|
||||||
|
sb.append(",\"trade_state\":\"")
|
||||||
|
.append(trade_state).append('\"');
|
||||||
|
sb.append(",\"trade_state_desc\":\"")
|
||||||
|
.append(trade_state_desc).append('\"');
|
||||||
|
sb.append(",\"bank_type\":\"")
|
||||||
|
.append(bank_type).append('\"');
|
||||||
|
sb.append(",\"attach\":\"")
|
||||||
|
.append(attach).append('\"');
|
||||||
|
sb.append(",\"success_time\":\"")
|
||||||
|
.append(success_time).append('\"');
|
||||||
|
sb.append(",\"payer\":")
|
||||||
|
.append(payer);
|
||||||
|
sb.append(",\"amount\":")
|
||||||
|
.append(amount);
|
||||||
|
sb.append(",\"scene_info\":")
|
||||||
|
.append(scene_info);
|
||||||
|
sb.append(",\"promotion_detail\":")
|
||||||
|
.append(promotion_detail);
|
||||||
|
sb.append('}');
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付者
|
||||||
|
*/
|
||||||
|
public static class Payer {
|
||||||
|
/**
|
||||||
|
* 用户标识
|
||||||
|
*/
|
||||||
|
private String openid;
|
||||||
|
|
||||||
|
public String getOpenid() {
|
||||||
|
return openid == null ? "" : openid.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOpenid(String openid) {
|
||||||
|
this.openid = openid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
final StringBuilder sb = new StringBuilder("{");
|
||||||
|
sb.append("\"openid\":\"")
|
||||||
|
.append(openid).append('\"');
|
||||||
|
sb.append('}');
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单金额
|
||||||
|
*/
|
||||||
|
public static class Amount {
|
||||||
|
/**
|
||||||
|
* 总金额
|
||||||
|
*/
|
||||||
|
private int total;
|
||||||
|
/**
|
||||||
|
* 用户支付金额
|
||||||
|
*/
|
||||||
|
private int payer_total;
|
||||||
|
/**
|
||||||
|
* 货币类型
|
||||||
|
*/
|
||||||
|
private String currency;
|
||||||
|
/**
|
||||||
|
* 用户支付币种
|
||||||
|
*/
|
||||||
|
private String payer_currency;
|
||||||
|
|
||||||
|
public int getTotal() {
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTotal(int total) {
|
||||||
|
this.total = total;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPayer_total() {
|
||||||
|
return payer_total;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPayer_total(int payer_total) {
|
||||||
|
this.payer_total = payer_total;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCurrency() {
|
||||||
|
return currency == null ? "" : currency.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrency(String currency) {
|
||||||
|
this.currency = currency;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPayer_currency() {
|
||||||
|
return payer_currency == null ? "" : payer_currency.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPayer_currency(String payer_currency) {
|
||||||
|
this.payer_currency = payer_currency;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
final StringBuilder sb = new StringBuilder("{");
|
||||||
|
sb.append("\"total\":")
|
||||||
|
.append(total);
|
||||||
|
sb.append(",\"payer_total\":")
|
||||||
|
.append(payer_total);
|
||||||
|
sb.append(",\"currency\":\"")
|
||||||
|
.append(currency).append('\"');
|
||||||
|
sb.append(",\"payer_currency\":\"")
|
||||||
|
.append(payer_currency).append('\"');
|
||||||
|
sb.append('}');
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 场景信息
|
||||||
|
*/
|
||||||
|
public static class SceneInfo {
|
||||||
|
/**
|
||||||
|
* 商户端设备号
|
||||||
|
*/
|
||||||
|
private String device_id;
|
||||||
|
|
||||||
|
public String getDevice_id() {
|
||||||
|
return device_id == null ? "" : device_id.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDevice_id(String device_id) {
|
||||||
|
this.device_id = device_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
final StringBuilder sb = new StringBuilder("{");
|
||||||
|
sb.append("\"device_id\":\"")
|
||||||
|
.append(device_id).append('\"');
|
||||||
|
sb.append('}');
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 优惠功能
|
||||||
|
*/
|
||||||
|
public static class PromotionDetail {
|
||||||
|
/**
|
||||||
|
* 券ID
|
||||||
|
*/
|
||||||
|
private String coupon_id;
|
||||||
|
/**
|
||||||
|
* 优惠名称
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
/**
|
||||||
|
* 优惠范围
|
||||||
|
*/
|
||||||
|
private String scope;
|
||||||
|
/**
|
||||||
|
* 优惠类型
|
||||||
|
*/
|
||||||
|
private String type;
|
||||||
|
/**
|
||||||
|
* 优惠券面额
|
||||||
|
*/
|
||||||
|
private Integer amount;
|
||||||
|
/**
|
||||||
|
* 活动ID
|
||||||
|
*/
|
||||||
|
private String stock_id;
|
||||||
|
/**
|
||||||
|
* 微信出资
|
||||||
|
*/
|
||||||
|
private Integer wechatpay_contribute;
|
||||||
|
/**
|
||||||
|
* 商户出资
|
||||||
|
*/
|
||||||
|
private Integer merchant_contribute;
|
||||||
|
/**
|
||||||
|
* 其他出资
|
||||||
|
*/
|
||||||
|
private Integer other_contribute;
|
||||||
|
/**
|
||||||
|
* 优惠币种
|
||||||
|
*/
|
||||||
|
private String currency;
|
||||||
|
/**
|
||||||
|
* 单品列表
|
||||||
|
*/
|
||||||
|
private GoodsDetail goods_detail;
|
||||||
|
|
||||||
|
public String getCoupon_id() {
|
||||||
|
return coupon_id == null ? "" : coupon_id.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCoupon_id(String coupon_id) {
|
||||||
|
this.coupon_id = coupon_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name == null ? "" : name.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getScope() {
|
||||||
|
return scope == null ? "" : scope.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScope(String scope) {
|
||||||
|
this.scope = scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type == null ? "" : type.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getAmount() {
|
||||||
|
return amount == null ? 0 : amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAmount(Integer amount) {
|
||||||
|
this.amount = amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStock_id() {
|
||||||
|
return stock_id == null ? "" : stock_id.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStock_id(String stock_id) {
|
||||||
|
this.stock_id = stock_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getWechatpay_contribute() {
|
||||||
|
return wechatpay_contribute == null ? 0 : wechatpay_contribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWechatpay_contribute(Integer wechatpay_contribute) {
|
||||||
|
this.wechatpay_contribute = wechatpay_contribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getMerchant_contribute() {
|
||||||
|
return merchant_contribute == null ? 0 : merchant_contribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMerchant_contribute(Integer merchant_contribute) {
|
||||||
|
this.merchant_contribute = merchant_contribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getOther_contribute() {
|
||||||
|
return other_contribute == null ? 0 : other_contribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOther_contribute(Integer other_contribute) {
|
||||||
|
this.other_contribute = other_contribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCurrency() {
|
||||||
|
return currency == null ? "" : currency.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrency(String currency) {
|
||||||
|
this.currency = currency;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GoodsDetail getGoods_detail() {
|
||||||
|
return goods_detail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGoods_detail(GoodsDetail goods_detail) {
|
||||||
|
this.goods_detail = goods_detail;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
final StringBuilder sb = new StringBuilder("{");
|
||||||
|
sb.append("\"coupon_id\":\"")
|
||||||
|
.append(coupon_id).append('\"');
|
||||||
|
sb.append(",\"name\":\"")
|
||||||
|
.append(name).append('\"');
|
||||||
|
sb.append(",\"scope\":\"")
|
||||||
|
.append(scope).append('\"');
|
||||||
|
sb.append(",\"type\":\"")
|
||||||
|
.append(type).append('\"');
|
||||||
|
sb.append(",\"amount\":")
|
||||||
|
.append(amount);
|
||||||
|
sb.append(",\"stock_id\":\"")
|
||||||
|
.append(stock_id).append('\"');
|
||||||
|
sb.append(",\"wechatpay_contribute\":")
|
||||||
|
.append(wechatpay_contribute);
|
||||||
|
sb.append(",\"merchant_contribute\":")
|
||||||
|
.append(merchant_contribute);
|
||||||
|
sb.append(",\"other_contribute\":")
|
||||||
|
.append(other_contribute);
|
||||||
|
sb.append(",\"currency\":\"")
|
||||||
|
.append(currency).append('\"');
|
||||||
|
sb.append(",\"goods_detail\":")
|
||||||
|
.append(goods_detail);
|
||||||
|
sb.append('}');
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单品列表
|
||||||
|
*/
|
||||||
|
public static class GoodsDetail {
|
||||||
|
/**
|
||||||
|
* 商品编码
|
||||||
|
*/
|
||||||
|
private String goods_id;
|
||||||
|
/**
|
||||||
|
* 商品数量
|
||||||
|
*/
|
||||||
|
private Integer quantity;
|
||||||
|
/**
|
||||||
|
* 商品单价
|
||||||
|
*/
|
||||||
|
private Integer unit_price;
|
||||||
|
/**
|
||||||
|
* 商品优惠金额
|
||||||
|
*/
|
||||||
|
private Integer discount_amount;
|
||||||
|
/**
|
||||||
|
* 商品备注
|
||||||
|
*/
|
||||||
|
private String goods_remark;
|
||||||
|
|
||||||
|
public String getGoods_id() {
|
||||||
|
return goods_id == null ? "" : goods_id.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGoods_id(String goods_id) {
|
||||||
|
this.goods_id = goods_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getQuantity() {
|
||||||
|
return quantity == null ? 0 : quantity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setQuantity(Integer quantity) {
|
||||||
|
this.quantity = quantity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getUnit_price() {
|
||||||
|
return unit_price == null ? 0 : unit_price;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUnit_price(Integer unit_price) {
|
||||||
|
this.unit_price = unit_price;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getDiscount_amount() {
|
||||||
|
return discount_amount == null ? 0 : discount_amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDiscount_amount(Integer discount_amount) {
|
||||||
|
this.discount_amount = discount_amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGoods_remark() {
|
||||||
|
return goods_remark == null ? "" : goods_remark.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGoods_remark(String goods_remark) {
|
||||||
|
this.goods_remark = goods_remark;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
final StringBuilder sb = new StringBuilder("{");
|
||||||
|
sb.append("\"goods_id\":\"")
|
||||||
|
.append(goods_id).append('\"');
|
||||||
|
sb.append(",\"quantity\":")
|
||||||
|
.append(quantity);
|
||||||
|
sb.append(",\"unit_price\":")
|
||||||
|
.append(unit_price);
|
||||||
|
sb.append(",\"discount_amount\":")
|
||||||
|
.append(discount_amount);
|
||||||
|
sb.append(",\"goods_remark\":\"")
|
||||||
|
.append(goods_remark).append('\"');
|
||||||
|
sb.append('}');
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,77 @@
|
|||||||
|
package ink.wgink.module.wechat.pojo.pay.v3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ClassName: PaySign
|
||||||
|
* @Description: 支付签名
|
||||||
|
* @Author: wanggeng
|
||||||
|
* @Date: 2021/8/20 5:41 下午
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
public class PaySign {
|
||||||
|
|
||||||
|
private String appId;
|
||||||
|
private String timestamp;
|
||||||
|
private String nonceStr;
|
||||||
|
/**
|
||||||
|
* 预支付交易会话标识,预支付交易会话标识。用于后续接口调用中使用,该值有效期为2小时
|
||||||
|
*/
|
||||||
|
private String prepayId;
|
||||||
|
private String paySign;
|
||||||
|
|
||||||
|
public String getAppId() {
|
||||||
|
return appId == null ? "" : appId.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAppId(String appId) {
|
||||||
|
this.appId = appId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTimestamp() {
|
||||||
|
return timestamp == null ? "" : timestamp.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTimestamp(String timestamp) {
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNonceStr() {
|
||||||
|
return nonceStr == null ? "" : nonceStr.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNonceStr(String nonceStr) {
|
||||||
|
this.nonceStr = nonceStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPrepayId() {
|
||||||
|
return prepayId == null ? "" : prepayId.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPrepayId(String prepayId) {
|
||||||
|
this.prepayId = prepayId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPaySign() {
|
||||||
|
return paySign == null ? "" : paySign.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPaySign(String paySign) {
|
||||||
|
this.paySign = paySign;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
final StringBuilder sb = new StringBuilder("{");
|
||||||
|
sb.append("\"appId\":\"")
|
||||||
|
.append(appId).append('\"');
|
||||||
|
sb.append(",\"timestamp\":\"")
|
||||||
|
.append(timestamp).append('\"');
|
||||||
|
sb.append(",\"nonceStr\":\"")
|
||||||
|
.append(nonceStr).append('\"');
|
||||||
|
sb.append(",\"prepayId\":\"")
|
||||||
|
.append(prepayId).append('\"');
|
||||||
|
sb.append(",\"paySign\":\"")
|
||||||
|
.append(paySign).append('\"');
|
||||||
|
sb.append('}');
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -30,14 +30,15 @@ public class PlaceOrderPayRequestImpl extends AbstractPayRequest<PayPlaceOrder,
|
|||||||
bodyObject.put("notify_url", payPlaceOrder.getNotifyUrl());
|
bodyObject.put("notify_url", payPlaceOrder.getNotifyUrl());
|
||||||
bodyObject.put("goods_tag", payPlaceOrder.getGoodsTag());
|
bodyObject.put("goods_tag", payPlaceOrder.getGoodsTag());
|
||||||
bodyObject.put("amount", getAmountJsonObject(payPlaceOrder.getAmount()));
|
bodyObject.put("amount", getAmountJsonObject(payPlaceOrder.getAmount()));
|
||||||
|
bodyObject.put("payer", getPayer(payPlaceOrder.getPayer()));
|
||||||
if (payPlaceOrder.getDetail() != null) {
|
if (payPlaceOrder.getDetail() != null) {
|
||||||
bodyObject.put("detail", payPlaceOrder.getDetail());
|
bodyObject.put("detail", getDetail(payPlaceOrder.getDetail()));
|
||||||
}
|
}
|
||||||
if (payPlaceOrder.getSceneInfo() != null) {
|
if (payPlaceOrder.getSceneInfo() != null) {
|
||||||
bodyObject.put("scene_info", payPlaceOrder.getSceneInfo());
|
bodyObject.put("scene_info", getSceneInfo(payPlaceOrder.getSceneInfo()));
|
||||||
}
|
}
|
||||||
if (payPlaceOrder.getSettleInfo() != null) {
|
if (payPlaceOrder.getSettleInfo() != null) {
|
||||||
bodyObject.put("settle_info", payPlaceOrder.getSettleInfo());
|
bodyObject.put("settle_info", getSettleInfo(payPlaceOrder.getSettleInfo()));
|
||||||
}
|
}
|
||||||
return bodyObject.toJSONString();
|
return bodyObject.toJSONString();
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
package ink.wgink.module.wechat.service.pay.v3;
|
||||||
|
|
||||||
|
import ink.wgink.module.wechat.pojo.pay.v3.PayNoticeCiphertext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ClassName: IPayNoticeService
|
||||||
|
* @Description: 支付通知业务,完成支付后,微信支付发起异步通知,实现该类完成业务处理
|
||||||
|
* @Author: wanggeng
|
||||||
|
* @Date: 2021/8/20 4:45 下午
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
public interface IPayNoticeService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理支付通知结果,该方法在所有校验通过,加密文本解密之后调用。
|
||||||
|
*
|
||||||
|
* @param payNoticeCiphertext
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
void handle(PayNoticeCiphertext payNoticeCiphertext) throws Exception;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package ink.wgink.module.wechat.service.pay.v3;
|
||||||
|
|
||||||
|
import ink.wgink.module.wechat.pojo.pay.v3.PayNotice;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ClassName: IPayService
|
||||||
|
* @Description: 支付
|
||||||
|
* @Author: wanggeng
|
||||||
|
* @Date: 2021/8/20 8:15 上午
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
public interface IPayService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付通知
|
||||||
|
*
|
||||||
|
* @param request
|
||||||
|
* @param response
|
||||||
|
* @param wechatpaySignature
|
||||||
|
* @param payNotice
|
||||||
|
*/
|
||||||
|
void notice(HttpServletRequest request, HttpServletResponse response, String wechatpaySignature, PayNotice payNotice);
|
||||||
|
}
|
@ -0,0 +1,107 @@
|
|||||||
|
package ink.wgink.module.wechat.service.pay.v3.impl;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import ink.wgink.common.base.DefaultBaseService;
|
||||||
|
import ink.wgink.module.wechat.enums.PayErrorMsgEnum;
|
||||||
|
import ink.wgink.module.wechat.pojo.pay.v3.PayErrorResponse;
|
||||||
|
import ink.wgink.module.wechat.pojo.pay.v3.PayNotice;
|
||||||
|
import ink.wgink.module.wechat.pojo.pay.v3.PayNoticeCiphertext;
|
||||||
|
import ink.wgink.module.wechat.request.pay.v3.AbstractPayRequest;
|
||||||
|
import ink.wgink.module.wechat.service.pay.v3.IPayNoticeService;
|
||||||
|
import ink.wgink.module.wechat.service.pay.v3.IPayService;
|
||||||
|
import ink.wgink.module.wechat.utils.pay.PayVerifyUtil;
|
||||||
|
import ink.wgink.properties.wechat.pay.v3.PayProperties;
|
||||||
|
import org.joda.time.DateTime;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ClassName: IPayServiceImpl
|
||||||
|
* @Description: 支付
|
||||||
|
* @Author: wanggeng
|
||||||
|
* @Date: 2021/8/20 8:15 上午
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class IPayServiceImpl extends DefaultBaseService implements IPayService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PayProperties payProperties;
|
||||||
|
@Autowired
|
||||||
|
private IPayNoticeService payNoticeService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notice(HttpServletRequest request, HttpServletResponse response, String wechatpaySignature, PayNotice payNotice) {
|
||||||
|
String nonce = payNotice.getResource().getNonce();
|
||||||
|
DateTime createTimeDateTime = DateTime.parse(payNotice.getCreate_time());
|
||||||
|
long millis = createTimeDateTime.getMillis();
|
||||||
|
String payNoticeJsonString = JSONObject.toJSONString(payNotice);
|
||||||
|
|
||||||
|
try {
|
||||||
|
LOG.debug("验证签名");
|
||||||
|
boolean checkVerify = PayVerifyUtil.verifySignature(wechatpaySignature, payNoticeJsonString, nonce, String.valueOf(millis), new FileInputStream(payProperties.getCertificatePath()));
|
||||||
|
if (!checkVerify) {
|
||||||
|
errorResult(response, PayErrorMsgEnum.SIGN_ERROR_401);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG.debug("解密内容");
|
||||||
|
PayNotice.Resource resource = payNotice.getResource();
|
||||||
|
AbstractPayRequest.AesUtil aesUtil = new AbstractPayRequest.AesUtil(payProperties.getApiV3Secretkey().getBytes(StandardCharsets.UTF_8));
|
||||||
|
String payNoticeCiphertextJsonString = aesUtil.decryptToString(resource.getAssociated_data().getBytes(StandardCharsets.UTF_8), resource.getNonce().getBytes(StandardCharsets.UTF_8), resource.getCiphertext());
|
||||||
|
PayNoticeCiphertext payNoticeCiphertext = JSONObject.parseObject(payNoticeCiphertextJsonString, PayNoticeCiphertext.class);
|
||||||
|
payNoticeService.handle(payNoticeCiphertext);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
errorResult(response, PayErrorMsgEnum.ERROR_500);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
successResult(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 错误结果
|
||||||
|
*
|
||||||
|
* @param payErrorMsgEnum
|
||||||
|
*/
|
||||||
|
private void errorResult(HttpServletResponse response, PayErrorMsgEnum payErrorMsgEnum) {
|
||||||
|
PayErrorResponse payErrorResponse = new PayErrorResponse();
|
||||||
|
payErrorResponse.setCode(payErrorMsgEnum.getErrorCode());
|
||||||
|
payErrorResponse.setMessage(payErrorMsgEnum.getSummary());
|
||||||
|
response.setContentType("application/json; charset=UTF-8");
|
||||||
|
response.setStatus(payErrorMsgEnum.getCode());
|
||||||
|
try (PrintWriter writer = response.getWriter()) {
|
||||||
|
writer.println(JSONObject.toJSONString(payErrorResponse));
|
||||||
|
writer.flush();
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 成功结果
|
||||||
|
*/
|
||||||
|
private void successResult(HttpServletResponse response) {
|
||||||
|
response.setContentType("application/json; charset=UTF-8");
|
||||||
|
response.setStatus(HttpStatus.OK.value());
|
||||||
|
JSONObject successJsonObject = new JSONObject();
|
||||||
|
successJsonObject.put("code", "SUCCESS");
|
||||||
|
successJsonObject.put("message", "成功");
|
||||||
|
try (PrintWriter writer = response.getWriter()) {
|
||||||
|
writer.println(successJsonObject.toJSONString());
|
||||||
|
writer.flush();
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package ink.wgink.module.wechat.service.pay.v3.jsapi;
|
package ink.wgink.module.wechat.service.pay.v3.jsapi;
|
||||||
|
|
||||||
|
import ink.wgink.module.wechat.pojo.pay.v3.PaySign;
|
||||||
import ink.wgink.module.wechat.pojo.pay.v3.jsapi.pojo.PayPlaceOrder;
|
import ink.wgink.module.wechat.pojo.pay.v3.jsapi.pojo.PayPlaceOrder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -17,6 +18,6 @@ public interface IJsapiService {
|
|||||||
* @param payPlaceOrder
|
* @param payPlaceOrder
|
||||||
* @return 预支付交易会话标识,预支付交易会话标识。用于后续接口调用中使用,该值有效期为2小时
|
* @return 预支付交易会话标识,预支付交易会话标识。用于后续接口调用中使用,该值有效期为2小时
|
||||||
*/
|
*/
|
||||||
String placeOrder(PayPlaceOrder payPlaceOrder) throws Exception;
|
PaySign placeOrder(PayPlaceOrder payPlaceOrder) throws Exception;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,18 @@ package ink.wgink.module.wechat.service.pay.v3.jsapi.impl;
|
|||||||
|
|
||||||
import ink.wgink.common.base.DefaultBaseService;
|
import ink.wgink.common.base.DefaultBaseService;
|
||||||
import ink.wgink.module.wechat.enums.PayAuthorizationTypeEnum;
|
import ink.wgink.module.wechat.enums.PayAuthorizationTypeEnum;
|
||||||
|
import ink.wgink.module.wechat.pojo.pay.v3.PaySign;
|
||||||
import ink.wgink.module.wechat.pojo.pay.v3.jsapi.pojo.PayPlaceOrder;
|
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.pojo.pay.v3.jsapi.pojo.PayPrepay;
|
||||||
|
import ink.wgink.module.wechat.request.pay.v3.jsapi.PlaceOrderPayRequestImpl;
|
||||||
import ink.wgink.module.wechat.service.pay.v3.jsapi.IJsapiService;
|
import ink.wgink.module.wechat.service.pay.v3.jsapi.IJsapiService;
|
||||||
import ink.wgink.module.wechat.utils.pay.PayCertificateUtil;
|
import ink.wgink.module.wechat.utils.pay.PayCertificateUtil;
|
||||||
|
import ink.wgink.module.wechat.utils.pay.PayPrivateKeyUtil;
|
||||||
|
import ink.wgink.properties.wechat.miniapp.MiniappProperties;
|
||||||
import ink.wgink.properties.wechat.pay.v3.PayProperties;
|
import ink.wgink.properties.wechat.pay.v3.PayProperties;
|
||||||
import ink.wgink.util.BeanPropertyCheckUtil;
|
import ink.wgink.util.BeanPropertyCheckUtil;
|
||||||
|
import ink.wgink.util.UUIDUtil;
|
||||||
|
import ink.wgink.util.string.WStringUtil;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
@ -28,22 +33,59 @@ public class JsapiServiceImpl extends DefaultBaseService implements IJsapiServic
|
|||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private PayProperties payProperties;
|
private PayProperties payProperties;
|
||||||
|
@Autowired
|
||||||
|
private MiniappProperties miniappProperties;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String placeOrder(PayPlaceOrder payPlaceOrder) throws Exception {
|
public PaySign placeOrder(PayPlaceOrder payPlaceOrder) throws Exception {
|
||||||
|
payPlaceOrder.setAppid(miniappProperties.getAppKey());
|
||||||
|
payPlaceOrder.setMchid(payProperties.getMchid());
|
||||||
BeanPropertyCheckUtil.checkField(payPlaceOrder);
|
BeanPropertyCheckUtil.checkField(payPlaceOrder);
|
||||||
String urlSuffix = "/v3/pay/transactions/jsapi";
|
String urlSuffix = "/v3/pay/transactions/jsapi";
|
||||||
String url = "https://api.mch.weixin.qq.com" + urlSuffix;
|
String url = "https://api.mch.weixin.qq.com" + urlSuffix;
|
||||||
|
|
||||||
// 获得证书
|
LOG.debug("获得证书");
|
||||||
X509Certificate certificate = PayCertificateUtil.getCertificate(new FileInputStream(payProperties.getCertificatePath()));
|
X509Certificate certificate = PayCertificateUtil.getCertificate(new FileInputStream(payProperties.getCertificatePath()));
|
||||||
String serialNumber = certificate.getSerialNumber().toString(16);
|
String serialNumber = certificate.getSerialNumber().toString(16);
|
||||||
|
|
||||||
|
LOG.debug("调用微信支付,发起预支付");
|
||||||
PlaceOrderPayRequestImpl placeOrderPayRequest = new PlaceOrderPayRequestImpl();
|
PlaceOrderPayRequestImpl placeOrderPayRequest = new PlaceOrderPayRequestImpl();
|
||||||
String body = placeOrderPayRequest.bodyJsonString(payPlaceOrder);
|
String body = placeOrderPayRequest.bodyJsonString(payPlaceOrder);
|
||||||
String authorization = placeOrderPayRequest.getAuthorization(RequestMethod.POST, urlSuffix, serialNumber, payProperties, body, PayAuthorizationTypeEnum.WECHATPAY2_SHA256_RSA2048);
|
String authorization = placeOrderPayRequest.getAuthorization(RequestMethod.POST, urlSuffix, serialNumber, payProperties, body, PayAuthorizationTypeEnum.WECHATPAY2_SHA256_RSA2048);
|
||||||
// 请求获得结果
|
LOG.debug("请求获得结果");
|
||||||
PayPrepay payPrepay = placeOrderPayRequest.post(url, authorization, serialNumber, body);
|
PayPrepay payPrepay = placeOrderPayRequest.post(url, authorization, serialNumber, body);
|
||||||
return payPrepay.getPrepayId();
|
|
||||||
|
LOG.debug("生成返回结果");
|
||||||
|
long timestamp = System.currentTimeMillis();
|
||||||
|
String nonceStr = WStringUtil.randomSubStr(UUIDUtil.get32UUID(), 10).toUpperCase();
|
||||||
|
|
||||||
|
PaySign paySign = new PaySign();
|
||||||
|
paySign.setAppId(miniappProperties.getAppKey());
|
||||||
|
paySign.setPrepayId(payPrepay.getPrepayId());
|
||||||
|
paySign.setNonceStr(nonceStr);
|
||||||
|
paySign.setTimestamp(String.valueOf(timestamp));
|
||||||
|
paySign.setPaySign(getPaySign(timestamp, nonceStr, payPrepay.getPrepayId()));
|
||||||
|
return paySign;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得小程序签名
|
||||||
|
*
|
||||||
|
* @param timestamp
|
||||||
|
* @param nonceStr
|
||||||
|
* @param prepayId
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private String getPaySign(long timestamp, String nonceStr, String prepayId) throws Exception {
|
||||||
|
StringBuilder signBS = new StringBuilder();
|
||||||
|
signBS.append(miniappProperties.getAppKey()).append("\n")
|
||||||
|
.append(timestamp).append("\n")
|
||||||
|
.append(nonceStr).append("\n")
|
||||||
|
.append("prepay_id=").append(prepayId).append("\n");
|
||||||
|
String key = PayPrivateKeyUtil.getPrivateKey(payProperties.getKeyPath());
|
||||||
|
// 生成签名
|
||||||
|
return PayPrivateKeyUtil.encryptByPrivateKey(signBS.toString(), key);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package ink.wgink.module.wechat.startup;
|
|||||||
|
|
||||||
import ink.wgink.module.wechat.manager.MiniappManager;
|
import ink.wgink.module.wechat.manager.MiniappManager;
|
||||||
import ink.wgink.module.wechat.manager.OfficialAccountAccessTokenManager;
|
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.miniapp.MiniappProperties;
|
||||||
import ink.wgink.properties.wechat.official.account.OfficialAccountProperties;
|
import ink.wgink.properties.wechat.official.account.OfficialAccountProperties;
|
||||||
import ink.wgink.properties.wechat.pay.v3.PayProperties;
|
import ink.wgink.properties.wechat.pay.v3.PayProperties;
|
||||||
@ -36,9 +35,6 @@ public class WechatStartUp implements ApplicationRunner {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(ApplicationArguments args) throws Exception {
|
public void run(ApplicationArguments args) throws Exception {
|
||||||
if (payProperties.getActive()) {
|
|
||||||
PayManager.getInstance().setX509Certificate(payProperties.getCertificatePath());
|
|
||||||
}
|
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
refreshOfficialAccountAccessToken();
|
refreshOfficialAccountAccessToken();
|
||||||
}).start();
|
}).start();
|
||||||
|
@ -16,9 +16,6 @@ import java.util.*;
|
|||||||
*/
|
*/
|
||||||
public class PaySignAuthorizationUtil {
|
public class PaySignAuthorizationUtil {
|
||||||
|
|
||||||
// 商户号:1609461201
|
|
||||||
// APIv3秘钥:_TSKJ_0471_TSkj_0471_tsKJ_0471__
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param requestMethod 请求方法
|
* @param requestMethod 请求方法
|
||||||
* @param url 请求接口
|
* @param url 请求接口
|
||||||
|
@ -19,11 +19,11 @@ public class PayVerifyUtil {
|
|||||||
/**
|
/**
|
||||||
* 验证签名
|
* 验证签名
|
||||||
*
|
*
|
||||||
* @param signature
|
* @param signature 待验证的签名
|
||||||
* @param body
|
* @param body 应答主体
|
||||||
* @param nonce
|
* @param nonce 随机串
|
||||||
* @param timestamp
|
* @param timestamp 时间戳
|
||||||
* @param certInputStream
|
* @param certInputStream 微信支付平台证书输入流
|
||||||
* @return
|
* @return
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
@ -35,6 +35,15 @@ public class PayVerifyUtil {
|
|||||||
return checkByPublicKey(buildSignMessage, signature, publicKey);
|
return checkByPublicKey(buildSignMessage, signature, publicKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 公钥验证签名
|
||||||
|
*
|
||||||
|
* @param data 需要加密的数据
|
||||||
|
* @param sign 签名
|
||||||
|
* @param publicKey 公钥
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
public static boolean checkByPublicKey(String data, String sign, PublicKey publicKey) throws Exception {
|
public static boolean checkByPublicKey(String data, String sign, PublicKey publicKey) throws Exception {
|
||||||
java.security.Signature signature = java.security.Signature.getInstance("SHA256WithRSA");
|
java.security.Signature signature = java.security.Signature.getInstance("SHA256WithRSA");
|
||||||
signature.initVerify(publicKey);
|
signature.initVerify(publicKey);
|
||||||
|
Loading…
Reference in New Issue
Block a user