微信支付
去年开发的小程序支付项目,一直没空梳理
需要申请商家支付服务
查看开发文档流程
流程:
->用户在购物车页点击支付
-> 这时调起我们写的接口(用户所携带的商品id,金额等等参数携带到服务器)
-> 这时业务操作可以在这里实现,比如生成订单 -> 商户后台收到用户支付单,(需要填上支付成功回调接口)调用微信支付统一下单接口
-> 发送post请求"统一下单接口"返回预支付id:prepay_id (需要把参与签名的字段名为appid,partnerid,prepayid,noncestr,timestamp,package 返回给前端 然后唤起支付页面)
-> 前端支付成功后会走支付回调接口
使用Java开发微信支付
demo工具类下载
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1
支付参数
@Data
public class Pay {
public String openid;
private Long id;
private Long customerViewingRecordId;
private Long userId;
private Integer type;
private String ordersNo;
private String frontIdCardUrl;
private String backIdCardUrl;
private String contractUrl;
private String idCard;
private String contactName;
private String phoneNumber;
}
开发接口如下
@Slf4j
@Api(tags = "app支付功能")
@RestController
@RequestMapping("/payment/")
public class PaymentController {
@Resource
private Environment environment;
/*调用支付接口*/
@ApiOperation(httpMethod = "POST", value = "调用支付接口")
@RequestMapping(value = "prePay", method = RequestMethod.POST)
public Map<String, Object> prePay(@RequestBody Pay pay,HttpServletRequest request){
log.info("调用支付接口");
// 返回参数
Map<String, Object> resMap = new HashMap<>();
//获取当前请求ip地址
String ip = request.getHeader("x-forwarded-for");
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
ip = request.getHeader("Proxy-Client-IP");
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
ip = request.getHeader("WL-Proxy-Client-IP");
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
ip = request.getRemoteAddr();
}
if(ip.indexOf(",")!=-1){
String[] ips = ip.split(",");
ip = ips[0].trim();
}
try {
//业务需求
//前台传输一个openid--每个用户对应小程序都会生成一个独一无二的openid
Map<String, Object> paraMap = new HashMap<>();
//查询房屋
String body = "cs";
// 封装11个必需的参数
//小程序ID
paraMap.put("appid", environment.getProperty("wx.appId"));
//商家ID
paraMap.put("mch_id", environment.getProperty("wx.mchId"));
//获取随机字符串 Nonce Str
paraMap.put("nonce_str", WXPayUtil.generateNonceStr());
//商品名称
paraMap.put("body", body);
//订单号
if (pay.getType()==MsgConsts.ZERO_STATUS) {
//业务需求
// DecimalFormat df = new DecimalFormat("0.00%");
NumberFormat numberFormat = NumberFormat.getPercentInstance();
Double money = hpOrder.getTotalFee();//租金
numberFormat.setMinimumFractionDigits(2);//保留到小数点后2位,不设置或者设置为0表示不保留小数
//支付金额,单位:分,这边需要转成字符串类型,否则后面的签名会失败
String totalFee= BigDecimal.valueOf(money).multiply(new BigDecimal(100)).setScale(0,BigDecimal.ROUND_HALF_UP) + "";
paraMap.put("total_fee",totalFee);
paraMap.put("out_trade_no", hpOrder.getOrderNo());
}else{
Double money = obOrder.getTotalFee();
//支付金额,单位:分,这边需要转成字符串类型,否则后面的签名会失败
String totalFee= BigDecimal.valueOf(money).multiply(new BigDecimal(100)).setScale(0,BigDecimal.ROUND_HALF_UP) + "";
paraMap.put("total_fee",totalFee);
paraMap.put("out_trade_no", obOrder.getOrderNo());
}
paraMap.put("spbill_create_ip", ip);
// 此路径是微信服务器调用支付结果通知路径
paraMap.put("notify_url", "http://payment/callBack");
paraMap.put("trade_type", "JSAPI");
paraMap.put("openid", pay.getOpenid());
String sign = WXPayUtil.generateSignature(paraMap, environment.getProperty("wx.mchKey"));
//生成签名. 注意,若含有sign_type字段,必须和signType参数保持一致。
paraMap.put("sign", sign);
//将所有参数(map)转xml格式
String xml = WXPayUtil.mapToXml(paraMap);
log.info("xml=: "+xml);
// 统一下单 https://api.mch.weixin.qq.com/pay/unifiedorder
String unifiedorder_url = WXPayConstants.UNIFIEDORDER_URL;
log.info("统一下单接口unifiedorder_url:"+unifiedorder_url);
//发送post请求"统一下单接口"返回预支付id:prepay_id
String xmlStr = HttpClientUtil.doPostXml(unifiedorder_url, xml);
//以下内容是返回前端页面的json数据
//预支付id
String prepay_id = "";
if (xmlStr.indexOf("SUCCESS") != -1) {
Map<String, Object> map = WXPayUtil.xmlToMap(xmlStr);//XML格式字符串转换为Map
//获取封装好的预支付id
prepay_id = map.get("prepay_id").toString();
log.info("prepay_id_1= "+prepay_id);
}
// 封装所需6个参数调支付页面
Map<String, Object> payMap = new HashMap<String, Object>();
payMap.put("appId", environment.getProperty("wx.appId"));
payMap.put("timeStamp", WXPayUtil.getCurrentTimestamp()+"");//获取当前时间戳,单位秒
payMap.put("nonceStr", WXPayUtil.generateNonceStr());//获取随机字符串 Nonce Str
payMap.put("signType", "MD5");
payMap.put("package", "prepay_id=" + prepay_id);
//生成带有 sign 的 XML 格式字符串
String paySign = WXPayUtil.generateSignature(payMap, environment.getProperty("wx.mchKey"));
payMap.put("paySign", paySign);
// 封装正常情况返回数据
resMap.put("success",true);
resMap.put("payMap",payMap);
} catch (Exception e) {
//异常删除订单
// 封装异常情况返回数据
log.info("调用统一订单接口错误");
resMap.put("success",false);
resMap.put("message","调用统一订单接口错误");
e.printStackTrace();
}
return resMap;
}
/*支付成功回调*/
@ApiOperation(httpMethod = "POST", value = "调用支付成功回调的地址")
@RequestMapping(value = "callBack")
public Result callBack(HttpServletRequest request, HttpServletResponse response){
Result result = new Result();
log.info("调用微信支付成功回调");
InputStream is = null;
String resXml = "";
try {
is = request.getInputStream();//获取请求的流信息(这里是微信发的xml格式所有只能使用流来读)
String xml = WXPayUtil.inputStream2String(is);
Map<String, Object> notifyMap = WXPayUtil.xmlToMap(xml);//将微信发的xml转map
if(notifyMap.get("return_code").equals("SUCCESS")){
try {
//业务需求
resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
+ "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
out.write(resXml.getBytes());
out.flush();
out.close();
System.err.println("返回给微信的值:"+resXml.getBytes());
is.close();
}catch (Exception e){
log.info("订单状态修改失败");
result.setMsg("订单状态修改失败");
}
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}