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
*/
@Service
public 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();
}
}