1、引入依赖:(对于依赖冲突自行解决)
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-pay</artifactId>
<!--<version>3.4.9.B</version>-->
<version>3.5.0</version>
<exclusions>
<exclusion>
<artifactId>httpclient</artifactId>
<groupId>org.apache.httpcomponents</groupId>
</exclusion>
<exclusion>
<artifactId>commons-lang3</artifactId>
<groupId>org.apache.commons</groupId>
</exclusion>
<exclusion>
<artifactId>commons-beanutils</artifactId>
<groupId>commons-beanutils</groupId>
</exclusion>
<exclusion>
<artifactId>guava</artifactId>
<groupId>com.google.guava</groupId>
</exclusion>
</exclusions>
</dependency>
2、
package com.dhht.wechat.controller; import com.dhht.wechat.VO.PayVO;import com.dhht.wechat.service.PayService;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource;import javax.servlet.http.HttpServletRequest; /* * @Author: sh * @Description: WxPayController * @Date: 11:06 2019/7/17 */ @RestController@RequestMapping("wechat/")public class WxPayController { @Resource private PayService payService; /** * 微信支付统一下单接口(H5) * @param payVO * @param request * @return */ @PostMapping(value = "pay",produces = "application/json;charset=UTF-8") public String unifiedOrder(@RequestBody PayVO payVO, HttpServletRequest request){ return payService.unifiedOrder(payVO,request); } /** * 微信支付接收通知接口(供微信服务调用) * @param xmlData * @return */ @PostMapping(value = "pay/notify",produces = "application/json;charset=UTF-8") public synchronized String payNotify(@RequestBody String xmlData){ return payService.payNotifyCallBack(xmlData); } /** * 退款结果通知接口 * @param xmlData * @return */ @PostMapping("/notify/refund") public synchronized String parseRefundNotifyResult(@RequestBody String xmlData) { return payService.parseRefundNotifyResult(xmlData); } }
package com.dhht.wechat.service; import com.alibaba.fastjson.JSON;import com.dhht.wechat.VO.PayVO;import com.dhht.wechat.service.impservice.OrderRefundResultImplService;import com.dhht.wechat.service.impservice.SealOrderImplService;import com.dhht.wechat.service.impservice.SealOrderSealImplService;import com.dhht.wechat.util.ConstantUtil;import com.dhht.wechat.util.DateUtil;import com.dhht.wechat.wxpay.MyX509TrustManager;import com.dhht.wechat.wxpay.PayRespCodeMsg;import com.dhht.wechat.wxpay.PayResultVO;import com.dhht.wechat.wxpay.WechatPayConfigBean;import com.dhht.wechat.wxpay.config.WxPayProperties;import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;import com.github.binarywang.wxpay.bean.request.*;import com.github.binarywang.wxpay.bean.result.WxPayOrderCloseResult;import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;import com.github.binarywang.wxpay.service.WxPayService;import net.sf.json.JSONObject;import org.apache.commons.lang3.StringUtils;import org.jdom.Document;import org.jdom.Element;import org.jdom.input.SAXBuilder;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Service; import javax.annotation.Resource;import javax.net.ssl.HttpsURLConnection;import javax.net.ssl.SSLContext;import javax.net.ssl.SSLSocketFactory;import javax.net.ssl.TrustManager;import javax.servlet.http.HttpServletRequest;import java.io.*;import java.math.BigDecimal;import java.net.ConnectException;import java.net.URL;import java.security.MessageDigest;import java.text.MessageFormat;import java.util.*; /** * WxPayService */@Servicepublic class PayService { @Resource private WechatPayConfigBean wechatPayConfigBean; @Resource private WxPayProperties wxPayProperties;// 第三方 @Resource private SealOrderImplService sealOrderImplService; @Resource private WxPayService wxService;// 第三方sdk // @Resource// private OrderPayResultImplService orderPayResultImplService; @Resource private OrderRefundResultImplService orderRefundResultImplService; @Value("${spbill_create_ip}") private String SPBILL_CREATE_IP; @Value("${appSecret}") private String appSecret; @Resource WeiXinService weiXinService; @Resource SealOrderSealImplService sealOrderSealImplService; /** * 微信支付统一下单接口(H5) * * @param payVO * @param request * @return */ public String unifiedOrder(PayVO payVO, HttpServletRequest request) { try { String orderId = payVO.getOrderId(); String code = payVO.getCode(); if (StringUtils.isEmpty(orderId) || StringUtils.isEmpty(code)) { PayResultVO payResultVO = new PayResultVO(-1, "NO", null); return JSON.toJSONString(payResultVO); } WxPayOrderQueryResult payOrderQueryResult = wechatOrderQuery(orderId);// wxService.queryOrder(null, orderId);// 查询订单状态 String payOrderQuery_return_code = payOrderQueryResult.getReturnCode();// SUCCESS/FAIL if (ConstantUtil.PAY_RETURN_CODE_NO.equals(payOrderQuery_return_code)) {// 通信失败:FAIL PayResultVO queryPayResultVO = new PayResultVO(-1, payOrderQueryResult.getReturnMsg(), null); return JSON.toJSONString(queryPayResultVO);// 订单查询接口通信失败,直接返回 } // 订单查询通信成功:SUCCESS // 若业务成功 /** * trade_state状态如下: * SUCCESS—支付成功 * REFUND—转入退款 * NOTPAY—未支付 * CLOSED—已关闭 * REVOKED—已撤销(刷卡支付) * USERPAYING--用户支付中 * PAYERROR--支付失败(其他原因,如银行返回失败)商户订单支付失败需要生成新单号重新发起支付,要对原订单号调用关单,避免重复支付 */ String trade_state = payOrderQueryResult.getTradeState(); if (!ConstantUtil.PAY_TRADE_STATE_NOTPAY.equals(trade_state) && null != trade_state) {// 非未支付状态下(可以为null-代表还未生成订单,故需过滤掉) PayResultVO tradePayResultVO = new PayResultVO(-1, ConstantUtil.PAY_STATUS_MAP.get(trade_state), null); return JSON.toJSONString(tradePayResultVO); } // 以下转入订单未支付处理或还没有生成订单(trade_state==null)的处理逻辑 //String openUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+wxPayProperties.getAppId()+"&secret="+appSecret+"&code="+code+"&grant_type=authorization_code"; String openId = weiXinService.getOpenId(code);//SendMsgUtil.httpRequest(openUrl,"GET","{}").getString("openid");// 获取openid // 更新订单openId--2019-09-17 Map<String, Object> paMap = new HashMap<>(); paMap.put("orderId", orderId); paMap.put("userOpenId", openId); sealOrderImplService.updateOrderInfo(paMap); // 获取本系统印章订单信息 Map<String, Object> orderDetails = sealOrderImplService.getOrderMapById(orderId); String SUB_MCH_ID = (String) orderDetails.get("SUB_MCH_ID");// 营业网点扩展信息表中的子商户号-20190910 if (StringUtils.isEmpty(SUB_MCH_ID)) {// 若无配置子商户号退出 PayResultVO payResultVO = new PayResultVO(-1, "NO-SUB_MCH_ID", null); return JSON.toJSONString(payResultVO); } String siteName = (String) orderDetails.get("siteName");// 营业网点名称(刻章店名称) float orderPrice = ((BigDecimal) orderDetails.get("ORDER_AMOUNT")).floatValue();// 订单总金额 String bodyName = siteName + "-" + ConstantUtil.ADVANCE_PAY_GOODS_NAME;// 商品名称严格按照规范-公众号支付-例如(商家名称-销售商品类目) // 设置统一下单请求参数 // 请求对象,注意一些参数如appid、mchid等不用设置,方法内会自动从配置对象中获取到(前提是对应配置中已经设置) WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest(); orderRequest.setAppid(wxPayProperties.getAppId());// 服务商appid orderRequest.setMchId(wxPayProperties.getMchId());// 商户号 orderRequest.setSubMchId(SUB_MCH_ID);// 子商户号 String nonceStr = DateUtil.get32UUIDMilli(); orderRequest.setNonceStr(nonceStr);// 随机串,32位以内! orderRequest.setSignType(wxPayProperties.getSignType());// 签名类型 orderRequest.setBody(bodyName); orderRequest.setOutTradeNo(orderId); orderRequest.setTotalFee(BaseWxPayRequest.yuanToFen(orderPrice + ""/*order.getTotalFee()*/));//元转成分 orderRequest.setSpbillCreateIp(SPBILL_CREATE_IP);// 终端IP orderRequest.setNotifyUrl(wxPayProperties.getNotifyUrl());// 支付结果异步回调地址 orderRequest.setTradeType(wxPayProperties.getTradeType());// 交易类型 orderRequest.setOpenid(openId);// 设置openid WxPayMpOrderResult wxPayUnifiedOrderResult = wxService.createOrder(orderRequest);// 统一下单接口调用结果 String appId = wxPayUnifiedOrderResult.getAppId(); String timeStamp = create_timestamp(); String package_ = wxPayUnifiedOrderResult.getPackageValue();// ConstantUtil.PACKAGE_SUFFIX + wxPayUnifiedOrderResult.getPackageValue(); String paySign = wxPayUnifiedOrderResult.getPaySign(); Map<String, Object> resultMapData = new HashMap<>(); resultMapData.put("appId", appId); resultMapData.put("timeStamp", timeStamp); resultMapData.put("package", package_); resultMapData.put("paySign", paySign); resultMapData.put("nonceStr", wxPayUnifiedOrderResult.getNonceStr()); resultMapData.put("signType", wxPayProperties.getSignType()); PayResultVO paySucessResultVO = new PayResultVO(0, "OK", resultMapData); return JSON.toJSONString(paySucessResultVO); } catch (Exception e) { Map map = new HashMap(); map.put("data", e.getMessage()); PayResultVO payResultVO = new PayResultVO(-1, "NO", map); return JSON.toJSONString(payResultVO); } } /** * 支付回调 * * @param xmlData * @return */ public synchronized String payNotifyCallBack(String xmlData) { try { WxPayOrderNotifyResult wxPayOrderNotifyResult = wxService.parseOrderNotifyResult(xmlData);// 解析xml字符串 String return_code = wxPayOrderNotifyResult.getReturnCode();// SUCCESS/FAIL if (ConstantUtil.PAY_RETURN_CODE_NO.equals(return_code)) {// 支付通信失败 return WxPayNotifyResponse.fail("FAIL"); } // 以下通信成功操作 String out_trade_no = wxPayOrderNotifyResult.getOutTradeNo();// 商户系统内部订单号(即本系统印章订单号) // 内部订单支付情况 Map<String, Object> orderDetails = sealOrderImplService.getOrderMapById(out_trade_no); if (null != orderDetails) { String paySta = (Integer) orderDetails.get("PAY_STATUS") + ""; if ((ConstantUtil.ORDER_PAYSTATUS_1_ + "").equals(paySta)) {// 已支付直接返回 return WxPayNotifyResponse.success("OK"); } } if (ConstantUtil.PAY_RETURN_CODE_OK.equals(return_code)) {// 支付接口通信成功 String result_code = wxPayOrderNotifyResult.getResultCode();// SUCCESS/FAIL 是否真实支付成功 if (ConstantUtil.PAY_RETURN_CODE_OK.equals(result_code)) {// 支付成功 // 检查本库是否已经插入支付成功记录 // orderPayResultImplService.deleteByOrderId(out_trade_no); //orderPayResultImplService.add(wxPayOrderNotifyResult); //orderPayResultImplService.insertSelective(wxPayOrderNotifyResult); sealOrderImplService.updateOrderPaySta(out_trade_no, ConstantUtil.ORDER_PAYSTATUS_1_);// 更新支付状态 // 推送微信内容-2019-09-18 sealOrderSealImplService.sendWXMsgToSite(out_trade_no); } if (ConstantUtil.PAY_RETURN_CODE_NO.equals(result_code)) {// 支付失败 closePayOrder(out_trade_no);// 支付失败的话,需要关闭订单,才能重新支付 sealOrderImplService.upOrderRelation(out_trade_no);// 更新该订单的id,主要用于重新支付 sealOrderImplService.updateOrderPaySta(out_trade_no, ConstantUtil.ORDER_PAYSTATUS_2_);// 更新支付状态 } return WxPayNotifyResponse.success("OK"); } else {// 支付结果通信失败 return WxPayNotifyResponse.fail("FAIL"); } } catch (Exception e) { return WxPayNotifyResponse.fail("FAIL"); } } /** * 查询订单状态 * * @param orderId * @return */ public WxPayOrderQueryResult wechatOrderQuery(String orderId) { try { if (StringUtils.isEmpty(orderId)) { return null; } Map<String, Object> orderDetails = sealOrderImplService.getOrderMapById(orderId);// 获取本系统订单的相关信息 String SUB_MCH_ID = (String) orderDetails.get("SUB_MCH_ID");// 营业网点扩展信息表中的子商户号-20190910 WxPayOrderQueryRequest wxPayOrderQueryRequest = new WxPayOrderQueryRequest(); wxPayOrderQueryRequest.setAppid(wxPayProperties.getAppId()); wxPayOrderQueryRequest.setMchId(wxPayProperties.getMchId()); wxPayOrderQueryRequest.setSubMchId(SUB_MCH_ID);// 子商户好最终通过orderId从本系统获取 wxPayOrderQueryRequest.setOutTradeNo(orderId);// 微信内部订单号与本系统订单号二选一 wxPayOrderQueryRequest.setNonceStr(DateUtil.get32UUIDMilli()); wxPayOrderQueryRequest.setSignType(wxPayProperties.getSignType()); WxPayOrderQueryResult wxPayOrderQueryResult = wxService.queryOrder(wxPayOrderQueryRequest); return wxPayOrderQueryResult; } catch (Exception e) { WxPayOrderQueryResult wxPayOrderQueryResult = new WxPayOrderQueryResult(); wxPayOrderQueryResult.setReturnCode(ConstantUtil.PAY_RETURN_CODE_OK); wxPayOrderQueryResult.setResultCode(ConstantUtil.PAY_RETURN_CODE_OK); wxPayOrderQueryResult.setTradeState(null); return wxPayOrderQueryResult; } } /** * 关闭订单(关闭订单之后,重新提交支付需要更新订单号!) * * @param orderId * @return */ public WxPayOrderCloseResult closePayOrder(String orderId) { if (StringUtils.isEmpty(orderId)) { return null; } try { Map<String, Object> orderDetails = sealOrderImplService.getOrderMapById(orderId);// 获取本系统订单的相关信息 String SUB_MCH_ID = (String) orderDetails.get("SUB_MCH_ID");// 营业网点扩展信息表中的子商户号-20190910 WxPayOrderCloseRequest wxPayOrderCloseRequest = new WxPayOrderCloseRequest(); wxPayOrderCloseRequest.setAppid(wxPayProperties.getAppId()); wxPayOrderCloseRequest.setMchId(wxPayProperties.getMchId()); wxPayOrderCloseRequest.setSubMchId(SUB_MCH_ID);// 从本系统获取通过orderDetails wxPayOrderCloseRequest.setOutTradeNo(orderId); wxPayOrderCloseRequest.setNonceStr(DateUtil.get32UUIDMilli()); wxPayOrderCloseRequest.setSignType(wxPayProperties.getSignType()); WxPayOrderCloseResult wxPayOrderCloseResult = wxService.closeOrder(wxPayOrderCloseRequest); return wxPayOrderCloseResult; } catch (Exception e) { return null; } } /** * 订单退款(接口请求并非退款结果) * * @param orderId * @return */ public PayResultVO refundPayOrder(String orderId) { try { if (StringUtils.isEmpty(orderId)) { return null; } Map<String, Object> orderDetails = sealOrderImplService.getOrderMapById(orderId);// 获取本系统订单的相关信息 // 查询微信支付订单信息 WxPayOrderQueryResult wxPayOrderQueryResult = wechatOrderQuery(orderId); String order_return_code = wxPayOrderQueryResult.getReturnCode();// 订单查询网络状态 if (ConstantUtil.PREPAYID_RETURN_CODE_NO.equals(order_return_code)) { PayResultVO returnPayResultVO = new PayResultVO(-1, ConstantUtil.PAY_NETWORK_EXCEP, null); return returnPayResultVO; } String order_result_code = wxPayOrderQueryResult.getResultCode();// 订单查询业务状态 if (ConstantUtil.PREPAYID_RETURN_CODE_NO.equals(order_result_code)) { PayResultVO resultPayResultVO = new PayResultVO(-1, ConstantUtil.REFUND_FAIL_MSG, null); return resultPayResultVO; } String order_trade_state = wxPayOrderQueryResult.getTradeState();// 订单状态(已支付、未支付等等) if (!ConstantUtil.PAY_TRADE_STATE_SUCCESS.equals(order_trade_state)) {// 未支付成功,直接返回 PayResultVO tradePayResultVO = new PayResultVO(-1, ConstantUtil.REFUND_FAIL_MSG, null); } // 以下为订单已支付后续操作(只有order_trade_state为SUCCESS可获取如下参数) String transaction_id = wxPayOrderQueryResult.getTransactionId();// 微信内部支付订单号 int total_fee = wxPayOrderQueryResult.getTotalFee();// 订单总金额 String sub_mch_id = wxPayOrderQueryResult.getSubMchId();// 订单子商户号 String out_trade_no = wxPayOrderQueryResult.getOutTradeNo(); WxPayRefundRequest wxPayRefundRequest = new WxPayRefundRequest(); wxPayRefundRequest.setAppid(wxPayProperties.getAppId()); wxPayRefundRequest.setMchId(wxPayProperties.getMchId()); wxPayRefundRequest.setSubMchId(sub_mch_id);// 从本系统通过orderId获取 wxPayRefundRequest.setNonceStr(DateUtil.get32UUIDMilli()); wxPayRefundRequest.setSignType(wxPayProperties.getSignType()); wxPayRefundRequest.setTransactionId(transaction_id); wxPayRefundRequest.setOutTradeNo(out_trade_no);// 商户内部订单号 String refundNo = DateUtil.get32UUIDMilli();// 生成商户内部退款单号 wxPayRefundRequest.setOutRefundNo(refundNo);// 商户内部退款单号!!! wxPayRefundRequest.setTotalFee(total_fee); wxPayRefundRequest.setRefundFee(total_fee);// !!!申请退款金额???? wxPayRefundRequest.setNotifyUrl(wxPayProperties.getRefundNotifyUrl());// 退款结果通知url WxPayRefundResult wxPayRefundResult = wxService.refund(wxPayRefundRequest);// 订单退款接口 String refund_return_code = wxPayRefundResult.getReturnCode();// 退款接口网络状态 if (ConstantUtil.PREPAYID_RETURN_CODE_NO.equals(refund_return_code)) { PayResultVO refundExPayVO = new PayResultVO(-1, ConstantUtil.REFUND_FAIL_MSG, null); return refundExPayVO; } String refund_result_code = wxPayRefundResult.getResultCode();// 退款接口结果状态 if (ConstantUtil.PREPAYID_RETURN_CODE_NO.equals(refund_result_code)) { PayResultVO refundFailPayVO = new PayResultVO(-1, ConstantUtil.REFUND_FAIL_MSG, null); return refundFailPayVO; } // 以下为退款成功操作 PayResultVO refundSuceesResultVO = new PayResultVO(0, "OK", wxPayRefundResult); Map<String, Object> paramMap = new HashMap<>(); paramMap.put("refundNo", refundNo);// 内部退款单号 sealOrderImplService.updateOrderInfo(paramMap); return refundSuceesResultVO; } catch (Exception e) { return null; } } /** * 退款回调通知地址 * * @param xmlData * @return */ public synchronized String parseRefundNotifyResult(String xmlData) { try { WxPayRefundNotifyResult result = wxService.parseRefundNotifyResult(xmlData); String return_code = result.getReturnCode(); if (ConstantUtil.PREPAYID_RETURN_CODE_NO.equals(return_code)) {// 通信失败 return WxPayNotifyResponse.fail("FAIL"); } // 以下为通信成功返回的字段信息 WxPayRefundNotifyResult.ReqInfo reqInfo = result.getReqInfo();// 获取结果中的加密信息 /** * SUCCESS-退款成功 * CHANGE-退款异常 * REFUNDCLOSE—退款关闭 */ String refund_status = reqInfo.getRefundStatus();// 退款状态 if (ConstantUtil.REFUND_STATUS_0.equals(refund_status)) {// 成功 refund_status = ConstantUtil.ORDER_PAYSTATUS_3_ + ""; } if (ConstantUtil.REFUND_STATUS_1.equals(refund_status)) {// 异常 refund_status = ConstantUtil.ORDER_PAYSTATUS_4_ + ""; } if (ConstantUtil.REFUND_STATUS_2.equals(refund_status)) {// 关闭 refund_status = ConstantUtil.ORDER_PAYSTATUS_4_ + ""; } String out_trade_no = reqInfo.getOutTradeNo();// 内部订单号 Map<String, Object> paramMap = new HashMap<>(); paramMap.put("refundNo", out_trade_no);// 内部退款单号 paramMap.put("payStatus", refund_status);// 更新支付状态 sealOrderImplService.updateOrderInfo(paramMap); orderRefundResultImplService.deleteByOrderdId(out_trade_no);// 删除订单 orderRefundResultImplService.addRefundInfo(result);// 添加退款 记录 return WxPayNotifyResponse.success("OK"); } catch (Exception e) { return WxPayNotifyResponse.fail("FAIL"); } } //****************************************************************************************************************** /** * 获取微信签名信息(预支付订单信息) * * @param payVO * @param request * @return */ public synchronized String getWxPaySign(PayVO payVO, HttpServletRequest request) { try { if (null == payVO) { return null; } String orderId = payVO.getOrderId(); String wxCode = payVO.getCode(); if (StringUtils.isEmpty(orderId) || StringUtils.isEmpty(wxCode)) { return null; } // 获取openId JSONObject openIdJson = getAccess_tokenByCode(wxCode); int errcode_openId = openIdJson.getInt("errcode"); if (errcode_openId != 0) {// 调用获取openId接口不成功 PayRespCodeMsg payRespCodeMsg = new PayRespCodeMsg(errcode_openId, openIdJson.getString("errmsg")); PayResultVO payResultVO = new PayResultVO(payRespCodeMsg, null); return JSON.toJSONString(payResultVO); } String openid = openIdJson.getString("openid");// 用户唯一标识 String session_key = openIdJson.getString("session_key");// 会话秘钥 // 获取本地订单相关信息 Map<String, Object> orderDetails = sealOrderImplService.getOrderMapById(orderId); String siteName = (String) orderDetails.get("siteName");// 营业网点名称(刻章店名称) int orderPrice = ((BigDecimal) orderDetails.get("ORDER_AMOUNT")).intValue() * 100; String bodyName = siteName + "-" + ConstantUtil.ADVANCE_PAY_GOODS_NAME;// 商品名称严格按照规范-公众号支付-例如(商家名称-销售商品类目) String orderno = orderId;// "1234567890"; Integer total_fee = orderPrice;// "8.88";// 订单总费用,不能有小数点,以分为单位 String nonce_str = create_nonce_str(); String timestamp = create_timestamp(); // 获取预支付订单prepayId SortedMap<Object, Object> parameters = new TreeMap<Object, Object>(); String prepayIdResult = getPrepayId(request, bodyName, orderno, total_fee, openid);// 获取预支付订单id方法,返回的xml字符串结果 Map<String, String> prepayIdResultMap = doXMLParse(prepayIdResult);// xml字符串转map String prepayId_return_code = prepayIdResultMap.get("return_code");// SUCCESS/FAIL,此字段是通信标识,非交易标识,交易是否成功需要查看result_code来判断 if (ConstantUtil.PREPAYID_RETURN_CODE_NO.equals(prepayId_return_code)) {// 获取prepayId接口通信异常 PayRespCodeMsg preRespCodeMsg = new PayRespCodeMsg(-1, ConstantUtil.WECHAT_INTERFACE_EX_MSG);// PayResultVO preResultVO = new PayResultVO(preRespCodeMsg, null); return JSON.toJSONString(preResultVO); } // 获取prepayId的接口调用通信成功后 String prepayId_result_code = prepayIdResultMap.get("result_code");// SUCCESS/FAIL,业务结果 if (ConstantUtil.PAY_RETURN_CODE_NO.equals(prepayId_result_code)) {// 获取prepayId失败 PayRespCodeMsg preNo = new PayRespCodeMsg(-1, "NO"); PayResultVO preNoVO = new PayResultVO(preNo, null); return JSON.toJSONString(preNoVO); } // 微信预支付接口通信成功且业务结果成功 // 重新生成签名 parameters.put("appId", wechatPayConfigBean.getAppId()); parameters.put("timeStamp", timestamp); parameters.put("nonceStr", nonce_str); parameters.put("package", "prepay_id=" + prepayIdResultMap.get("prepay_id")); parameters.put("signType", "MD5"); String sign = createSign("UTF-8", parameters); parameters.put("prepay_id", "prepay_id=" + prepayIdResultMap.get("prepay_id")); parameters.put("paySign", sign); PayResultVO okResult = new PayResultVO(0, "OK", parameters); return JSON.toJSONString(okResult); } catch (Exception e) { PayResultVO resultVO = new PayResultVO(-1, "FALSE", null); return JSON.toJSONString(resultVO); } } public SortedMap<Object, Object> WapSignSignatureAction (HttpServletRequest request)throws Exception { SortedMap<Object, Object> parameters = new TreeMap<Object, Object>(); String code = request.getParameter("code"); System.out.println("code-------------" + code); // code作为换取access_token的票据,每次用户授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。 // 通过code换取网页授权access_token Map<String, String> data = getAccess_tokenByCode(code); String openid = data.get("openid"); String tName = "名称"; String orderno = "1234567890"; String total_fee = "8.88"; String nonce_str = create_nonce_str(); String timestamp = create_timestamp(); // 获取prepayId try { String result = getPrepayId(request, tName, orderno, Integer.parseInt(total_fee), openid); Map<String, String> map = doXMLParse(result); // 重新生成签名 parameters.put("appId", wechatPayConfigBean.getAppId() ); parameters.put("timeStamp", timestamp); parameters.put("nonceStr", nonce_str); parameters.put("package", "prepay_id=" + map.get("prepay_id")); parameters.put("signType", "MD5"); String sign = createSign("UTF-8", parameters); parameters.put("prepay_id", "prepay_id=" + map.get("prepay_id")); parameters.put("paySign", sign); } catch (Exception e) { e.printStackTrace(); } return parameters; } /** * 根据用户授权code获取access_token */ private JSONObject getAccess_tokenByCode(String code) { Map<String, String> data = new HashMap<String, String>(); //String requestUrlMessageFormat = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1}&code={2}&grant_type=authorization_code"; String requestUrlMessageFormat = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1}&code={2}&grant_type=authorization_code"; String requestUrl = MessageFormat.format(requestUrlMessageFormat, wxPayProperties.getAppId() , appSecret , code); String requestMethod = "GET"; String outputStr = ""; JSONObject json = httpRequest(requestUrl, requestMethod, outputStr); //String access_token = (String) json.get("access_token");// 此参数最新接口文档没发现的 String openid = (String) json.get("openid");// 用户唯一标识 String session_key = json.getString("session_key");// 会话秘钥 String unionid = json.getString("unionid");// 用户在开放平台的唯一标识符,在满足 UnionID 下发条件的情况下会返回 int errcode = json.getInt("errcode");// 错误码 String errmsg = json.getString("errmsg");// 错误信息 //data.put("access_token", access_token); data.put("openid", openid); data.put("session_key", session_key); data.put("unionid", unionid); data.put("errcode", errcode + ""); data.put("errmsg", errmsg); return json; } /** * 发起https请求并获取结果 * * @param requestUrl 请求地址 * @param requestMethod 请求方式(GET、POST) * @param outputStr 提交的数据 * @return JSONObject(通过JSONObject.get ( key)的方式获取json对象的属性值) */ public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) { JSONObject jsonObject = null; StringBuffer buffer = new StringBuffer(); try { // 创建SSLContext对象,并使用我们指定的信任管理器初始化 TrustManager[] tm = {new MyX509TrustManager()}; SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); sslContext.init(null, tm, new java.security.SecureRandom()); // 从上述SSLContext对象中得到SSLSocketFactory对象 SSLSocketFactory ssf = sslContext.getSocketFactory(); URL url = new URL(requestUrl); HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection(); httpUrlConn.setSSLSocketFactory(ssf); httpUrlConn.setDoOutput(true); httpUrlConn.setDoInput(true); httpUrlConn.setUseCaches(false); // 设置请求方式(GET/POST) httpUrlConn.setRequestMethod(requestMethod); if ("GET".equalsIgnoreCase(requestMethod)) httpUrlConn.connect(); // 当有数据需要提交时 if (null != outputStr) { OutputStream outputStream = httpUrlConn.getOutputStream(); // 注意编码格式,防止中文乱码 outputStream.write(outputStr.getBytes("UTF-8")); outputStream.close(); } // 将返回的输入流转换成字符串 InputStream inputStream = httpUrlConn.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8"); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); String str = null; while ((str = bufferedReader.readLine()) != null) { buffer.append(str); } bufferedReader.close(); inputStreamReader.close(); // 释放资源 inputStream.close(); inputStream = null; httpUrlConn.disconnect(); jsonObject = JSONObject.fromObject(buffer.toString()); } catch (ConnectException ce) { System.err.println("Weixin server connection timed out."); } catch (Exception e) { System.err.println("https request error"); } return jsonObject; } /** * 获取预支付订单id * * @param request * @param name * @param orderno * @param total_fee * @param openid * @return * @throws Exception */ public String getPrepayId(HttpServletRequest request, String name, String orderno, Integer total_fee, String openid) throws Exception { SortedMap<Object, Object> parameters = new TreeMap<Object, Object>(); parameters.put("appid", wechatPayConfigBean.getAppId() );// 服务商id parameters.put("mch_id", wechatPayConfigBean.getMchId() );// 商户号 parameters.put("nonce_str", CreateNoncestr());// 随机字符串 parameters.put("body", name);// 商品描述 parameters.put("out_trade_no", orderno);// 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*且在同一个商户号下唯一 parameters.put("total_fee", total_fee);// 支付金额单位:分 parameters.put("spbill_create_ip", getIp2(request));// 支持IPV4和IPV6两种格式的IP地址。调用微信支付API的机器IP parameters.put("notify_url", wechatPayConfigBean.getPayResultNotifyUrl());// 接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数 parameters.put("trade_type", "JSAPI");// 交易类型,小程序取值如下:JSAPI,详细说明见 parameters.put("openid", openid);// 商户标识 parameters.put("time_expire", DateUtil.getTimeStamp());// (非必填)交易结束时间,需要动态传入,格式为yyyyMMddHHmmss-20190719114936 String sign = createSign("UTF-8", parameters); parameters.put("sign", sign); String requestXML = getRequestXml(parameters); // 调用统一下单接口 String result = httpsRequest("https://api.mch.weixin.qq.com/pay/unifiedorder", "POST", requestXML); System.out.println(result); return result; } public static String CreateNoncestr() { String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; String res = ""; for (int i = 0; i < 16; i++) { Random rd = new Random(); res += chars.charAt(rd.nextInt(chars.length() - 1)); } return res; } public static String getIp2(HttpServletRequest request) { String ip = request.getHeader("X-Forwarded-For"); if (!org.apache.commons.lang3.StringUtils.isEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) { // 多次反向代理后会有多个ip值,第一个ip才是真实ip int index = ip.indexOf(","); if (index != -1) { return ip.substring(0, index); } else { return ip; } } ip = request.getHeader("X-Real-IP"); if (!org.apache.commons.lang3.StringUtils.isEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) { return ip; } return request.getRemoteAddr(); } @SuppressWarnings("rawtypes") public String createSign(String characterEncoding, SortedMap<Object, Object> parameters) { StringBuffer sb = new StringBuffer(); Set es = parameters.entrySet(); Iterator it = es.iterator(); while (it.hasNext()) { Map.Entry entry = (Map.Entry) it.next(); String k = (String) entry.getKey(); Object v = entry.getValue(); if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) { sb.append(k + "=" + v + "&"); } } sb.append("key=" + wechatPayConfigBean.getApiKey() ); String sign = MD5Encode(sb.toString(), characterEncoding).toUpperCase(); return sign; } public static String MD5Encode(String origin, String charsetname) { String resultString = null; try { resultString = new String(origin); MessageDigest md = MessageDigest.getInstance("MD5"); if (charsetname == null || "".equals(charsetname)) resultString = byteArrayToHexString(md.digest(resultString.getBytes())); else resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname))); } catch (Exception exception) { } return resultString; } private static String byteArrayToHexString(byte b[]) { StringBuffer resultSb = new StringBuffer(); for (int i = 0; i < b.length; i++) resultSb.append(byteToHexString(b[i])); return resultSb.toString(); } private static String byteToHexString(byte b) { int n = b; if (n < 0) n += 256; int d1 = n / 16; int d2 = n % 16; return hexDigits[d1] + hexDigits[d2]; } private static final String hexDigits[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"}; @SuppressWarnings("rawtypes") public static String getRequestXml(SortedMap<Object, Object> parameters) { StringBuffer sb = new StringBuffer(); sb.append("<xml>"); Set es = parameters.entrySet(); Iterator it = es.iterator(); while (it.hasNext()) { Map.Entry entry = (Map.Entry) it.next(); String k = (String) entry.getKey(); String v = (String) entry.getValue(); if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) { sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">"); } else { sb.append("<" + k + ">" + v + "</" + k + ">"); } } sb.append("</xml>"); return sb.toString(); } /** * * 发送https请求 * * @param requestUrl 请求地址 * @param requestMethod 请求方式(GET、POST) * @param outputStr 提交的数据 * @return 返回微信服务器响应的信息 */ public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) { try { // 创建SSLContext对象,并使用我们指定的信任管理器初始化 TrustManager[] tm = {new MyX509TrustManager()}; SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); sslContext.init(null, tm, new java.security.SecureRandom()); // 从上述SSLContext对象中得到SSLSocketFactory对象 SSLSocketFactory ssf = sslContext.getSocketFactory(); URL url = new URL(requestUrl); HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); conn.setSSLSocketFactory(ssf); conn.setDoOutput(true); conn.setDoInput(true); conn.setUseCaches(false); // 设置请求方式(GET/POST) conn.setRequestMethod(requestMethod); conn.setRequestProperty("content-type", "application/x-www-form-urlencoded"); // 当outputStr不为null时向输出流写数据 if (null != outputStr) { OutputStream outputStream = conn.getOutputStream(); // 注意编码格式 outputStream.write(outputStr.getBytes("UTF-8")); outputStream.close(); } // 从输入流读取返回内容 InputStream inputStream = conn.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8"); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); String str = null; StringBuffer buffer = new StringBuffer(); while ((str = bufferedReader.readLine()) != null) { buffer.append(str); } // 释放资源 bufferedReader.close(); inputStreamReader.close(); inputStream.close(); inputStream = null; conn.disconnect(); return buffer.toString(); } catch (ConnectException ce) { System.out.println("连接超时"); } catch (Exception e) { System.out.println("请求异常"); } return null; } public static String create_nonce_str() { return UUID.randomUUID().toString().replace("-", ""); } public static String create_timestamp() { return Long.toString(System.currentTimeMillis() / 1000); } /** * 解析xml * * @param strxml * @return * @throws Exception */ @SuppressWarnings({"rawtypes", "unchecked"}) public static Map doXMLParse(String strxml) throws Exception { strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\""); if (null == strxml || "".equals(strxml)) { return null; } Map m = new HashMap(); InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8")); SAXBuilder builder = new SAXBuilder(); Document doc = builder.build(in); Element root = doc.getRootElement(); List list = root.getChildren(); Iterator it = list.iterator(); while (it.hasNext()) { Element e = (Element) it.next(); String k = e.getName(); String v = ""; List children = e.getChildren(); if (children.isEmpty()) { v = e.getTextNormalize(); } else { v = getChildrenText(children); } m.put(k, v); } // 关闭流 in.close(); return m; } /** * 获取子结点的xml * * @param children * @return */ @SuppressWarnings("rawtypes") public static String getChildrenText(List children) { StringBuffer sb = new StringBuffer(); if (!children.isEmpty()) { Iterator it = children.iterator(); while (it.hasNext()) { Element e = (Element) it.next(); String name = e.getName(); String value = e.getTextNormalize(); List list = e.getChildren(); sb.append("<" + name + ">"); if (!list.isEmpty()) { sb.append(getChildrenText(list)); } sb.append(value); sb.append("</" + name + ">"); } } return sb.toString(); } }
原文地址:https://www.cnblogs.com/sung1024/p/11700735.html