微信App支付服务端详解
引言
主要实现app支付统一下单、异步通知、调起支付接口、支付订单查询、申请退款、查询退款功能;封装了https对发起退款的证书校验、签名、xml解析等。
支付流程
具体支付流程参考“微信APP”文档,文档地址
APP支付:APP端点击下单—-服务端生成订单,并调起“统一下单”,返回app支付所需参数—–APP端“调起支付接口“,发起支付—-微信服务器端调用服务端回调地址—–服务端按照“支付结果通知”,处理支付结果
app查询:调起“查询订单”
APP退款:发起退款请求,调用“申请退款”,发起退款,需双向证书验证
APP退款查询:调起“查询退款”
支付代码实现
代码实现签名、证书校验、http和https封装等,项目结构如下:
支付代码
包含支付、支付查询、异步通知、退款申请、退款查询
package org.andy.wxpay.controller;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.andy.wxpay.model.JsonResult;
import org.andy.wxpay.model.ResponseData;
import org.andy.wxpay.utils.CollectionUtil;
import org.andy.wxpay.utils.ConfigUtil;
import org.andy.wxpay.utils.FileUtil;
import org.andy.wxpay.utils.HttpUtils;
import org.andy.wxpay.utils.PayUtil;
import org.andy.wxpay.utils.SerializerFeatureUtil;
import org.andy.wxpay.utils.StringUtil;
import org.andy.wxpay.utils.WebUtil;
import org.andy.wxpay.utils.XmlUtil;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import com.alibaba.fastjson.JSON;
/**
* 创建时间:2016年11月2日 下午4:16:32
*
* @author andy
* @version 2.2
*/
@Controller
@RequestMapping("/order")
public class PayController {
private static final Logger LOG = Logger.getLogger(PayController.class);
private static final String ORDER_PAY = "https://api.mch.weixin.qq.com/pay/unifiedorder"; // 统一下单
private static final String ORDER_PAY_QUERY = "https://api.mch.weixin.qq.com/pay/orderquery"; // 支付订单查询
private static final String ORDER_REFUND = "https://api.mch.weixin.qq.com/secapi/pay/refund"; // 申请退款
private static final String ORDER_REFUND_QUERY = "https://api.mch.weixin.qq.com/pay/refundquery"; // 申请退款
private static final String APP_ID = ConfigUtil.getProperty("wx.appid");
private static final String MCH_ID = ConfigUtil.getProperty("wx.mchid");
private static final String API_SECRET = ConfigUtil.getProperty("wx.api.secret");
/**
* 支付下订单
*
* @param request
* @param response
* @param cashnum
* 支付金额
* @param mercid
* 商品id
* @param callback
*/
@RequestMapping(value = "/pay", method = RequestMethod.POST)
public void orderPay(HttpServletRequest request, HttpServletResponse response,
@RequestParam(required = false, defaultValue = "0") Double cashnum, String mercid, String callback) {
LOG.info("[/order/pay]");
if (!"001".equals(mercid)) {
WebUtil.response(response, WebUtil.packJsonp(callback, JSON
.toJSONString(new JsonResult(-1, "商品不存在", new ResponseData()), SerializerFeatureUtil.FEATURES)));
}
Map<String, String> restmap = null;
boolean flag = true; // 是否订单创建成功
try {
String total_fee = BigDecimal.valueOf(cashnum).multiply(BigDecimal.valueOf(100))
.setScale(0, BigDecimal.ROUND_HALF_UP).toString();
Map<String, String> parm = new HashMap<String, String>();
parm