From 18118188e370e45f6e1bd43e5b33fd4c4a156655 Mon Sep 17 00:00:00 2001
From: lin <sbla5888@163.com>
Date: Mon, 08 Apr 2024 16:01:44 +0800
Subject: [PATCH] 微信支付+获取用户的openid

---
 src/main/java/org/springblade/modules/pay/service/impl/WxPayServiceImpl.java |  732 +++++++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 611 insertions(+), 121 deletions(-)

diff --git a/src/main/java/org/springblade/modules/pay/service/impl/WxPayServiceImpl.java b/src/main/java/org/springblade/modules/pay/service/impl/WxPayServiceImpl.java
index 08b67fe..dfc021c 100644
--- a/src/main/java/org/springblade/modules/pay/service/impl/WxPayServiceImpl.java
+++ b/src/main/java/org/springblade/modules/pay/service/impl/WxPayServiceImpl.java
@@ -1,26 +1,48 @@
 package org.springblade.modules.pay.service.impl;
 
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.github.wxpay.sdk.WXPayUtil;
 import com.google.gson.Gson;
 import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
 import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
 import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.util.EntityUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springblade.common.config.WxPayConfig;
 import org.springblade.common.enums.OrderStatus;
 import org.springblade.common.enums.wxpay.WxApiType;
 import org.springblade.common.enums.wxpay.WxNotifyType;
-import org.springblade.modules.pay.controller.WxPayController;
+import org.springblade.common.enums.wxpay.WxRefundStatus;
+import org.springblade.common.enums.wxpay.WxTradeState;
+import org.springblade.common.utils.HttpUtils;
+import org.springblade.common.utils.SpringUtils;
+import org.springblade.common.utils.WechatPay2ValidatorForRequest;
+import org.springblade.core.secure.utils.AuthUtil;
+import org.springblade.modules.pay.entity.OrderInfoEntity;
+import org.springblade.modules.pay.entity.RefundInfoEntity;
 import org.springblade.modules.pay.entity.WxPayInfo;
 import org.springblade.modules.pay.mapper.WxPayMapper;
+import org.springblade.modules.pay.service.IOrderInfoService;
+import org.springblade.modules.pay.service.IPaymentInfoService;
+import org.springblade.modules.pay.service.IRefundInfoService;
 import org.springblade.modules.pay.service.IWxPayService;
