使用Spring控制器处理Paypal IPN请求



我想扩展Spring应用程序的功能,以包括一个接收Paypal即时支付通知的HTTP端点。

Paypal在HTTP正文中发送这些消息,如下所示:

mc_gross=19.95&protection_requality=合格&address_status=已确认&payer_id=LPLWNMTBWMFAY&税=0.00&address_street=1+Main+St&payment_ date=20%3A12%3A59+Jan+13%2C+2009+PST&payment_status=已完成&charset=windows-1252&address_zip=95131&first_name=测试&ee=0.88&address_country_code=美国&address_name=测试+用户&notify_ version=2.6&custom=&payer_status=已验证&address_country=美国+美国&address_city=圣何塞&数量=1&verify_sign=AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS6nMXgysbElEn9v-1XcmSoGtf&payer_email=gpmac_1231902590_per%40paypal.com&txn_id=61E67681CH3238416&payment_type=即时&last_name=用户&address_state=CA&receiver_email=gpmac_1231902686_biz%40paypal.com&payment_fee=0.88&receiver_ id=S8XGHLYDW9T3S&txn_type=express_checkout&项目名称=&mc_currency=美元&item_number=&residence_country=US&test_ipn=1&handling_amount=0.00&transaction_subject=&payment_gross=19.95&运费=0.00

https://developer.paypal.com/docs/classic/ipn/integration-guide/IPNIntro/

我是否需要定义一个具体的类来定义请求主体,例如

请求类

    public class PaypalIPNRequest {
    private static final long serialVersionUID = 1L;
    private String mc_gross;
    private String protection_eligibility;
    private String address_street;
    ...

    public PaypalIPNRequest() {
    }
    //getters setters
}

控制器

@Override
@Auditable
@RequestMapping(value = "/ipnRequest.do", method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.OK)
public void ipnRequest(@RequestBody final PaypalIPNRequest request) {
}

如本SO答案所述:Spring 中的@RequestBody和@ResponseBody注释

如果Paypal在未来更改他们的IPN请求,会发生什么?

有没有更好的方法可以在没有特定类的情况下传递请求体?

我可以使用HttpServlet请求吗?

我过去所做的是使用com.paypal.base.ipn.IPNMessage来验证并从请求中检索(就像您提出的那样)对我来说重要的字段,而不是将整个请求体映射到一个具体的类,即:

private final static String PAYPAL_WEB_IPN_TXN_PARAM = "txn_id";
private final static String PAYPAL_WEB_IPN_AMOUNT_PARAM = "mc_gross";
private final static String PAYPAL_WEB_IPN_PAYMENT_STATUS_PARAM = "payment_status";
private final static String PAYPAL_WEB_IPN_PAYMENT_STATUS = "Completed";
@Resource(name = "payPalConfigurationMap")
private Map<String, String> configurationMap;
private OAuthTokenCredential oAuthTokenCredential;
@PostConstruct
public void init() {
    Properties properties = new Properties();
    properties.putAll(configurationMap);
    PayPalResource.initConfig(properties);
    oAuthTokenCredential = new OAuthTokenCredential(
            configurationMap.get(Constants.CLIENT_ID),
            configurationMap.get(Constants.CLIENT_SECRET),
            configurationMap
    );
}

public DonationDTO validateWebIPN(HttpServletRequest request) throws Exception {
    IPNMessage ipnlistener = new IPNMessage(request, configurationMap);
    boolean isIpnVerified = ipnlistener.validate();
    String paymentStatus = ipnlistener.getIpnValue(PAYPAL_WEB_IPN_PAYMENT_STATUS_PARAM);
    if (isIpnVerified && paymentStatus.equalsIgnoreCase(PAYPAL_WEB_IPN_PAYMENT_STATUS)) {
        String amount = ipnlistener.getIpnValue(PAYPAL_WEB_IPN_AMOUNT_PARAM);
        String tx = ipnlistener.getIpnValue(PAYPAL_WEB_IPN_TXN_PARAM);
        // irrelevant code
        return donationDTO;
    }else{
        String exceptionMessage = "Problem when requesting info from PayPal service";
        logger.error(exceptionMessage);
        throw new Exception(exceptionMessage);
    }
}

这样,除非Paypal更改字段的名称(这不应该发生),否则您不会有任何问题。

最新更新