java苹果通知V2新版协议实现订阅退款

1.需要在苹果后台配置通知地址,选v2版本协议

2.相关地址

用来解析调试接收到的signedPayload

JSON Web Tokens - jwt.io

新版通知协议地址 responseBodyV2DecodedPayload​​​​​​https://developer.apple.com/documentation/appstoreservernotifications/responsebodyv2decodedpayload

3.上代码

pom引用,用来解析苹果的jws数据

        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>

工具类

@Component
public class JwsUtil {

    private Logger logger = LoggerFactory.getLogger(this.getClass());
    public Jws<Claims> verifyJWT(String x5c, String jws){
        try {
            X509Certificate cert = getCert(x5c);
            if (!cert.getSubjectDN().getName().contains("Apple Inc")){
                logger.info("not apple cert . name = {}", cert.getIssuerX500Principal().getName());
                return null;
            }
            return Jwts.parser().setSigningKey(cert.getPublicKey()).parseClaimsJws(jws);
        }catch (JwtException exc){
            logger.info("jws verify failure.", exc);
            return null;
        } catch (Exception exc){
            logger.info("jws verify error.", exc);
            return null;
        }
    }

    public static X509Certificate getCert(String x5c) throws CertificateException {
        String stripped = x5c.replaceAll("-----BEGIN (.*)-----", "");
        stripped = stripped.replaceAll("-----END (.*)----", "");
        stripped = stripped.replaceAll("\r\n", "");
        stripped = stripped.replaceAll("\n", "");
        stripped.trim();
        byte[] keyBytes = Base64.getDecoder().decode(stripped);
        CertificateFactory fact = CertificateFactory.getInstance("X.509");
        return (X509Certificate) fact.generateCertificate(new ByteArrayInputStream(keyBytes));
    }
}

接收参数实体类

@Data
public class RefundIosDto {
   
    private String signedPayload;
}

接口代码

@PostMapping("/notification")
    public BaseResponse notification(@RequestBody RefundIosDto refundIosDto) {
        //记录每次的苹果通知请求
        AppleNotificationInfo appleNotificationInfo=new AppleNotificationInfo();
        appleNotificationInfo.setCreatetime(new Date());
        appleNotificationInfo.setContent(refundIosDto.getSignedPayload());

        appleNotificationService.insert(appleNotificationInfo);
        //解析苹果请求的数据
        String signedPayload=new String(com.google.api.client.util.Base64.decodeBase64(refundIosDto.getSignedPayload().split("\\.")[0]));
//        String result2=java.util.Base64.getUrlDecoder().decode(refundIosDto.getSignedPayload()).toString();
        JSONObject jsonObject=JSONObject.parseObject(signedPayload);
        ;
        Jws<Claims> result=jwsUtil.verifyJWT(jsonObject.getJSONArray("x5c").get(0).toString(),refundIosDto.getSignedPayload());
        System.out.println(result.toString());

        String notificationType=result.getBody().get("notificationType").toString();
        Claims map=result.getBody();
        HashMap<String,Object> envmap=map.get("data",HashMap.class);
        String env=envmap.get("environment").toString();
        String resulttran=new String(com.google.api.client.util.Base64.decodeBase64(envmap.get("signedTransactionInfo").toString().split("\\.")[0]));
        JSONObject jsonObjecttran=JSONObject.parseObject(resulttran);

        Jws<Claims> result3=jwsUtil.verifyJWT(jsonObjecttran.getJSONArray("x5c").get(0).toString(),envmap.get("signedTransactionInfo").toString());
        System.out.println(result3.getBody().toString());
//        HashMap<String,Object> orderMap=result3.getBody().("data",HashMap.class);
        logger.info("苹果通知类型:"+notificationType+"环境:"+env);

            if(notificationType.equals("DID_RENEW")) {
//查找原始订单的memberuid

//                VipOrder vipOrderinsert=new VipOrder();


                String transactionId = result3.getBody().get("transactionId").toString();
                String productId = result3.getBody().get("productId").toString();
                String originalTransactionId = result3.getBody().get("originalTransactionId").toString();
                VipOrder vipOrder = vipOrdrService.getOne(originalTransactionId, productId, "ios");
                if (Objects.nonNull(vipOrder)&&StringUtils.isNotBlank(productId) && StringUtils.isNotBlank(transactionId)) {//判重,避免重复分发内购商品。

                    //逻辑代码

                }
            }
            else if(notificationType.equals("REFUND")) {

                String originalTransactionId= result3.getBody().get("originalTransactionId").toString();
                String productId = result3.getBody().get("productId").toString();
               //逻辑代码
            }
            else {
                logger.info("notificationType未处理:" + notificationType);
            }


//        result.toLowerCase();
        return ReturnResponseUtil.Success(ReturnResponseUtil.SUCCESS, "success");

    }

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
苹果橘子问题是一个经典的多线程同步问题,假设有一个篮子,里面装有若干个苹果和橘子,现在有两个人要从篮子里取出水果,一个人只能拿苹果,另一个人只能拿橘子,直到篮子里的水果被取完为止。 Java中可以使用wait()和notify()方法来实现多线程同步,具体实现如下: ``` public class Basket { private int appleCount; // 苹果数量 private int orangeCount; // 橘子数量 public synchronized void getApple() { while (appleCount == 0) { try { wait(); // 等待苹果 } catch (InterruptedException e) { e.printStackTrace(); } } appleCount--; System.out.println("取出一个苹果,还剩" + appleCount + "个苹果"); notifyAll(); // 唤醒其他线程 } public synchronized void getOrange() { while (orangeCount == 0) { try { wait(); // 等待橘子 } catch (InterruptedException e) { e.printStackTrace(); } } orangeCount--; System.out.println("取出一个橘子,还剩" + orangeCount + "个橘子"); notifyAll(); // 唤醒其他线程 } public synchronized void put(String fruit, int count) { if ("apple".equals(fruit)) { appleCount += count; System.out.println("放入" + count + "个苹果,还剩" + appleCount + "个苹果"); } else if ("orange".equals(fruit)) { orangeCount += count; System.out.println("放入" + count + "个橘子,还剩" + orangeCount + "个橘子"); } notifyAll(); // 唤醒其他线程 } } public class AppleThread extends Thread { private Basket basket; public AppleThread(Basket basket) { this.basket = basket; } @Override public void run() { while (true) { basket.getApple(); } } } public class OrangeThread extends Thread { private Basket basket; public OrangeThread(Basket basket) { this.basket = basket; } @Override public void run() { while (true) { basket.getOrange(); } } } public class Main { public static void main(String[] args) { Basket basket = new Basket(); new AppleThread(basket).start(); new OrangeThread(basket).start(); for (int i = 0; i < 10; i++) { basket.put("apple", 1); basket.put("orange", 1); } } } ``` 在上面的代码中,Basket类是共享资源,getApple()和getOrange()方法是消费者线程,put()方法是生产者线程。当苹果或橘子被取走后,消费者线程会调用notifyAll()方法来唤醒其他线程,生产者线程在放入水果时也会调用notifyAll()方法来唤醒其他线程。通过wait()和notify()方法的配合,可以实现多线程同步,保证线程安全。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值