* 要想使用微信支付能力,不管是App支付、公众号支付、h5支付等支付方式都需要先在微信商户平台申请开通支付能力。
* 申请开通支付能力的资料有公司营业执照、负责人身份证正反面等图片,相关所需的所有资料在微信官方商户平台上有说明。
* 申请完开通支付能力后,我们会得到商户号以及appId,然后设置32位官方密钥。
* 如果你是h5支付,还需要去微信商户平台设置支付URL的IP或者域名,一般最多可以设置5个IP或者域名,建议同时将正式环境和测试环境的IP或者域名设置好。
* 如果你是公众号支付,同上,你也需要设置你的支付IP或者域名,注意,异步通知的URL也要在你设置的IP或者域名下。
时序图
*** APP支付**
支付集成流程如下(微信和支付宝流程上基本一致,具体参考代码):
步骤1:用户在商户APP中选择商品,提交订单,选择微信支付。(app端向服务端发起请求)
步骤2:商户后台收到用户支付单,调用微信支付统一下单接口。(服务端向微信请求)
步骤3:统一下单接口返回正常的prepay_id,再按签名规范重新生成签名后,将数据传输给APP。参与签名的字段名为appid,partnerid,prepayid,noncestr,timestamp,package。注意:package的值格式为Sign=WXPay(将微信回传的prepayid与其他参数组合返回给app端)
步骤4:商户APP调起微信支付。(app端利用服务端回传的参数调起微信支付)
步骤5:商户后台接收支付通知。(微信将支付结果异步通知服务端)
步骤6:商户后台查询支付结果。(微信将支付结果同步通知app端)
微信统一下单接口和回调
@Override
public String getWxPayOrderStr(String orderNo, HttpServletRequest request) {
//最终返回加签之后的,app需要传给支付宝app的订单信息字符串 String orderString = "";
System.out.println("==================微信下单,商户订单号为:" + orderNo);
String appId = PayConfigUtil.APP_ID;//appId String mchId = PayConfigUtil.MCH_ID;//商户id String key = PayConfigUtil.API_KEY;
String currTime = PayCommonUtil.getCurrTime();
String strTime = currTime.substring(8, currTime.length());
String strRandom = PayCommonUtil.buildRandom(4) + "";
String nonce_str = strTime + strRandom;
order_price = order_price.substring(0, order_price.indexOf("."));
String body = teaNames;
String spbill_create_ip = PayConfigUtil.CREATE_IP;
String notify_url = PayConfigUtil.NOTIFY_URL;
String trade_type = "APP";
SortedMap<Object, Object> map = new TreeMap<>();
map.put("appid", appId);
map.put("mch_id", mchId);
map.put("nonce_str", nonce_str);
map.put("body", body);
map.put("out_trade_no", orderNo);
map.put("total_fee", order_price);
map.put("spbill_create_ip", spbill_create_ip);
map.put("notify_url", notify_url);
map.put("trade_type", trade_type);
//签名数据,MD5加密 String sign = PayCommonUtil.createSign("UTF-8", map, key);
map.put("sign", sign);
//请求微信支付,进行下单 String requestXML = PayCommonUtil.getRequestXml(map);
String resXml = HttpUtil.postData(PayConfigUtil.UFDODER_URL, requestXML);
System.out.println("微信返回值:" + resXml);
Map<String, String> data = null;
try {
data = XMLUtil.doXMLParse(resXml);
if (data.get("return_code").equals("SUCCESS")) {
//返回给APP端的参数,APP端再调起支付接口 SortedMap<Object, Object> repData = new TreeMap<>();
repData.put("appid", appId);
repData.put("noncetr", nonce_str);
repData.put("partnerid", mchId);
repData.put("prepayid", data.get("prepay_id"));
repData.put("package", "Sign=WXPay");
repData.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
String sign1 = PayCommonUtil.createSign("UTF-8", repData, key);
JSONObject json = new JSONObject();
json.put("appid", appId);
json.put("partnerid", mchId);
json.put("package", "Sign=WXPay");
json.put("noncestr", nonce_str);
json.put("prepayid", data.get("prepay_id"));
json.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
json.put("sign", "1232");
return json.toString();
} else {
return "";
}
} catch (JDOMException | IOException e) {
e.printStackTrace();
return "";
}
}
@PostMapping("/wxPayAppCallback")
public void wxPayCallback(HttpServletRequest request, HttpServletResponse response) throws JDOMException, Exception {
System.out.println("微信支付回调");
InputStream inStream = request.getInputStream();
ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = inStream.read(buffer)) != -1) {
outSteam.write(buffer, 0, len);
}
String resultxml = new String(outSteam.toByteArray(), "utf-8");
Map<String, String> map = XMLUtil.doXMLParse(resultxml);
outSteam.close();
inStream.close();
System.out.println("微信返回值:" + map);
String resultCode = map.get("result_code");
//订单号 String out_trade_no = map.get("out_trade_no");
if (StringUtils.equals(resultCode, "SUCCESS")) {
//业务代码
System.out.println("微信回调成功");
//返回微信处理成功 response.setContentType("text/xml");
response.getWriter().println("success");
} else {
response.setContentType("text/xml");
response.getWriter().println("fail");
}
}
支付宝支付和回调
/** * 获取支付宝加签后台的订单信息字符串 */
@Override
public String getAliPayOrderStr(String orderNo) {
String teaNames = "";//商品名称
//最终返回加签之后的,app需要传给支付宝app的订单信息字符串 String orderString = "";
System.out.println("==================支付宝下单,商户订单号为:" + orderNo);
try {
//实例化客户端(参数:网关地址、商户appid、商户私钥、格式、编码、支付宝公钥、加密类型),为了取得预付订单信息 AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID,
AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET,
AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.SIGN_TYPE);
//实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay AlipayTradeAppPayRequest ali_request = new AlipayTradeAppPayRequest();
//SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式 AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
//业务参数传入,可以传很多,参考API //model.setPassbackParams(URLEncoder.encode(request.getBody().toString())); //公用参数(附加数据)
model.setBody("购买商品");//对一笔交易的具体描述信息。如果是多种商品,请将商品描述字符串累加传给body。
model.setSubject(teaNames);//商品名称
model.setOutTradeNo(orderNo);//商户订单号(自动生成)
model.setTimeoutExpress("15m");//交易超时时间
model.setTotalAmount(String.valueOf(orderTea.getOrderTotal()));//支付金额
model.setProductCode("QUICK_MSECURITY_PAY");//销售产品码(固定值)
ali_request.setBizModel(model);
ali_request.setNotifyUrl(AlipayConfig.notify_url);//异步回调地址(后台)
ali_request.setReturnUrl(AlipayConfig.return_url);//同步回调地址(APP)
// 这里和普通的接口调用不同,使用的是sdkExecute
AlipayTradeAppPayResponse alipayTradeAppPayResponse = alipayClient.sdkExecute(ali_request); //返回支付宝订单信息(预处理)
orderString = alipayTradeAppPayResponse.getBody();//就是orderString 可以直接给APP请求,无需再做处理。
} catch (AlipayApiException e) {
e.printStackTrace();
}
return orderString;
}
@PostMapping("/appCallback")
public void appCallback(HttpServletRequest request, HttpServletResponse response) {
try {
// 获取支付宝POST过来反馈信息 Map<String, String> params = new HashMap<>();
Map requestParams = request.getParameterMap();
for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
String name = (String) iter.next();
String[] values = (String[]) requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i]
: valueStr + values[i] + ",";
}
// 乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化 valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
params.put(name, valueStr);
}
// 调用SDK验证签名 boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET, AlipayConfig.SIGN_TYPE);
//先不做回调验证 //if (signVerified) { System.out.println("回调验签");
// 商户订单号(后台生成) String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), "UTF-8");
// 支付宝交易号 String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"), "UTF-8");
// 交易状态 String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"), "UTF-8");
System.out.println("trade_no:" + trade_no);
// 获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表(以上仅供参考)// if (StringUtils.equals("TRADE_SUCCESS", trade_status)) {
//ZK表示用户购买了赚客商品开通了赚客 if (out_trade_no.contains("d") || out_trade_no.contains("ZK")) {
String[] orderNoArr = new String[1024];
int a = 0;
//根据订单号修改订单状态 MallOrder mallOrder = new MallOrder();
mallOrder.setOrderStatus(Byte.valueOf("1"));
mallOrder.setOutTradeNo(trade_no);//支付宝交易号 mallOrder.setPayChannel(Byte.valueOf("2"));//支付方式 mallOrder.setPayTime(new Date());
mallOrder.setCreated(true);
if (out_trade_no.contains(",")) {
orderNoArr = out_trade_no.split(",");
for (String orderNo : orderNoArr) {
MallOrderExample mallOrderExample = new MallOrderExample();
mallOrderExample.createCriteria().andOrderNoEqualTo(orderNo);
saveRecord(orderNo);
a += orderService.updateByExampleSelective(mallOrder, mallOrderExample);
}
} else {
saveRecord(out_trade_no);
MallOrderExample mallOrderExample = new MallOrderExample();
mallOrderExample.createCriteria().andOrderNoEqualTo(out_trade_no);
a = orderService.updateByExampleSelective(mallOrder, mallOrderExample);
}
if (a > 1) {
System.out.println("修改成功");
}
System.out.println("订单提交成功");
} else {
//根据订单号修改订单状态,生成取货码 machineOrderTea orderTea = machineService.findMachineOrder(out_trade_no);
String prefix = RandomStringUtils.random(4, "1234567890").toUpperCase();
long l = System.currentTimeMillis();
String newSuffix=String.valueOf(l).substring(String.valueOf(l).length()-5,String.valueOf(l).length());
String suffix = String.valueOf(l / 500000000);
// String verificationCode = prefix + suffix; String verificationCode = prefix + newSuffix;
orderTea.setVerificationCode(verificationCode);
orderTea.setTradeNo(trade_no);
orderTea.setOrderNo(out_trade_no);
orderTea.setPayMethod("Alipay");
orderTea.setOrderStatus("1");
//如果使用了优惠券则将优惠券设置为已使用 Integer couponLinkId = orderTea.getCouponId();
if (null != couponLinkId) {
MemberCouponsLink link = couponsLinkMapper.selectByPrimaryKey(couponLinkId);
//设置优惠为已使用// link.setIsUse(true); /*临时方案↓*/ //如果优惠券码不为"888888"或者"666666",则设置优惠券为"已使用" if(!(link.getCouponCode().equals("888888")||link.getCouponCode().equals("666666"))){
link.setIsUse(true);
}
/*临时方案↑*/ couponsLinkMapper.updateByPrimaryKeySelective(link);
}
machineService.updateMachineOrder(orderTea);
System.out.println("订单提交成功");
}
String result = "success";
// if(signVerified){//验签成功// result="success";// }else{// result="fail";// } //,不然业务代码不会执行 BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
out.write(result.getBytes());
out.flush();
out.close();
}
// } else {// System.out.println("回调验签失败");// } } catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("支付异常");
}
}