我们明白了微信支付的一些基础概念,只有先创建好支付订单,然后用户才能付款,所以这节课我们来实现创建支付订单的后端代码。
首先你要明白一个概念,支付订单是由商户系统调用微信支付接口创建的,所以写代码之前,我们必须要了解微信支付的API接口规范,需要我们提交什么参数,返回什么结果。
一、创建支付订单的API接口
大家可以用浏览器访问微信支付的API手册(https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1),查阅具体的调用规范。因为其中有很多非必要的参数,所以我整理了一下,我们看下面的表格。
参数 | 含义 | 类型 | 例子 |
---|---|---|---|
appid | 公众号ID | String | wxd678efh567hg6787 |
mch_id | 商户号ID | String | 1230000109 |
nonce_str | 随机字符串 | String | 5K8264ILTKCH16CQ2502SI8ZNMTM67VS |
sign | 签名 | String | C380BEC2BFD727A4B6845133519F3AD6 |
body | 商品订单描述 | String | QQ会员充值 |
out_trade_no | 商品订单号 | String | 20150806125346 |
total_fee | 订单金额 | int | 150 |
spbill_create_ip | 终端IP | String | 123.12.12.123 |
notify_url | 通知地址 | String | http://140.143.132.225:8000/project-1/doc-110/ |
trade_type | 交易类型 | String | NATIVE |
微信支付平台给我们返回的响应中包含了下面这些参数。
参数 | 含义 | 类型 | 例子 |
---|---|---|---|
return_code | 通信状态码 | String | SUCCESS |
result_code | 业务状态码 | String | SUCCESS |
app_id | 微信公众账号APPID | String | wx8888888888888888 |
mch_id | 商户ID | String | 1900000109 |
nonce_str | 随机字符串 | String | 5K8264ILTKCH16CQ2502SI8ZNMTM67VS |
sign | 数字签名 | String | C380BEC2BFD727A4B6845133519F3AD6 |
trade_type | 交易类型 | String | NATIVE |
prepay_id | 支付订单ID | String | wx201410272009395522657a690389285100 |
二、定义值注入
在application.yml
文件中,定义值注入内容,这些内容必须都是QQ群里面企业身份的。
wx:
app-id: 企业身份APPID
app-secret: 企业身份密钥
mch-id: 企业身份商户号ID
key: 企业身份微信支付的密钥
cert-path: 企业身份微信支付的数字证书路径
然后大家创建com.example.emos.api.wxpay
包,把课程GIT上面的微信支付工具类放入这个包。
三、编写持久层代码
在TbAmectDao.xml
文件中,声明SQL语句。
<select id="searchAmectByCondition" parameterType="HashMap" resultType="HashMap">
SELECT uuid,
amount,
prepay_id AS prepayId,
`status`
FROM tb_amect
WHERE id = #{amectId}
AND user_id = #{userId}
<if test="status!=null">
AND `status` = #{status}
</if>
</select>
<update id="updatePrepayId" parameterType="HashMap">
UPDATE tb_amect
SET prepay_id = #{prepayId}
WHERE id = #{amectId} AND status = 1
</update>
在TbAmectDao.java
接口中,声明DAO方法。
public interface TbAmectDao {
……
public HashMap searchAmectByCondition(HashMap param);
public int updatePrepayId(HashMap param);
}
四、编写业务层代码
在AmectService.java
接口中,定义抽象方法。
public interface AmectService {
……
public String createNativeAmectPayOrder(HashMap param);
}
在AmectServiceImpl.java
类中,实现抽象方法,创建支付订单。
public class AmectServiceImpl implements AmectService {
@Autowired
private MyWXPayConfig myWXPayConfig;
……
@Override
public String createNativeAmectPayOrder(HashMap param) {
int userId = MapUtil.getInt(param, "userId");
int amectId = MapUtil.getInt(param, "amectId");
//根据罚款单ID和用户ID查询罚款单记录
HashMap map = amectDao.searchAmectByCondition(param);
if (map != null && map.size() > 0) {
String amount = new BigDecimal(MapUtil.getStr(map, "amount")).multiply(new BigDecimal("100")).intValue() + "";
try {
WXPay wxPay = new WXPay(myWXPayConfig);
param.clear();
param.put("nonce_str", WXPayUtil.generateNonceStr()); //随机字符串
param.put("body", "缴纳罚款");
param.put("out_trade_no", MapUtil.getStr(map, "uuid"));
param.put("total_fee", amount);
param.put("spbill_create_ip", "127.0.0.1");
param.put("notify_url", "http://s1.nsloop.com:35750/emos-api/amect/recieveMessage");
param.put("trade_type", "NATIVE");
String sign = WXPayUtil.generateSignature(param, myWXPayConfig.getKey());
param.put("sign", sign);
Map<String, String> result = wxPay.unifiedOrder(param); //创建支付订单
String prepayId = result.get("prepay_id"); //微信订单ID
String codeUrl = result.get("code_url"); //支付连接,需要生成二维码让手机扫码
if (prepayId != null) {
param.clear();
param.put("prepayId", prepayId);
param.put("amectId", amectId);
int rows = amectDao.updatePrepayId(param);
if (rows != 1) {
throw new EmosException("更新罚款单的支付订单ID失败");
}
//把支付订单的URL生成二维码
QrConfig qrConfig = new QrConfig();
qrConfig.setWidth(255);
qrConfig.setHeight(255);
qrConfig.setMargin(2);
String qrCodeBase64 = QrCodeUtil.generateAsBase64(codeUrl, qrConfig, "jpg");
return qrCodeBase64;
} else {
log.error("创建支付订单失败", result);
throw new EmosException("创建支付订单失败");
}
} catch (Exception e) {
log.error("创建支付订单失败", e);
throw new EmosException("创建支付订单失败");
}
} else {
throw new EmosException("没有找到罚款单");
}
}
}