上个小节我们看到了弹窗页面上显示的付款二维码,用户拿微信扫描二维码就可以去付款了。在付款之前,我们要把接收付款通知的后端代码写了。要不然,用户付完款,后端系统不接收付款结果通知,岂不是用户白白付了款,但是罚款还是未支付的状态?
一、编写持久层代码
在TbAmectDao.xml
文件中,定义SQL语句,用于修改罚款状态。
<update id="updateStatus" parameterType="HashMap">
UPDATE tb_amect
SET status = #{status}
WHERE uuid = #{uuid}
</update>
在TbAmectDao.java
接口中,声明DAO方法。
public interface TbAmectDao {
……
public int updateStatus(HashMap param);
}
二、编写业务层代码
在AmectService.java
接口中,定义抽象方法。
public interface AmectService {
……
public int updateStatus(HashMap param);
}
在AmectServiceImpl.java
类中,实现抽象方法。
public class AmectServiceImpl implements AmectService {
……
@Override
public int updateStatus(HashMap param) {
int rows = amectDao.updateStatus(param);
return rows;
}
}
三、编写Web层代码
微信平台发送付款结果通知的Request里面是XML格式的数据,所以我们要从中提取出我们需要的关键数据,这部分的文档规范,大家可以查阅微信支付的官方资料(https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_7&index=8)。而且这个请求并不是只发送一次,如果商户系统没有接收到请求,微信平台会每隔一小段时间再发送一次付款结果。
参数 | 含义 | 类型 | 示例 |
---|---|---|---|
return_code | 通信状态码 | String | SUCCESS |
result_code | 业务状态吗 | String | SUCCESS |
sign | 数字签名 | String | C380BEC2BFD727A4B6845133519F3AD6 |
out_trade_no | 商品订单ID | String | 1212321211201407033568112322 |
transaction_id | 支付订单ID | String | 1217752501201407033233368018 |
total_fee | 订单金额 | int | 150 |
time_end | 支付的时间 | String | 20141030133525 |
<xml>
<appid><![CDATA[wx2421b1c4370ec43b]]></appid>
<attach><![CDATA[支付测试]]></attach>
<bank_type><![CDATA[CFT]]></bank_type>
<fee_type><![CDATA[CNY]]></fee_type>
<is_subscribe><![CDATA[Y]]></is_subscribe>
<mch_id><![CDATA[10000100]]></mch_id>
<nonce_str><![CDATA[5d2b6c2a8db53831f7eda20af46e531c]]></nonce_str>
<openid><![CDATA[oUpF8uMEb4qRXf22hE3X68TekukE]]></openid>
<out_trade_no><![CDATA[1409811653]]></out_trade_no>
<result_code><![CDATA[SUCCESS]]></result_code>
<return_code><![CDATA[SUCCESS]]></return_code>
<sign><![CDATA[B552ED6B279343CB493C5DD0D78AB241]]></sign>
<time_end><![CDATA[20140903131540]]></time_end>
<total_fee>1</total_fee>
<coupon_fee><![CDATA[10]]></coupon_fee>
<coupon_count><![CDATA[1]]></coupon_count>
<coupon_type><![CDATA[CASH]]></coupon_type>
<coupon_id><![CDATA[10000]]></coupon_id>
<trade_type><![CDATA[JSAPI]]></trade_type>
<transaction_id><![CDATA[1004400740201409030005092168]]></transaction_id>
</xml>
返回给微信平台的响应内容也必须是XML格式的,否则微信平台就会认为你没收到付款结果通知。
<xml>
<return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
</xml>
我们需要创建一个Web方法来接收微信平台发送过来的付款结果通知,所以我们找到AmectController.java
类,然后声明Web方法。
public class AmectController {
@Value("${wx.key}")
private String key;
……
@Operation(summary = "接收消息通知")
@RequestMapping("/recieveMessage")
public void recieveMessage(HttpServletRequest request, HttpServletResponse response) throws Exception {
request.setCharacterEncoding("utf-8");
Reader reader = request.getReader();
BufferedReader buffer = new BufferedReader(reader);
String line = buffer.readLine();
StringBuffer temp = new StringBuffer();
while (line != null) {
temp.append(line);
line = buffer.readLine();
}
buffer.close();
reader.close();
String xml = temp.toString();
//利用数字证书验证收到的响应内容,避免有人伪造付款结果发送给Web方法。
if (WXPayUtil.isSignatureValid(xml, key)) {
Map<String, String> map = WXPayUtil.xmlToMap(temp.toString());
String resultCode = map.get("result_code");
String returnCode = map.get("return_code");
if ("SUCCESS".equals(resultCode) && "SUCCESS".equals(returnCode)) {
String outTradeNo = map.get("out_trade_no"); //罚款单UUID
//更新订单状态
HashMap param = new HashMap() {{
put("status", 2);
put("uuid", outTradeNo);
}};
int rows = amectService.updateStatus(param);
if (rows == 1) {
//TODO 向前端页面推送付款结果
//给微信平台返回响应
response.setCharacterEncoding("utf-8");
response.setContentType("application/xml");
Writer writer = response.getWriter();
BufferedWriter bufferedWriter = new BufferedWriter(writer);
bufferedWriter.write("<xml><return_code><![CDATA[SUCCESS]]></return_code> <return_msg><![CDATA[OK]]></return_msg></xml>");
bufferedWriter.close();
writer.close();
} else {
log.error("更新订单状态失败");
response.sendError(500, "更新订单状态失败");
}
}
} else {
log.error("数字签名异常");
response.sendError(500, "数字签名异常");
}
}
}