-import org.springframework.beans.factory.annotation.Value;
+import org.springblade.modules.property.entity.PropertyChargeRecord;
+import org.springblade.modules.property.service.IPropertyChargeService;
+import org.springblade.modules.system.entity.User;
+import org.springblade.modules.system.service.IUserService;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.StringUtils;
 
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
@@ -31,100 +53,37 @@
 
 @Service
 public class WxPayServiceImpl extends ServiceImpl<WxPayMapper,WxPayInfo> implements IWxPayService {
+	private static Logger logger = LoggerFactory.getLogger(WxPayServiceImpl.class);
 
-	private final String  MINI_PROGRAM_APP_ID = "wx41aa8a5d2e565a05";
-	private static final Logger logger = LoggerFactory.getLogger(WxPayServiceImpl.class);
+
+	@Resource
+	private WxPayConfig wxPayConfig;
+
+	@Resource
+	private IPropertyChargeService iPropertyChargeService;
+
+
+	@Resource
+	private CloseableHttpClient wxPayClient;
+
+	@Resource
+	private IOrderInfoService orderInfoService;
+
+	@Resource
+	private IPaymentInfoService paymentInfoService;
+
+	@Resource
+	private IRefundInfoService refundsInfoService;
 
 	private final ReentrantLock lock = new ReentrantLock();
+
 
 	@Override
 	public Object getOpenId(String code) {
 		return null;
 	}
 
-	@Override
-	public Map<String, String> jsapiPay(Long productId) throws IOException {
-
-		String prepayId = "";
-		//生成订单
-//		OrderInfo orderInfo = orderInfoService.createOrderByProductId(productId);
-
-
-		logger.info("调用统一下单API");
-
-//		//调用统一下单API
-//		HttpPost httpPost = new HttpPost(wxPayConfig.getDomain().concat(WxApiType.JSAPI_PAY.getType()));
-//
-//		// 请求body参数
-//
-//		Gson gson = new Gson();
-//		Map paramsMap = new HashMap();
-//		paramsMap.put("appid", wxPayConfig.getAppid());
-//		paramsMap.put("mchid", wxPayConfig.getMchId());
-//		paramsMap.put("description", orderInfo.getTitle());
-//		paramsMap.put("out_trade_no", orderInfo.getOrderNo());
-//		paramsMap.put("notify_url", wxPayConfig.getNotifyDomain().concat(WxNotifyType.NATIVE_NOTIFY.getType()));
-//
-//		Map amountMap = new HashMap();
-//		amountMap.put("total", orderInfo.getTotalFee());
-//		amountMap.put("currency", "CNY");
-//
-//		paramsMap.put("amount", amountMap);
-//
-//		Map payerMap = new HashMap();
-//		payerMap.put("openid", "oSX3G6OUuGaKJbWzSHUpPbzgtDXo");
-//
-//		paramsMap.put("payer", payerMap);
-//
-//		//将参数转换成json字符串
-//		String jsonParams = gson.toJson(paramsMap);
-//		logger.info("请求参数 ===> {}" + jsonParams);
-//
-//		StringEntity entity = new StringEntity(jsonParams, "utf-8");
-//		entity.setContentType("application/json");
-//		httpPost.setEntity(entity);
-//		httpPost.setHeader("Accept", "application/json");
-//
-//		//完成签名并执行请求
-//		CloseableHttpResponse response = wxPayClient.execute(httpPost);
-//
-//		try {
-//			String bodyAsString = EntityUtils.toString(response.getEntity());//响应体
-//			int statusCode = response.getStatusLine().getStatusCode();//响应状态码
-//			if (statusCode == 200) { //处理成功
-//				logger.info("成功, 返回结果 = " + bodyAsString);
-//			} else if (statusCode == 204) { //处理成功,无返回Body
-//				logger.info("成功");
-//			} else {
-//				logger.info("jszpi下单失败,响应码 = " + statusCode + ",返回结果 = " + bodyAsString);
-//				throw new IOException("request failed");
-//			}
-//			//响应结果
-//			Map<String, String> resultMap = gson.fromJson(bodyAsString, HashMap.class);
-//			//预支付交易会话标识
-//			prepayId = resultMap.get("prepay_id");
-//
-//			//返回预支付交易会话标识
-//			// 组装前端预下单参数
-//			/** 返回给前端所需要的数据 */
-//			SortedMap<String, String> payMap = new TreeMap<>();
-//			String nonceStr = WXPayUtil.generateNonceStr();
-//			String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
-//			payMap.put("appId", wxPayConfig.getAppid());
-//			payMap.put("timeStamp", timestamp);
-//			payMap.put("nonceStr", nonceStr);
-//			payMap.put("signType", "RSA");
-//			payMap.put("package", "prepay_id=" + prepayId);
-//			String paySign = getSign(wxPayConfig.getAppid(), prepayId, timestamp, nonceStr);
-//			payMap.put("paySign", paySign);
-//			logger.info("返回参数 ===> {}" + gson.toJson(payMap));
-//			return payMap;
-//		} finally {
-//			response.close();
-//		}
-		return null;
-	}
-
+	@Transactional(rollbackFor = Exception.class)
 	@Override
 	public void processOrder(Map<String, Object> bodyMap) throws GeneralSecurityException {
 		logger.info("处理订单");
@@ -143,32 +102,410 @@
         以避免函数重入造成的数据混乱*/
 		//尝试获取锁:
 		// 成功获取则立即返回true,获取失败则立即返回false。不必一直等待锁的释放
-//		if (lock.tryLock()) {
-//			try {
-//				//处理重复的通知
-//				//接口调用的幂等性:无论接口被调用多少次,产生的结果是一致的。
-//				String orderStatus = orderInfoService.getOrderStatus(orderNo);
-//				if (!OrderStatus.NOTPAY.getType().equals(orderStatus)) {
-//					return;
-//				}
-//
-//				//模拟通知并发
-//				try {
-//					TimeUnit.SECONDS.sleep(5);
-//				} catch (InterruptedException e) {
-//					e.printStackTrace();
-//				}
-//
-//				//更新订单状态
-//				orderInfoService.updateStatusByOrderNo(orderNo, OrderStatus.SUCCESS);
-//
-//				//记录支付日志
-//				paymentInfoService.createPaymentInfo(plainText);
-//			} finally {
-//				//要主动释放锁
-//				lock.unlock();
-//			}
-//		}
+		if (lock.tryLock()) {
+			try {
+				//处理重复的通知
+				//接口调用的幂等性:无论接口被调用多少次,产生的结果是一致的。
+				String orderStatus = orderInfoService.getOrderStatus(orderNo);
+				if (!OrderStatus.NOTPAY.getType().equals(orderStatus)) {
+					return;
+				}
+
+				//模拟通知并发
+				try {
+					TimeUnit.SECONDS.sleep(5);
+				} catch (InterruptedException e) {
+					e.printStackTrace();
+				}
+
+				//更新订单状态
+				orderInfoService.updateStatusByOrderNo(orderNo, OrderStatus.SUCCESS);
+
+				//记录支付日志
+				paymentInfoService.createPaymentInfo(plainText);
+			} finally {
+				//要主动释放锁
+				lock.unlock();
+			}
+		}
+	}
+
+	/**
+	 * 用户取消订单
+	 *
+	 * @param orderNo
+	 */
+	@Override
+	public void cancelOrder(String orderNo) throws Exception {
+
+		//调用微信支付的关单接口
+		this.closeOrder(orderNo);
+
+		//更新商户端的订单状态
+		orderInfoService.updateStatusByOrderNo(orderNo, OrderStatus.CANCEL);
+	}
+
+	@Override
+	public String queryOrder(String orderNo) throws Exception {
+
+		logger.info("查单接口调用 ===> {}", orderNo);
+
+		String url = String.format(WxApiType.ORDER_QUERY_BY_NO.getType(), orderNo);
+		url = wxPayConfig.getDomain().concat(url).concat("?mchid=").concat(wxPayConfig.getMchId());
+
+		HttpGet httpGet = new HttpGet(url);
+		httpGet.setHeader("Accept", "application/json");
+
+		//完成签名并执行请求
+		CloseableHttpResponse response = wxPayClient.execute(httpGet);
+
+		try {
+			String bodyAsString = EntityUtils.toString(response.getEntity());//响应体
+			int statusCode = response.getStatusLine().getStatusCode();//响应状态码
+			if (statusCode == 200) { //处理成功
+				logger.info("成功, 返回结果 = " + bodyAsString);
+			} else if (statusCode == 204) { //处理成功,无返回Body
+				logger.info("成功");
+			} else {
+				logger.info("查单接口调用,响应码 = " + statusCode + ",返回结果 = " + bodyAsString);
+				throw new IOException("request failed");
+			}
+
+			return bodyAsString;
+
+		} finally {
+			response.close();
+		}
+
+	}
+
+	/**
+	 * 根据订单号查询微信支付查单接口,核实订单状态
+	 * 如果订单已支付,则更新商户端订单状态,并记录支付日志
+	 * 如果订单未支付,则调用关单接口关闭订单,并更新商户端订单状态
+	 *
+	 * @param orderNo
+	 */
+	@Transactional(rollbackFor = Exception.class)
+	@Override
+	public void checkOrderStatus(String orderNo) throws Exception {
+
+		logger.info("根据订单号核实订单状态 ===> {}", orderNo);
+
+		//调用微信支付查单接口
+		String result = this.queryOrder(orderNo);
+
+		Gson gson = new Gson();
+		Map<String, String> resultMap = gson.fromJson(result, HashMap.class);
+
+		//获取微信支付端的订单状态
+		String tradeState = resultMap.get("trade_state");
+
+		//判断订单状态
+		if (WxTradeState.SUCCESS.getType().equals(tradeState)) {
+
+			logger.info("核实订单已支付 ===> {}", orderNo);
+
+			//如果确认订单已支付则更新本地订单状态
+			orderInfoService.updateStatusByOrderNo(orderNo, OrderStatus.SUCCESS);
+			//记录支付日志
+			paymentInfoService.createPaymentInfo(result);
+		}
+
+		if (WxTradeState.NOTPAY.getType().equals(tradeState)) {
+			logger.info("核实订单未支付 ===> {}", orderNo);
+
+			//如果订单未支付,则调用关单接口
+			this.closeOrder(orderNo);
+
+			//更新本地订单状态
+			orderInfoService.updateStatusByOrderNo(orderNo, OrderStatus.CLOSED);
+		}
+
+	}
+
+	/**
+	 * 退款
+	 *
+	 * @param orderNo
+	 * @param reason
+	 * @throws IOException
+	 */
+	@Transactional(rollbackFor = Exception.class)
+	@Override
+	public void refund(String orderNo, String reason) throws Exception {
+
+		logger.info("创建退款单记录");
+		//根据订单编号创建退款单
+		RefundInfoEntity refundsInfo = refundsInfoService.createRefundByOrderNo(orderNo, reason);
+
+		logger.info("调用退款API");
+
+		//调用统一下单API
+		String url = wxPayConfig.getDomain().concat(WxApiType.DOMESTIC_REFUNDS.getType());
+		HttpPost httpPost = new HttpPost(url);
+
+		// 请求body参数
+		Gson gson = new Gson();
+		Map paramsMap = new HashMap();
+		paramsMap.put("out_trade_no", orderNo);//订单编号
+		paramsMap.put("out_refund_no", refundsInfo.getRefundNo());//退款单编号
+		paramsMap.put("reason", reason);//退款原因
+		paramsMap.put("notify_url", wxPayConfig.getNotifyDomain().concat(WxNotifyType.REFUND_NOTIFY.getType()));//退款通知地址
+
+		Map amountMap = new HashMap();
+		amountMap.put("refund", refundsInfo.getRefund());//退款金额
+		amountMap.put("total", refundsInfo.getTotalFee());//原订单金额
+		amountMap.put("currency", "CNY");//退款币种
+		paramsMap.put("amount", amountMap);
+
+		//将参数转换成json字符串
+		String jsonParams = gson.toJson(paramsMap);
+		logger.info("请求参数 ===> {}" + jsonParams);
+
+		StringEntity entity = new StringEntity(jsonParams, "utf-8");
+		entity.setContentType("application/json");//设置请求报文格式
+		httpPost.setEntity(entity);//将请求报文放入请求对象
+		httpPost.setHeader("Accept", "application/json");//设置响应报文格式
+
+		//完成签名并执行请求,并完成验签
+		CloseableHttpResponse response = wxPayClient.execute(httpPost);
+
+		try {
+
+			//解析响应结果
+			String bodyAsString = EntityUtils.toString(response.getEntity());
+			int statusCode = response.getStatusLine().getStatusCode();
+			if (statusCode == 200) {
+				logger.info("成功, 退款返回结果 = " + bodyAsString);
+			} else if (statusCode == 204) {
+				logger.info("成功");
+			} else {
+				throw new RuntimeException("退款异常, 响应码 = " + statusCode + ", 退款返回结果 = " + bodyAsString);
+			}
+
+			//更新订单状态
+			orderInfoService.updateStatusByOrderNo(orderNo, OrderStatus.REFUND_PROCESSING);
+
+			//更新退款单
+			refundsInfoService.updateRefund(bodyAsString);
+
+		} finally {
+			response.close();
+		}
+	}
+
+
+	/**
+	 * 查询退款接口调用
+	 *
+	 * @param refundNo
+	 * @return
+	 */
+	@Override
+	public String queryRefund(String refundNo) throws Exception {
+
+		logger.info("查询退款接口调用 ===> {}", refundNo);
+
+		String url = String.format(WxApiType.DOMESTIC_REFUNDS_QUERY.getType(), refundNo);
+		url = wxPayConfig.getDomain().concat(url);
+
+		//创建远程Get 请求对象
+		HttpGet httpGet = new HttpGet(url);
+		httpGet.setHeader("Accept", "application/json");
+
+		//完成签名并执行请求
+		CloseableHttpResponse response = wxPayClient.execute(httpGet);
+
+		try {
+			String bodyAsString = EntityUtils.toString(response.getEntity());
+			int statusCode = response.getStatusLine().getStatusCode();
+			if (statusCode == 200) {
+				logger.info("成功, 查询退款返回结果 = " + bodyAsString);
+			} else if (statusCode == 204) {
+				logger.info("成功");
+			} else {
+				throw new RuntimeException("查询退款异常, 响应码 = " + statusCode + ", 查询退款返回结果 = " + bodyAsString);
+			}
+
+			return bodyAsString;
+
+		} finally {
+			response.close();
+		}
+	}
+
+	/**
+	 * 根据退款单号核实退款单状态
+	 *
+	 * @param refundNo
+	 * @return
+	 */
+	@Transactional(rollbackFor = Exception.class)
+	@Override
+	public void checkRefundStatus(String refundNo) throws Exception {
+
+		logger.info("根据退款单号核实退款单状态 ===> {}", refundNo);
+
+		//调用查询退款单接口
+		String result = this.queryRefund(refundNo);
+
+		//组装json请求体字符串
+		Gson gson = new Gson();
+		Map<String, String> resultMap = gson.fromJson(result, HashMap.class);
+
+		//获取微信支付端退款状态
+		String status = resultMap.get("status");
+
+		String orderNo = resultMap.get("out_trade_no");
+
+		if (WxRefundStatus.SUCCESS.getType().equals(status)) {
+
+			logger.info("核实订单已退款成功 ===> {}", refundNo);
+
+			//如果确认退款成功,则更新订单状态
+			orderInfoService.updateStatusByOrderNo(orderNo, OrderStatus.REFUND_SUCCESS);
+
+			//更新退款单
+			refundsInfoService.updateRefund(result);
+		}
+
+		if (WxRefundStatus.ABNORMAL.getType().equals(status)) {
+
+			logger.info("核实订单退款异常  ===> {}", refundNo);
+
+			//如果确认退款成功,则更新订单状态
+			orderInfoService.updateStatusByOrderNo(orderNo, OrderStatus.REFUND_ABNORMAL);
+
+			//更新退款单
+			refundsInfoService.updateRefund(result);
+		}
+	}
+
+	/**
+	 * 处理退款单
+	 */
+	@Transactional(rollbackFor = Exception.class)
+	@Override
+	public void processRefund(Map<String, Object> bodyMap) throws Exception {
+
+		logger.info("退款单");
+
+		//解密报文
+		String plainText = decryptFromResource(bodyMap);
+
+		//将明文转换成map
+		Gson gson = new Gson();
+		HashMap plainTextMap = gson.fromJson(plainText, HashMap.class);
+		String orderNo = (String) plainTextMap.get("out_trade_no");
+
+		if (lock.tryLock()) {
+			try {
+
+				String orderStatus = orderInfoService.getOrderStatus(orderNo);
+				if (!OrderStatus.REFUND_PROCESSING.getType().equals(orderStatus)) {
+					return;
+				}
+
+				//更新订单状态
+				orderInfoService.updateStatusByOrderNo(orderNo, OrderStatus.REFUND_SUCCESS);
+
+				//更新退款单
+				refundsInfoService.updateRefund(plainText);
+
+			} finally {
+				//要主动释放锁
+				lock.unlock();
+			}
+		}
+	}
+
+
+
+	@Override
+	public Map<String, String> jsapiPay(Long properChargeRecordId) throws Exception {
+
+		String prepayId = "";
+		//生成订单
+		OrderInfoEntity orderInfo = orderInfoService.getOne(Wrappers.<OrderInfoEntity>lambdaQuery().eq(OrderInfoEntity::getProperChargeRecordId,properChargeRecordId));
+		IUserService userService = SpringUtils.getBean(IUserService.class);
+		User serviceOne = userService.getOne(Wrappers.<User>lambdaQuery().eq(User::getId, AuthUtil.getUserId()));
+
+		logger.info("调用统一下单API");
+
+		//调用统一下单API
+		HttpPost httpPost = new HttpPost(wxPayConfig.getDomain().concat(WxApiType.JSAPI_PAY.getType()));
+
+		// 请求body参数
+
+		Gson gson = new Gson();
+		Map paramsMap = new HashMap();
+		paramsMap.put("appid", wxPayConfig.getAppid());
+		paramsMap.put("mchid", wxPayConfig.getMchId());
+		paramsMap.put("description", orderInfo.getTitle());
+		paramsMap.put("out_trade_no", orderInfo.getOrderNo());
+		paramsMap.put("notify_url", wxPayConfig.getNotifyDomain().concat(WxNotifyType.NATIVE_NOTIFY.getType()));
+
+		Map amountMap = new HashMap();
+		amountMap.put("total", orderInfo.getTotalFee());
+		amountMap.put("currency", "CNY");
+
+		paramsMap.put("amount", amountMap);
+
+		Map payerMap = new HashMap();
+		payerMap.put("openid", serviceOne.getMiniOpenId());
+
+		paramsMap.put("payer", payerMap);
+
+		// 是否指定分账,枚举值 true:是 false:否
+		paramsMap.put("profit_sharing", true);
+
+		//将参数转换成json字符串
+		String jsonParams = gson.toJson(paramsMap);
+		logger.info("请求参数 ===> {}" + jsonParams);
+
+		StringEntity entity = new StringEntity(jsonParams, "utf-8");
+		entity.setContentType("application/json");
+		httpPost.setEntity(entity);
+		httpPost.setHeader("Accept", "application/json");
+
+		//完成签名并执行请求
+		CloseableHttpResponse response = wxPayClient.execute(httpPost);
+
+		try {
+			String bodyAsString = EntityUtils.toString(response.getEntity());//响应体
+			int statusCode = response.getStatusLine().getStatusCode();//响应状态码
+			if (statusCode == 200) { //处理成功
+				logger.info("成功, 返回结果 = " + bodyAsString);
+			} else if (statusCode == 204) { //处理成功,无返回Body
+				logger.info("成功");
+			} else {
+				logger.info("jszpi下单失败,响应码 = " + statusCode + ",返回结果 = " + bodyAsString);
+				throw new IOException("request failed");
+			}
+			//响应结果
+			Map<String, String> resultMap = gson.fromJson(bodyAsString, HashMap.class);
+			//预支付交易会话标识
+			prepayId = resultMap.get("prepay_id");
+
+			//返回预支付交易会话标识
+			// 组装前端预下单参数
+			/** 返回给前端所需要的数据 */
+			SortedMap<String, String> payMap = new TreeMap<>();
+			String nonceStr = WXPayUtil.generateNonceStr();
+			String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
+			payMap.put("appId", wxPayConfig.getAppid());
+			payMap.put("timeStamp", timestamp);
+			payMap.put("nonceStr", nonceStr);
+			payMap.put("signType", "RSA");
+			payMap.put("package", "prepay_id=" + prepayId);
+			String paySign = getSign(wxPayConfig.getAppid(), prepayId, timestamp, nonceStr);
+			payMap.put("paySign", paySign);
+			logger.info("返回参数 ===> {}" + gson.toJson(payMap));
+			return payMap;
+		} finally {
+			response.close();
+		}
 	}
 
 	/**
@@ -196,7 +533,7 @@
 		//签名方式
 		Signature sign = Signature.getInstance("SHA256withRSA");
 		//私钥,通过MyPrivateKey来获取,这是个静态类可以接调用方法 ,需要的是_key.pem文件的绝对路径配上文件名
-//		sign.initSign(getPrivateKey(wxPayConfig.getPrivateKeyPath()));
+		sign.initSign(getPrivateKey(wxPayConfig.getPrivateKeyPath()));
 		sign.update(message);
 
 		return Base64.getEncoder().encodeToString(sign.sign());
@@ -227,6 +564,52 @@
 		}
 	}
 
+
+	/**
+	 * 关单接口的调用
+	 *
+	 * @param orderNo
+	 */
+	private void closeOrder(String orderNo) throws Exception {
+
+		logger.info("关单接口的调用,订单号 ===> {}", orderNo);
+		//创建远程请求对象
+		String url = String.format(WxApiType.CLOSE_ORDER_BY_NO.getType(), orderNo);
+		url = wxPayConfig.getDomain().concat(url);
+		HttpPost httpPost = new HttpPost(url);
+
+		//组装json请求体
+		Gson gson = new Gson();
+		Map<String, String> paramsMap = new HashMap<>();
+		paramsMap.put("mchid", wxPayConfig.getMchId());
+		String jsonParams = gson.toJson(paramsMap);
+		logger.info("请求参数 ===> {}", jsonParams);
+
+		//将请求参数设置到请求对象中
+		StringEntity entity = new StringEntity(jsonParams, "utf-8");
+		entity.setContentType("application/json");
+		httpPost.setEntity(entity);
+		httpPost.setHeader("Accept", "application/json");
+
+		//完成签名并执行请求
+		CloseableHttpResponse response = wxPayClient.execute(httpPost);
+
+		try {
+			int statusCode = response.getStatusLine().getStatusCode();//响应状态码
+			if (statusCode == 200) { //处理成功
+				logger.info("成功200");
+			} else if (statusCode == 204) { //处理成功,无返回Body
+				logger.info("成功204");
+			} else {
+				logger.info("Native下单失败,响应码 = " + statusCode);
+				throw new IOException("request failed");
+			}
+
+		} finally {
+			response.close();
+		}
+	}
+
 	/**
 	 * 对称解密
 	 *
@@ -247,15 +630,122 @@
 		String associatedData = resourceMap.get("associated_data");
 
 		logger.info("密文 ===> {}", ciphertext);
-//		AesUtil aesUtil = new AesUtil(wxPayConfig.getApiV3Key().getBytes(StandardCharsets.UTF_8));
-//		String plainText = aesUtil.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8),
-//			nonce.getBytes(StandardCharsets.UTF_8),
-//			ciphertext);
+		AesUtil aesUtil = new AesUtil(wxPayConfig.getApiV3Key().getBytes(StandardCharsets.UTF_8));
+		String plainText = aesUtil.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8),
+			nonce.getBytes(StandardCharsets.UTF_8),
+			ciphertext);
 
-//		logger.info("明文 ===> {}", plainText);
+		logger.info("明文 ===> {}", plainText);
 
-//		return plainText;
-		return null;
+		return plainText;
 	}
 
+	@Override
+	public String nativeNotify(HttpServletRequest request, HttpServletResponse response) {
+		Gson gson = new Gson();
+		Map<String, String> map = new HashMap<>();//应答对象
+
+		try {
+
+			//处理通知参数
+			String body = HttpUtils.readData(request);
+			Map<String, Object> bodyMap = gson.fromJson(body, HashMap.class);
+			String requestId = (String) bodyMap.get("id");
+			logger.info("支付通知的id ===> {}", requestId);
+			logger.info("支付通知的完整数据 ===> {}", body);
+			//int a = 9 / 0;
+
+			//签名的验证
+			WechatPay2ValidatorForRequest wechatPay2ValidatorForRequest
+				= new WechatPay2ValidatorForRequest(wxPayConfig.getVerifier(), requestId, body);
+			if (!wechatPay2ValidatorForRequest.validate(request)) {
+
+				logger.error("通知验签失败");
+				//失败应答
+				response.setStatus(500);
+				map.put("code", "ERROR");
+				map.put("message", "通知验签失败");
+				return gson.toJson(map);
+			}
+			logger.info("通知验签成功");
+
+			//处理订单
+			processOrder(bodyMap);
+
+			//成功应答
+			response.setStatus(200);
+			map.put("code", "SUCCESS");
+			map.put("message", "成功");
+			return gson.toJson(map);
+
+		} catch (Exception e) {
+			e.printStackTrace();
+			//失败应答
+			response.setStatus(500);
+			map.put("code", "ERROR");
+			map.put("message", "失败");
+			return gson.toJson(map);
+		}
+	}
+
+	@Override
+	public String refundsNotify(HttpServletRequest request, HttpServletResponse response) {
+		Gson gson = new Gson();
+		Map<String, String> map = new HashMap<>();//应答对象
+
+		try {
+			//处理通知参数
+			String body = HttpUtils.readData(request);
+			Map<String, Object> bodyMap = gson.fromJson(body, HashMap.class);
+			String requestId = (String) bodyMap.get("id");
+			logger.info("支付通知的id ===> {}", requestId);
+
+			//签名的验证
+			WechatPay2ValidatorForRequest wechatPay2ValidatorForRequest
+				= new WechatPay2ValidatorForRequest(wxPayConfig.getVerifier(), requestId, body);
+			if (!wechatPay2ValidatorForRequest.validate(request)) {
+
+				logger.error("通知验签失败");
+				//失败应答
+				response.setStatus(500);
+				map.put("code", "ERROR");
+				map.put("message", "通知验签失败");
+				return gson.toJson(map);
+			}
+			logger.info("通知验签成功");
+
+			//处理退款单
+			processRefund(bodyMap);
+
+			//成功应答
+			response.setStatus(200);
+			map.put("code", "SUCCESS");
+			map.put("message", "成功");
+			return gson.toJson(map);
+
+		} catch (Exception e) {
+			e.printStackTrace();
+			//失败应答
+			response.setStatus(500);
+			map.put("code", "ERROR");
+			map.put("message", "失败");
+			return gson.toJson(map);
+		}
+	}
+
+
+	//创建签名所需要的参数xml格式
+//	public static String createXML(Map<String, Object> map) {
+//		String xml = "<xml>";
+//		Set<String> set = map.keySet();
+//		Iterator<String> i = set.iterator();
+//		while (i.hasNext()) {
+//			String str = i.next();
+//			xml += "<" + str + ">" + "<![CDATA[" + map.get(str) + "]]>" + "</" + str + ">";
+//		}
+//		xml += "</xml>";
+//		return xml;
+//	}
+
+
 }

--
Gitblit v1.9.3