回调:分布式事物解决方案。
1、通知结果:分为
同步通知: 以浏览器方式重定向到网站上去。
异步通知:支付宝会以httpclient技术更改订单状态。
为什么项目要做服务化?
服务化的好处是把共同的代码抽象出来封装成接口给别人调用。
扩展性高,降低耦合性。
分布式事物:
A B两个支付服务,调用订单服务进行订单状态更改
payInfo.update();
orderInfoClient.update();---http协议
当orderInfoClient.update()没有问题的时候,会发出一个通知给payInfo.update(),
这个时候两个服务就会一起提交事物。
当orderInfoClient.update()有问题的时候,也会发出通知给payInfo.update(),这个时候就会一起
回滚事物。
MQ解决分布式事物。 它自身有重试机制。我们只需要处理接口幂等性就好了。
订单信息表中有个state状态。为0就是没有支付 1表示已支付。
aliPayInfo.update();支付宝数据库支付信息状态已经变成已支付
会以httpclient.回调接口,异步通知通过回调接口,把订单状态告诉给网站。
同步回调代码书写过程:
首先肯定是要在api工程中创建一个专门做回调的api接口。
在实现类中实现:
@Override
@ResponseBody
public ResponseBase synCallBack(@RequestParam Map params) {
try {
// 1.日志记录
log.info("####支付宝同步通知synCallBack####开始,params:{}", params);
// 2.验签操作
boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.alipay_public_key,
AlipayConfig.charset, AlipayConfig.sign_type); // 调用SDK验证签名
log.info("####支付参数验签signVerified:{}####",signVerified);
// ——请在这里编写您的程序(以下代码仅作参考)——
if (!signVerified) {
return setResultError("验签失败!");
}
// 商户订单号
String outTradeNo = params.get("outTradeNo");
// 支付宝交易号
String tradeNo = params.get("tradeNo");
// 付款金额
String totalAmount = params.get("totalAmount");
JSONObject data = new JSONObject();
data.put("outTradeNo", outTradeNo);
data.put("tradeNo", tradeNo);
data.put("totalAmount", totalAmount);
return setResultSuccess(data);
} catch (Exception e) {
log.info("####支付宝支付异常####,异常原因:{}", e);
return setResultError("系统错误");
} finally {
// 不管是否有错,都会打印
log.info("####支付宝同步通知synCallBack####结束,params:{}", params);
}
}
整合到PCweb上去
支付流程:首先网站生成支付token,然后调用支付宝支付接口,支付完成后有同步回调和异步回调。
支付回调的时候使用的同步回调是使用了GET,所以回传过来的信息会在地址栏上,可见。
这样不安全。
所以要使用from表单隐藏回调参数,在内部使用post提交。
优化代码变成在内部进行post进行转发提交。
/**
* 支付宝 同步回调通知 封装成form表单来进行提交
*
* @return
* @throws IOException
*/
@RequestMapping("/returnUrl")
public void synCallBack(HttpServletRequest request, HttpServletResponse response)
throws IOException {
// 获取支付宝GET过来反馈信息
log.info("#####支付宝同步回调接口CallBackController#####synCallBack开始");
// 设置成这种格式才能解析成网页
response.setContentType("text/html;charset=utf-8");
Map params = new HashMap();
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);
}
log.info("#####支付宝同步回调接口CallBackController#####synCallBack接受参数params:{}", params);
ResponseBase synCallBackResponseBase = callBackServiceFegin.synCallBack(params);
log.info("#####支付宝同步回调接口CallBackController#####synCallBack结束");
if (!synCallBackResponseBase.getRtnCode().equals(Constants.HTTP_RES_CODE_200)) {
// 如果是200直接返回的是报错页面
request.setAttribute("error", synCallBackResponseBase.getMsg());
return;
}
LinkedHashMap data = (LinkedHashMap) synCallBackResponseBase.getData();
// 商户订单号
String outTradeNo = (String) data.get("outTradeNo");
// 支付宝交易号
String tradeNo = (String) data.get("tradeNo");
// 交易金额
String totalAmount = (String) data.get("totalAmount");
// 将这些内容转发到页面上去
request.setAttribute("outTradeNo", outTradeNo);
request.setAttribute("tradeNo", tradeNo);
request.setAttribute("totalAmount", totalAmount);
// 封装成html 浏览器模拟去提交
String formHtml = " ";
//封装成POST 表单后,在页面上进行渲染出来
PrintWriter writer = response.getWriter();
writer.write(formHtml);
writer.close();
}
/**
* 以post回调,隐藏参数
*
* @return
*/
@RequestMapping(value = "synSuccessPage", method = RequestMethod.POST)
public String synSuccessPage(HttpServletRequest request, String outTradeNo, String tradeNo, String totalAmount) {
log.info("####以POST提交了回调支付信息表单了 synSuccessPage#####");
// 将这些内容转发到页面上去
request.setAttribute("outTradeNo", outTradeNo);
request.setAttribute("tradeNo", tradeNo);
request.setAttribute("totalAmount", totalAmount);
return PAY_SUCCESS;
}
封装回写成html记住
已经成功换行了