1. 准备工作
微信公众平台配置appid;
商户平台配置:MCH_ID ,api_key,和notify_url(微信支付的支付结果 异步回调地址);
2. 生成订单,调用微信统一下单接口
//统一下单接口地址
public static String UFDODER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
/**
*这是统一下单参数
* @param 公众账号ID appid String(32)
* @param 商户号 mch_id String(32)
* @param 随机字符串 nonce_str String(32)
* @param 签名 sign String(32)
* @param 商品描述 body String(128)
* @param 商户订单号 out_trade_no String(32)
* @param 标价金额 total_fee Int 88 单位 分
* @param 终端IP spbill_create_ip String(16)
* @param 通知地址 notify_url String(256)
* @param 交易类型 trade_type String(16) NATIVE 扫码支付
*/
appid 已知;mchid 已知;notify_url 已知 ; trade_type 固定;
随机字符串 nonce_str 无要求 保证随机性即可
body (内容),out_trade_no(订单号) ,total_fee(总价格/分) 三个参数与业务相关,测试环境可设简单点
以上八个参数放入map中(sign除外),对map进行遍历,去除非空参数生成一个 key1=value1& key2=value2…格式的字符串 sb.append("key=" + API_KEY);然后对此字符串MD5加密,统一编码,并转成大写 生成签名sign(字符串格式);
将sign添加至map中。
Map转为xml格式(工具类);
然后发起请求,调统一下单接口(参数:xml);
接收到的也是xml格式响应。
解析为map,取出xml中的code_url值(利用此链接可以生成二维码);
将code_url和业务结果(code,out_trade_no)一并存入json返回给前台。
3. 用户支付完成后,微信异步通知notify_url,告诉我们支付结果。
InputStream inputStream ;
StringBuffer sb = new StringBuffer();
//接收微信数据流
inputStream = request.getInputStream();
String s ;
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
while ((s = in.readLine()) != null){
sb.append(s);
}
in.close();
inputStream.close();
微信异步通知以数据流的形式返回给我们。
//解析xml成map
Map m = new HashMap();
m = XMLUtil.doXMLParse(sb.toString());
拿到相应内容里面的签名。与之前签名进行匹配。如果匹配,进行业务逻辑操作。
4.前台收到链接生成二维码,并拿到订单号轮询调后台查询订单接口去查询支付结果。
5.后台重复调用订单查询接口:
Appid,mchid,随机数,订单号,并进行签名,发送请求,接收到相应内容,转成xml,
获取里面的参数(trade_state,trade_state_desc)等,如果"SUCCESS".equalsIgnoreCase(trade_state),
代表查询到订单状态为成功,那么告诉前台,进行业务操作
@Service("wechatpayService")
public class WeChatPayServiceImpl extends SihealService {
// 企业方公众号Id
private final static String APP_ID = "xxxxxxxxxxxxxxxxxx";
//财付通平台的商户账号
private final static String MCH_ID = "xxxxxxxxxxxxxxxxxx";
//财付通平台的商户密钥
private final static String API_KEY = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
//回调URL
private final static String NOTIFY_URL = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
//查询订单URL
private final static String ORDER_QUERY_URL = "https://api.mch.weixin.qq.com/pay/orderquery";
private static final Logger LOG = Logger.getLogger(WeChatPayServiceImpl.class);
@Autowired
private OrderDaoImpl orderDao;
/**
* 微信支付调下单API,生成二维码链接
*
* @param order
* @return String
*/
public String payBySihealDynamicQrCode(TOrder order) throws AssertException {
try {
// (必填)商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|* 且在同一个商户号下唯一。
String outTradeNo = order.getNo();
String body = "xxxx";//商品名称
String total_fee = (int) (order.getPayPrice() * 100) + "";//标价金额,以分为单位
//构建请求参数
Map param = new HashMap<>();
param.put("appid", APP_ID);
param.put("mch_id", MCH_ID);
param.put("nonce_str", WXPayUtil.generateNonceStr());
param.put("body", body);
param.put("out_trade_no", outTradeNo);
param.put("total_fee", total_fee);
param.put("spbill_create_ip", "127.0.0.1");
param.put("notify_url", NOTIFY_URL);
param.put("trade_type", "NATIVE");
//将map转换成xml
String xml = WXPayUtil.generateSignedXml(param, API_KEY);
System.out.println("发送给微信的参数" + xml);
//发送请求调用统一下单接口
HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");
client.setXmlParam(xml);
client.setHttps(true);
client.post();
//返回结果
String xmlResult = client.getContent();
//将xml字符串转换成map集合
Map result = WXPayUtil.xmlToMap(xmlResult);
System.out.println("微信支付返回的参数" + result);
if ("SUCCESS".equalsIgnoreCase((String) result.get("result_code"))) {
LOG.error("微信扫码下单成功");
//生成二维码
ZxingUtils.getQRCodeImge(result.get("code_url").toString(), 256, "C:\\Users\\Administrator\\Desktop\\qrcode.png");
return result.get("code_url").toString();
} else {
LOG.error("微信扫码下单失败");
order.setOrderStatus(Constants.ORDER_STATUS_CREATE_FAILED);
orderDao.SaveOrUpdate(order);
throw new AssertException(Result.ERROR_WECHAT_ORDER_ERROR);
}
} catch (Exception ex) {
LOG.error(ex.getMessage());
order.setOrderStatus(Constants.ORDER_STATUS_CREATE_FAILED);
orderDao.SaveOrUpdate(order);
throw new AssertException(Result.ERROR_WECHAT_ORDER_ERROR);
}
}
/**
* 微信支付查询订单状态
*
* @param order
* @return TOrder
*/
public TOrder getOrderStatus(TOrder order) throws Exception {
//1.构建请求参数,
String out_trade_no = order.getNo();
LOG.warn("构建请求参数,查询订单,订单号为:" + out_trade_no);
Map param = new HashMap<>();
param.put("appid", APP_ID);
param.put("mch_id", MCH_ID);
// 随机数 nonce_str
String nonce_str = WXPayUtil.generateNonceStr();
param.put("nonce_str", nonce_str);
//订单号
param.put("out_trade_no", out_trade_no);
//将map转换成xml
String xml = WXPayUtil.generateSignedXml(param, API_KEY);
LOG.info("查询订单的入参为:" + xml);
//调用查询订单API
HttpClient client = new HttpClient(ORDER_QUERY_URL);
client.setXmlParam(xml);
client.setHttps(true);
client.post();
//返回结果
String xmlResult = client.getContent();
//将xml字符串转换成map集合
Map map = WXPayUtil.xmlToMap(xmlResult);
System.out.println("查询订单返回参数:" + map);
//return_code通信标识,非交易标识,交易是否成功需要查看trade_state来判断
String return_code = (String) map.get("return_code");
//交易状态,如trade_state不为 SUCCESS,则只返回out_trade_no(必传)和attach(选传)。
String trade_state = (String) map.get("trade_state");
LOG.info("交易状态为:" + trade_state);
switch (trade_state) {
case "SUCCESS":
//支付成功
String trade_state_desc = (String) map.get("trade_state_desc");
LOG.info("trade_state_desc:" + trade_state_desc + ",查询返回该订单支付成功!");
order.setPayStatus(Constants.PAYMENT_STATUS_PAID);
orderDao.SaveOrUpdate(order);
break;
case "NOTPAY":
//未支付
LOG.info("查询返回该订单未支付");
order.setPayStatus(Constants.PAYMENT_STATUS_UNPAY);
orderDao.SaveOrUpdate(order);
break;
case "USERPAYING":
//用户支付中
LOG.info("查询返回该订单未支付");
order.setPayStatus(Constants.PAYMENT_STATUS_UNPAY);
orderDao.SaveOrUpdate(order);
break;
case "REFUND":
//转入退款
break;
case "CLOSED":
LOG.error("查询返回该订单被关闭!!!");
order.setOrderStatus(Constants.ORDER_STATUS_CLOSED);
orderDao.SaveOrUpdate(order);
break;
case "PAYERROR":
//支付失败
break;
default:
LOG.error("不支持的交易状态,交易返回异常!!!");
break;
}
return order;
}
/**
* 微信支付异步回调
*
* @param request
* @param response
*/
public void onPaymentStatusChanged(HttpServletRequest request, HttpServletResponse response) throws IOException, Exception {
//读取参数
LOG.info("微信异步通知商户后台,读取通知参数,获得xml字符串");
System.out.println("微信异步通知商户后台,读取通知参数,获得xml字符串");
InputStream inputStream;
StringBuilder sb = new StringBuilder();
//接收微信数据流,获得xml字符串
inputStream = request.getInputStream();
String s;
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
while ((s = in.readLine()) != null) {
sb.append(s);
}
in.close();
inputStream.close();
LOG.info("接收到xml字符串为:" + sb.toString());
//解析xml成map
Map m = new HashMap<>();
m = WXPayUtil.xmlToMap(sb.toString());
//过滤空 设置 TreeMap
SortedMap