|
@@ -0,0 +1,170 @@
|
|
|
+package com.qs.mp.web.controller.api.callback;
|
|
|
+
|
|
|
+import com.alipay.api.AlipayApiException;
|
|
|
+import com.alipay.api.domain.AlipayTradeAppPayModel;
|
|
|
+import com.alipay.api.internal.util.AlipaySignature;
|
|
|
+import com.alipay.api.request.AlipayTradeAppPayRequest;
|
|
|
+import com.alipay.api.response.AlipayTradeAppPayResponse;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
|
|
+import com.qs.mp.common.enums.PayOrderStatusEnum;
|
|
|
+import com.qs.mp.common.exception.ServiceException;
|
|
|
+import com.qs.mp.common.utils.DateUtils;
|
|
|
+import com.qs.mp.common.utils.LogUtil;
|
|
|
+import com.qs.mp.common.utils.StringUtils;
|
|
|
+import com.qs.mp.common.utils.WebhookService;
|
|
|
+import com.qs.mp.pay.domain.PayOrder;
|
|
|
+import com.qs.mp.pay.service.IPayOrderService;
|
|
|
+import com.qs.mp.pay.service.IWalletService;
|
|
|
+import java.io.IOException;
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.sql.Date;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.Iterator;
|
|
|
+import java.util.Map;
|
|
|
+import javax.servlet.http.HttpServletRequest;
|
|
|
+import javax.servlet.http.HttpServletResponse;
|
|
|
+import org.slf4j.Logger;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
+import org.springframework.web.bind.annotation.RequestMapping;
|
|
|
+import org.springframework.web.bind.annotation.RequestMethod;
|
|
|
+import org.springframework.web.bind.annotation.RestController;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @auther duota
|
|
|
+ * @create 2021 2021/9/6 2:54 下午
|
|
|
+ * @describe 三方支付平台回调
|
|
|
+ */
|
|
|
+
|
|
|
+@RestController
|
|
|
+@RequestMapping("/service/notify")
|
|
|
+public class AlipayCallBackController {
|
|
|
+
|
|
|
+ private final Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName());
|
|
|
+ private String UNKNOWN = "UNKNOWN";
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IPayOrderService payOrderService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IWalletService walletService;
|
|
|
+
|
|
|
+ @Value("${ali-miniApp.public-key}")
|
|
|
+ private String aliPublicKey;
|
|
|
+
|
|
|
+
|
|
|
+ @RequestMapping(value = "/alipayCallback", method = RequestMethod.POST)
|
|
|
+ public void payCallback(HttpServletRequest request, HttpServletResponse response) {
|
|
|
+ //获取支付宝POST过来反馈信息
|
|
|
+ Map< String , String > params = new HashMap< String , String >();
|
|
|
+ Map requestParams = request.getParameterMap();
|
|
|
+ for(Iterator iter = requestParams.keySet().iterator();iter.hasNext();){
|
|
|
+ String name = (String)iter.next();
|
|
|
+ String[] values = (String [])requestParams.get(name);
|
|
|
+ String valueStr = "";
|
|
|
+ for(int i = 0;i < values.length;i ++ ){
|
|
|
+ valueStr = (i==values.length-1)?valueStr + values [i]:valueStr + values[i] + ",";
|
|
|
+ }
|
|
|
+ //乱码解决,这段代码在出现乱码时使用。
|
|
|
+ //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
|
|
|
+ params.put (name,valueStr);
|
|
|
+ }
|
|
|
+ //切记alipaypublickey是支付宝的公钥,请去open.alipay.com对应应用下查看。
|
|
|
+ //boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
|
|
|
+ boolean flag = false;
|
|
|
+ try {
|
|
|
+ flag = AlipaySignature.rsaCheckV1 (params, aliPublicKey, "GBK","RSA2");
|
|
|
+ if (!flag) {
|
|
|
+ LogUtil.error(logger,"验签失败");
|
|
|
+ responseWrite(response,"error");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ } catch (AlipayApiException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ String bizId = request.getParameter("out_trade_no");
|
|
|
+ String tradeNo = request.getParameter("trade_no");
|
|
|
+ String tradeStatus = request.getParameter("trade_status"); // TRADE_SUCCESS
|
|
|
+ Integer totalAmount = new BigDecimal(request.getParameter("total_amount")).multiply(new BigDecimal(100)).intValue();
|
|
|
+ String completeDate = request.getParameter("gmt_payment");
|
|
|
+ logger.info("data: bizId:"+bizId +" tradeNo:"+tradeNo +" totalAmount:"+totalAmount+ "tradeStatus:"+tradeStatus);
|
|
|
+
|
|
|
+ //回调金额与订单金额一致性校验
|
|
|
+ PayOrder order = payOrderService.getOne(new LambdaQueryWrapper<PayOrder>()
|
|
|
+ .eq(PayOrder::getBizId, bizId)
|
|
|
+ .eq(PayOrder::getOrderNo, tradeNo));
|
|
|
+ if (null == order) {
|
|
|
+ logger.error("支付订单不存在,bizId:" + bizId + ",tradeNo:" + tradeNo);
|
|
|
+ responseWrite(response,"error");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if(order.getTransactionAmount() != totalAmount){
|
|
|
+ logger.error("回调金额与订单金额不一致");
|
|
|
+ responseWrite(response,"error");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!"TRADE_SUCCESS".equals(tradeStatus)) {
|
|
|
+ logger.error("非支付成功消息,忽略");
|
|
|
+ responseWrite(response,"error");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ PayOrder payOrder = new PayOrder();
|
|
|
+ payOrder.setOrderId(order.getOrderId());
|
|
|
+ payOrder.setOrderNo(tradeNo);
|
|
|
+ payOrder.setCompleteDate(completeDate);
|
|
|
+// payOrder.setChannelNo(channelNo);
|
|
|
+ payOrder.setOrderStatus(PayOrderStatusEnum.SUCCESS.getValue());
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 订单支付状态单独保存
|
|
|
+ LambdaUpdateWrapper<PayOrder> updateWrapper = new LambdaUpdateWrapper<>();
|
|
|
+ updateWrapper.eq(PayOrder::getOrderStatus, PayOrderStatusEnum.WAIT.getValue());
|
|
|
+ updateWrapper.eq(PayOrder::getOrderId, order.getOrderId());
|
|
|
+ boolean ret = payOrderService.update(payOrder, updateWrapper);
|
|
|
+ if (!ret) {
|
|
|
+ throw new ServiceException("支付订单更新失败,orderId:" + order.getOrderId());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新订单,单个事务处理
|
|
|
+ logger.info("支付回调消息更新成功 orderId:" + order.getOrderId());
|
|
|
+ walletService.payOrderStatusHandle(payOrder);
|
|
|
+ responseWrite(response,"success");
|
|
|
+ } catch (Exception e){
|
|
|
+ LogUtil.error(logger, e, "支付回调消息更新失败 orderId:" + order.getOrderId());
|
|
|
+ responseWrite(response,"error");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void responseWrite(HttpServletResponse response,String echostr){
|
|
|
+ try {
|
|
|
+ response.getWriter().write(echostr);
|
|
|
+ response.getWriter().flush();
|
|
|
+ response.getWriter().close();
|
|
|
+ } catch (IOException e) {
|
|
|
+ LogUtil.error(logger, e, "微信公众号设置url回调处理异常");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取 IP地址
|
|
|
+ * 使用 Nginx等反向代理软件, 则不能通过 request.getRemoteAddr()获取 IP地址
|
|
|
+ * 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,
|
|
|
+ * X-Forwarded-For中第一个非 unknown的有效IP字符串,则为真实IP地址
|
|
|
+ */
|
|
|
+ private String getIpAddr(HttpServletRequest request) {
|
|
|
+ String ip = request.getHeader("x-forwarded-for");
|
|
|
+ if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
|
|
|
+ ip = request.getHeader("Proxy-Client-IP");
|
|
|
+ }
|
|
|
+ if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
|
|
|
+ ip = request.getHeader("WL-Proxy-Client-IP");
|
|
|
+ }
|
|
|
+ if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
|
|
|
+ ip = request.getRemoteAddr();
|
|
|
+ }
|
|
|
+ return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|