全部开发者教程

企业级在线办公系统

上个小节我们看到了弹窗页面上显示的付款二维码,用户拿微信扫描二维码就可以去付款了。在付款之前,我们要把接收付款通知的后端代码写了。要不然,用户付完款,后端系统不接收付款结果通知,岂不是用户白白付了款,但是罚款还是未支付的状态?

图片描述

一、编写持久层代码

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, "数字签名异常");
        }
    }
}