xiongzhu 4 tahun lalu
induk
melakukan
7b2bbab871

+ 35 - 1
src/main/java/com/izouma/nineth/service/HMPayService.java

@@ -9,8 +9,10 @@ import com.izouma.nineth.config.GeneralProperties;
 import com.izouma.nineth.config.HmPayProperties;
 import com.izouma.nineth.exception.BusinessException;
 import com.izouma.nineth.utils.DateTimeUtils;
+import com.izouma.nineth.utils.SnowflakeIdWorker;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.RandomStringUtils;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.stereotype.Service;
 
@@ -31,6 +33,7 @@ import java.util.Map;
 public class HMPayService {
     private final HmPayProperties   hmPayProperties;
     private final GeneralProperties generalProperties;
+    private final SnowflakeIdWorker snowflakeIdWorker;
 
     private String getSign(Map<String, String> params) {
         try {
@@ -57,6 +60,24 @@ public class HMPayService {
         });
     }
 
+    public JSONObject requestApi(String method, Map<String, String> bizContent) {
+        Map<String, String> params = new HashMap<>();
+        params.put("app_id", hmPayProperties.getMerNo());
+        params.put("method", method);
+        params.put("timestamp", DateTimeUtils.format(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss"));
+        params.put("nonce", RandomStringUtils.randomAlphabetic(32));
+
+        params.put("biz_content", JSON.toJSONString(bizContent));
+        params.put("sign", getSign(params));
+        log.info("请求参数{}", params);
+        String body = HttpRequest.post("https://hmpay.sandpay.com.cn/gateway/api")
+                .contentType("application/json")
+                .send(JSON.toJSONString(params)).body();
+        JSONObject res = JSON.parseObject(body);
+        log.info("请求结果{}", JSON.toJSONString(res, true));
+        return res;
+    }
+
     public String getReqTime() {
         return DateTimeUtils.format(LocalDateTime.now(), "yyyyMMddHHmmss");
     }
@@ -74,7 +95,7 @@ public class HMPayService {
         }
         Map<String, String> params = new HashMap<>();
         params.put("version", "10");
-        params.put("mer_no", "664403000025502");
+        params.put("mer_no", hmPayProperties.getMerNo());
         params.put("mer_order_no", orderId);
         params.put("create_time", getReqTime());
         params.put("expire_time", getTimeout(timeout));
@@ -112,4 +133,17 @@ public class HMPayService {
         throw new BusinessException("绿洲宇宙冷却系统已启动,请稍后支付");
     }
 
+    public JSONObject queryOrder(String orderId) {
+        Map<String, String> bizContent = new HashMap<>();
+        bizContent.put("out_order_no", orderId);
+        return requestApi("trade.query", bizContent);
+    }
+
+    public JSONObject refund(String orderId, BigDecimal amount) {
+        Map<String, String> bizContent = new HashMap<>();
+        bizContent.put("out_order_no", orderId);
+        bizContent.put("refund_amount", amount.stripTrailingZeros().toPlainString());
+        bizContent.put("refund_request_no", snowflakeIdWorker.nextId() + "");
+        return requestApi("trade.refund", bizContent);
+    }
 }

+ 0 - 62
src/main/java/com/izouma/nineth/service/RedisLock.java

@@ -1,62 +0,0 @@
-package com.izouma.nineth.service;
-
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.redis.core.StringRedisTemplate;
-import org.springframework.stereotype.Component;
-
-@Component
-@Slf4j
-public class RedisLock {
-    @Autowired
-    private StringRedisTemplate stringRedisTemplate;
-
-    /**
-     * 加锁
-     *
-     * @param key   productId - 商品的唯一标志
-     * @param value 当前时间+超时时间 也就是时间戳
-     * @return
-     */
-    public boolean lock(String key, String value) {
-        if (stringRedisTemplate.opsForValue().setIfAbsent(key, value)) {//对应setnx命令
-            //可以成功设置,也就是key不存在
-            return true;
-        }
-
-        //判断锁超时 - 防止原来的操作异常,没有运行解锁操作  防止死锁
-        String currentValue = stringRedisTemplate.opsForValue().get(key);
-        //如果锁过期
-        if (!StringUtils.isEmpty(currentValue) && Long.parseLong(currentValue) < System.currentTimeMillis()) {//currentValue不为空且小于当前时间
-            //获取上一个锁的时间value
-            String oldValue = stringRedisTemplate.opsForValue().getAndSet(key, value);//对应getset,如果key存在
-
-            //假设两个线程同时进来这里,因为key被占用了,而且锁过期了。获取的值currentValue=A(get取的旧的值肯定是一样的),两个线程的value都是B,key都是K.锁时间已经过期了。
-            //而这里面的getAndSet一次只会一个执行,也就是一个执行之后,上一个的value已经变成了B。只有一个线程获取的上一个值会是A,另一个线程拿到的值是B。
-            if (!StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue)) {
-                //oldValue不为空且oldValue等于currentValue,也就是校验是不是上个对应的商品时间戳,也是防止并发
-                return true;
-            }
-        }
-        return false;
-    }
-
-
-    /**
-     * 解锁
-     *
-     * @param key
-     * @param value
-     */
-    public void unlock(String key, String value) {
-        try {
-            String currentValue = stringRedisTemplate.opsForValue().get(key);
-            if (!StringUtils.isEmpty(currentValue) && currentValue.equals(value)) {
-                stringRedisTemplate.opsForValue().getOperations().delete(key);//删除key
-            }
-        } catch (Exception e) {
-            log.error("[Redis分布式锁] 解锁出现异常了,{}", e);
-        }
-    }
-}

+ 23 - 18
src/main/java/com/izouma/nineth/service/UserService.java

@@ -605,16 +605,17 @@ public class UserService {
         }
         smsService.verify(phone, code);
 
-        adapayMerchantService.createMemberForAll(userId.toString(), user.getPhone(), identityAuth.getRealName(), identityAuth.getIdNo());
-        user.setMemberId(user.getId().toString());
-        save(user);
-
-        String accountId = adapayMerchantService.createSettleAccountForAll
-                (user.getMemberId(), identityAuth.getRealName(),
-                        identityAuth.getIdNo(), phone, bankNo);
-        user.setSettleAccountId(Optional.ofNullable(accountId).orElse("1"));
-        save(user);
+//        adapayMerchantService.createMemberForAll(userId.toString(), user.getPhone(), identityAuth.getRealName(), identityAuth.getIdNo());
+//        user.setMemberId(user.getId().toString());
+//        save(user);
+//
+//        String accountId = adapayMerchantService.createSettleAccountForAll
+//                (user.getMemberId(), identityAuth.getRealName(),
+//                        identityAuth.getIdNo(), phone, bankNo);
+//        user.setSettleAccountId(Optional.ofNullable(accountId).orElse("1"));
+//        save(user);
 
+        user.setMemberId(user.getId().toString());
         user.setSettleAccountId("1");
         save(user);
         userBankCardRepo.save(UserBankCard.builder()
@@ -634,15 +635,19 @@ public class UserService {
 
     public void removeBankCard(Long userId) throws BaseAdaPayException {
         User user = userRepo.findById(userId).orElseThrow(new BusinessException("用户不存在"));
-        if (StringUtils.isNotBlank(user.getSettleAccountId()) && StringUtils.isNotBlank(user.getMemberId())) {
-            adapayMerchantService.delSettleAccountForAll(user.getMemberId());
-            user.setSettleAccountId(null);
-            save(user);
-            userBankCardRepo.deleteByUserId(userId);
-            cacheService.clearUserMy(userId);
-        } else {
-            throw new BusinessException("未绑定");
-        }
+//        if (StringUtils.isNotBlank(user.getSettleAccountId()) && StringUtils.isNotBlank(user.getMemberId())) {
+//            adapayMerchantService.delSettleAccountForAll(user.getMemberId());
+//            user.setSettleAccountId(null);
+//            save(user);
+//            userBankCardRepo.deleteByUserId(userId);
+//            cacheService.clearUserMy(userId);
+//        } else {
+//            throw new BusinessException("未绑定");
+//        }
+        user.setSettleAccountId(null);
+        save(user);
+        userBankCardRepo.deleteByUserId(userId);
+        cacheService.clearUserMy(userId);
     }
 
     public void removeAuth(Long userId) {

+ 53 - 6
src/main/java/com/izouma/nineth/web/HmPayController.java

@@ -1,23 +1,70 @@
 package com.izouma.nineth.web;
 
 import com.alibaba.fastjson.JSON;
-import com.izouma.nineth.service.HMPayService;
+import com.alipay.api.AlipayApiException;
+import com.alipay.api.internal.util.AlipaySignature;
+import com.izouma.nineth.config.GeneralProperties;
+import com.izouma.nineth.config.HmPayProperties;
+import com.izouma.nineth.enums.PayMethod;
+import com.izouma.nineth.event.OrderNotifyEvent;
+import com.izouma.nineth.service.*;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.web.bind.annotation.*;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.rocketmq.spring.core.RocketMQTemplate;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
 
 import javax.servlet.http.HttpServletRequest;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 @RestController
 @RequestMapping("/hmpay")
 @Slf4j
 @AllArgsConstructor
 public class HmPayController extends BaseController {
-    private final HMPayService hmPayService;
+    private final HMPayService      hmPayService;
+    private final HmPayProperties   hmPayProperties;
+    private final RocketMQTemplate  rocketMQTemplate;
+    private final OrderService      orderService;
+    private final MintOrderService  mintOrderService;
+    private final GiftOrderService  giftOrderService;
+    private final GeneralProperties generalProperties;
 
-    @GetMapping("/notify/{type}/{orderId}")
-    public String orderNotify(@PathVariable String type, @PathVariable String orderId, HttpServletRequest req) {
-        log.info("回调type={}, orderId={}, 参数={}", type, orderId, JSON.toJSONString(req.getParameterMap(), true));
+    @GetMapping("/notify/{type}/{id}")
+    public String orderNotify(@PathVariable String type, @PathVariable Long id, HttpServletRequest req) throws AlipayApiException {
+        log.info("回调type={}, orderId={}, 参数={}", type, id, JSON.toJSONString(req.getParameterMap(), true));
+        Map<String, String> params = new HashMap<>();
+        req.getParameterMap().forEach((k, v) -> {
+            if (v != null && v.length > 0 && StringUtils.isNotEmpty(v[0])) {
+                params.put(k, v[0]);
+            }
+        });
+        String sign = params.get("sign");
+        params.remove("sign");
+        String signStr = params.entrySet().stream().sorted(Map.Entry.comparingByKey())
+                .map(e -> e.getKey() + "=" + e.getValue())
+                .collect(Collectors.joining("&"));
+        boolean verify = AlipaySignature.verify(signStr, sign, hmPayProperties.getHmPublicKey(), "UTF-8", "RSA");
+        log.info("签名校验: {}", verify);
+        if ("SUCCESS".equals(params.get("trade_status"))) {
+            String plat_trx_no = params.get("plat_trx_no");
+            switch (type) {
+                case "order":
+                    rocketMQTemplate.syncSend(generalProperties.getOrderNotifyTopic(),
+                            new OrderNotifyEvent(id, PayMethod.ALIPAY, plat_trx_no, System.currentTimeMillis()));
+                    break;
+                case "gift":
+                    giftOrderService.giftNotify(id, PayMethod.ALIPAY, plat_trx_no);
+                    break;
+                case "mintOrder":
+                    mintOrderService.mintNotify(id, PayMethod.ALIPAY, plat_trx_no);
+            }
+        }
         return "respCode=000000";
     }
 }

+ 0 - 40
src/main/java/com/izouma/nineth/web/TestStockController.java

@@ -1,40 +0,0 @@
-package com.izouma.nineth.web;
-
-import com.izouma.nineth.service.RedisLock;
-import lombok.AllArgsConstructor;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.annotation.PostConstruct;
-
-@RestController
-@RequestMapping("/teststock")
-@AllArgsConstructor
-public class TestStockController {
-
-    private RedisLock                     redisLock;
-    private RedisTemplate<String, Object> redisTemplate;
-
-    @PostConstruct
-    public void init() {
-        redisTemplate.opsForValue().set("teststock", 1000);
-    }
-
-    @GetMapping("/setup")
-    public void setup() {
-        redisTemplate.opsForValue().getAndSet("teststock", 1000);
-    }
-
-    @GetMapping("/test")
-    public String test() {
-        int stock = Math.toIntExact(redisTemplate.opsForValue().decrement("teststock", 1));
-        if (stock < 0) {
-            redisTemplate.opsForValue().increment("teststock", 1);
-            return "库存不足";
-        } else {
-            return "ok";
-        }
-    }
-}

+ 1 - 1
src/main/resources/application.yaml

@@ -237,7 +237,7 @@ hmpay:
   mer-no: 664403000025502
   app-private-key: MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJCaYSAw8c2uk4gry+/uy5thmzgdg1tPr6TRRj25AKxa13hnhjMEzp/eD8++LHxyPXg0ZXlbotZ/g0ES1XHJMkmHA4fRZ6Ki35LxlY60Z8xRwaTZXIctlaCkjhJmURNncQzyB5XMFF2M6cgy1T0yr+czoVPelVEFbAWu4cg/kQ1tAgMBAAECgYAGQwktsbDm7UZqQStFqpuakPF9zplfnOXIR1+5UIec7xohlqoTD4Q7HAynPF8EzJWo3OwAA13b2A3BBaXElafdwod7J2H9zlGJiqfmsnSTMhapVYsBbqnXGYWFS33wAm1Wx4Y9hSQxUD6AsZ+A05RiolrTTfAAGMS9E4sGhh1O6QJBANGUbGUednN4/0A0KlH3pWgLKPT+JyMeZLFGXeFLJpwWf25Xj98JcGai5t9sDqPl6xSgkEnJHdLB7LNEnmqr5X8CQQCwoaZwsVd0jnW6RU6F3SZ+BY4YS7SAhMlElqaJbBTP7DbXH/Z3cS1V696bvKup6+HlI/l0YwTDdRJIR0hl9XsTAkEAwFpPWkepQ7ZL36uBJBX9FA8aGjGhzhO5KxOAWqTU3PGxJ57qBzTsmubsqybMERWWuynbBD24R5WBH8/c7d6zFQJAShIP9TQ5Y5SWRB3qVvKtwK1dsEyXDkohCRVQE1Lyy1rYiJBL0Dzy8RQvzwlox6I2odvbMXaQudKvbwYNk0xFZwJAAxAeFweoXqDWcYl7Oa4nmgbM9LVqAMCbjzkChquXvj5q5sE9LOXiSMfbnDalNlLonbApnuTx5YCJYB0jA0ml8g==
   app-public-key: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCQmmEgMPHNrpOIK8vv7subYZs4HYNbT6+k0UY9uQCsWtd4Z4YzBM6f3g/Pvix8cj14NGV5W6LWf4NBEtVxyTJJhwOH0Weiot+S8ZWOtGfMUcGk2VyHLZWgpI4SZlETZ3EM8geVzBRdjOnIMtU9Mq/nM6FT3pVRBWwFruHIP5ENbQIDAQAB
-  public-key: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCLobxNslmsua5fnegILQSMioA5N0E5Kfg1hYLzhOuPdyJbFIImFkRF8RYt6Fp24LpDfpEEBhX8EGYIJSPpRWPZYVBzlGWOj1jS0FeF/JK+8a8ihgSxAU2JwsUySqGv+8aXIofJUus/j/KEPQZgjyVebi9J/ww75pbpGrymnAZUdwIDAQAB
+  hm-public-key: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCLobxNslmsua5fnegILQSMioA5N0E5Kfg1hYLzhOuPdyJbFIImFkRF8RYt6Fp24LpDfpEEBhX8EGYIJSPpRWPZYVBzlGWOj1jS0FeF/JK+8a8ihgSxAU2JwsUySqGv+8aXIofJUus/j/KEPQZgjyVebi9J/ww75pbpGrymnAZUdwIDAQAB
   notify-url: http://xiongzhu.frp.izouma.com/hmpay/notify
 ---
 

+ 43 - 0
src/test/java/com/izouma/nineth/HMPayTest.java

@@ -7,6 +7,7 @@ import com.alipay.api.internal.util.AlipaySignature;
 import com.github.kevinsawicki.http.HttpRequest;
 import com.izouma.nineth.utils.DateTimeUtils;
 import com.izouma.nineth.utils.SnowflakeIdWorker;
+import org.apache.commons.lang3.RandomStringUtils;
 import org.junit.jupiter.api.Test;
 
 import java.io.IOException;
@@ -117,4 +118,46 @@ public class HMPayTest {
         System.out.println(JSON.toJSONString(JSON.parseObject(body), true));
     }
 
+    @Test
+    public void queryOrder() {
+        Map<String, String> params = new HashMap<>();
+        params.put("app_id", "664403000025502");
+        params.put("method", "trade.query");
+        params.put("timestamp", DateTimeUtils.format(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss"));
+        params.put("nonce", RandomStringUtils.randomAlphabetic(32));
+        params.put("biz_content", "{\"out_order_no\":\"967114410067890176\"}");
+        params.put("sign", getSign(params));
+        String body = HttpRequest.post("https://hmpay.sandpay.com.cn/gateway/api")
+                .contentType("application/json")
+                .send(JSON.toJSONString(params)).body();
+        JSONObject res = JSON.parseObject(body);
+        System.out.println(JSON.toJSONString(res, true));
+
+        JSONObject data = res.getJSONObject("data");
+        System.out.println(JSON.toJSONString(data, true));
+    }
+
+    @Test
+    public void refund() {
+        Map<String, String> params = new HashMap<>();
+        params.put("app_id", "664403000025502");
+        params.put("method", "trade.refund");
+        params.put("timestamp", DateTimeUtils.format(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss"));
+        params.put("nonce", RandomStringUtils.randomAlphabetic(32));
+
+        Map<String, String> bizContent = new HashMap<>();
+        bizContent.put("out_order_no", "967126032563965952");
+        bizContent.put("refund_amount", "0.01");
+        bizContent.put("refund_request_no", "967126032563965952");
+        params.put("biz_content", JSON.toJSONString(bizContent));
+        params.put("sign", getSign(params));
+        String body = HttpRequest.post("https://hmpay.sandpay.com.cn/gateway/api")
+                .contentType("application/json")
+                .send(JSON.toJSONString(params)).body();
+        JSONObject res = JSON.parseObject(body);
+        System.out.println(JSON.toJSONString(res, true));
+
+        JSONObject data = res.getJSONObject("data");
+        System.out.println(JSON.toJSONString(data, true));
+    }
 }