我想扩展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=测试+用户¬ify_ 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更改字段的名称(这不应该发生),否则您不会有任何问题。