微信小程序订单支付及退款功能
源码:
public class Test_OrderControllerImpl {
private static final Logger logger = Logger.getLogger(PayServiceImpl.class);
@Value("${WX_AppID}")
private String appId;
@Value("${NotityUrl}")
private String notityUrl;
/**
* 支付订单接口
* @param payDto
* @param request
* @return
*/
@Test
public JSONObject payOrder(PayDto payDto, HttpServletRequest request) {
if (logger.isDebugEnabled()) {
logger.debug("entering payOrder(PayDto)");
logger.debug("payDto: \"" + payDto + "\"");
}
JSONObject jsonObject = new JSONObject();
boolean result = true;
String info = "成功了,获取到prepayId";
String openId = payDto.getOpenId();
if(StringUtils.isBlank(openId)) {
String key = null;
String mchId = null;
openId = openId.replace("\"", "").trim();
String clientIP = CommonUtil.getClientIp(request);
int money = (int)(1*100);
String orderCode = "";
logger.error("openId: " + openId + ", clientIP: " + clientIP + ", money: " + money + ", orderCode: " + orderCode );
String randomNonceStr = RandomUtils.generateMixString(32);
Map<String, String> rest = unifiedOrder(openId,clientIP,randomNonceStr,money,orderCode,key,mchId);
String prepayId = rest.get("prepay_id");
String randomStr = rest.get("nonce_str");
logger.error("prepayId: " + prepayId);
if(StringUtils.isBlank(prepayId)) {
result = false;
info = "出错了,未获取到prepayId";
} else {
String timeStamp = String.valueOf(System.currentTimeMillis() / 1000 );
SignInfo signInfo = new SignInfo();
try {
signInfo = createSignInfo(prepayId, randomStr, timeStamp);
String sign = getTwoSign(signInfo,key);
signInfo.setSign(sign);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
jsonObject.put("signInfo", signInfo);
}
}
jsonObject.put("result", result);
jsonObject.put("info", info);
System.out.println("---------"+jsonObject+"----------");
return jsonObject;
}
/**
* 调用统一下单接口
* @param openId
*/
private Map<String, String> unifiedOrder(String openId, String clientIP, String randomNonceStr, int money, String orderCode,String key,String mchId) {
try {
String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
PayInfo payInfo = createPayInfo(openId,clientIP,randomNonceStr,money,orderCode,mchId);
String md5 = getSign(payInfo,key);
payInfo.setSign(md5);
logger.error("md5 value: " + md5);
String xml = CommonUtil.payInfoToXML(payInfo);
xml = xml.replace("__", "_").replace("<![CDATA[", "").replace("]]>", "");
StringBuffer buffer = CommonUtil.httpsRequest(url, "POST", xml);
Map<String, String> result = CommonUtil.parseXml(buffer.toString());
System.out.println("-----result----:"+result+"----");
String return_code = result.get("return_code");
if(StringUtils.isNotBlank(return_code) && return_code.equals("SUCCESS")) {
String return_msg = result.get("return_msg");
if(StringUtils.isNotBlank(return_msg) && !return_msg.equals("OK")) {
//log.error("统一下单错误!");
return null;
}
return result;
} else {
return null;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private PayInfo createPayInfo(String openId, String clientIP, String randomNonceStr, int money,String orderCode,String mchId) {
Date date = new Date();
String timeStart = TimeUtils.formatDate(date, "yyyyMMddHHmmss");
String timeExpire = TimeUtils.formatDate(TimeUtils.addDay(date, 2), "yyyyMMddHHmmss");
PayInfo payInfo = new PayInfo();
payInfo.setAppid(appId);
payInfo.setMch_id(mchId);
payInfo.setDevice_info("WEB");
payInfo.setNonce_str(randomNonceStr);
payInfo.setSign_type("MD5"); //默认即为MD5
payInfo.setBody("**");
payInfo.setAttach("商品名称");
payInfo.setOut_trade_no(orderCode);
payInfo.setTotal_fee(money);
payInfo.setSpbill_create_ip(clientIP);
payInfo.setTime_start(timeStart);
payInfo.setTime_expire(timeExpire);
payInfo.setNotify_url(notityUrl);
payInfo.setTrade_type("JSAPI");
payInfo.setLimit_pay("no_credit");
payInfo.setOpenid(openId);
return payInfo;
}
private String getSign(PayInfo payInfo,String key) throws Exception {
StringBuffer sb = new StringBuffer();
sb.append("appid=" + payInfo.getAppid())
.append("&attach=" + payInfo.getAttach())
.append("&body=" + payInfo.getBody())
.append("&device_info=" + payInfo.getDevice_info())
.append("&limit_pay=" + payInfo.getLimit_pay())
.append("&mch_id=" + payInfo.getMch_id())
.append("&nonce_str=" + payInfo.getNonce_str())
.append("¬ify_url=" + payInfo.getNotify_url())
.append("&openid=" + payInfo.getOpenid())
.append("&out_trade_no=" + payInfo.getOut_trade_no())
.append("&sign_type=" + payInfo.getSign_type())
.append("&spbill_create_ip=" + payInfo.getSpbill_create_ip())
.append("&time_expire=" + payInfo.getTime_expire())
.append("&time_start=" + payInfo.getTime_start())
.append("&total_fee=" + payInfo.getTotal_fee())
.append("&trade_type=" + payInfo.getTrade_type())
.append("&key=" + key);
logger.error("排序后的拼接参数:" + sb.toString());
System.out.println("排序后的拼接参数:" +sb.toString());
return CommonUtil.getMD5(sb.toString().trim()).toUpperCase();
}
private SignInfo createSignInfo(String prepayId,String randomNonceStr,String timeStamp) {
SignInfo signInfo = new SignInfo();
signInfo.setAppId(appId);
signInfo.setNonceStr(randomNonceStr);
signInfo.setPrepay_id("prepay_id="+prepayId);
signInfo.setSignType("MD5");
signInfo.setTimeStamp(timeStamp);
return signInfo;
}
//二次签名
private String getTwoSign(SignInfo signInfo,String key) throws Exception {
StringBuffer sb = new StringBuffer();
sb.append("appId=" + signInfo.getAppId())
.append("&nonceStr=" + signInfo.getNonceStr())
.append("&package="+signInfo.getPrepay_id())
.append("&signType=" + signInfo.getSignType())
.append("&timeStamp=" + signInfo.getTimeStamp())
.append("&key=" + key);
logger.error("排序后的拼接参数:" + sb.toString());
return CommonUtil.getMD5(sb.toString().trim()).toUpperCase();
}
/**
* 微信支付回调接口
* @param request
* @param response
*/
@Test
public void payCallback(HttpServletRequest request, HttpServletResponse response) {
logger.info("微信回调接口方法 start");
logger.info("微信回调接口 操作逻辑 start ");
String inputLine = "";
String notityXml = "";
try {
while((inputLine = request.getReader().readLine()) !=null ) {
notityXml += inputLine;
}
//关闭流
request.getReader().close();
logger.info("微信回调内容信息:"+notityXml);
//解析成Map
Map<String,String> map = CommonUtil.parseXml(notityXml);
logger.info("微信回调内容信息:"+map);
//判断 支付是否成功
if("SUCCESS".equals(map.get("result_code"))) {
logger.info("微信回调返回是否支付成功:是");
//获得 返回的商户订单号
String outTradeNo = map.get("out_trade_no");
logger.info("微信回调返回商户订单号:"+outTradeNo);
//进数据库查询这条订单号
OrderDto orderInfo = orderBiz.queryOrderByTradeNo(outTradeNo);
logger.info("微信回调 根据订单号查询订单状态: "+orderInfo.getPayState());
int cashFee = Integer.valueOf(map.get("cash_fee"));
if (cashFee == orderInfo.getJsMoney()*100) {
if( 0 == orderInfo.getPayState() ) {
//修改订单状态
orderInfo.setPayState(1);
//更新订单
int count = orderBiz.updateOrder(orderInfo);
//判断 是否更新成功
if(count == 1) {
logger.info("微信回调 订单号:"+ outTradeNo +",修改状态成功" );
//封装 返回值
StringBuffer buffer = new StringBuffer();
buffer.append("<xml>");
buffer.append("<return_code>SUCCESS</return_code>");
buffer.append("<return_msg>OK</return_msg>");
buffer.append("<xml>");
//给微信服务器返回 成功标示 否则会一直询问 咱们服务器 是否回调成
PrintWriter writer = response.getWriter();
//返回
writer.print(buffer.toString());
}
}
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Test
public JSONObject refundOrder(PayDto payDto, HttpServletRequest request) {
if (logger.isDebugEnabled()) {
logger.debug("entering refundOrder(PayDto)");
logger.debug("payDto: \"" + payDto + "\"");
}
JSONObject jsonObject = new JSONObject();
boolean result = true;
String info = "";
String key = null;
String mchId = null;
int money = (int)(10*100);//金额*100
String orderCode = "";//订单编号
String randomNonceStr = RandomUtils.generateMixString(32);
String outRefundNo = TimeUtils.formatDate(new Date(),"yyyyMMddHHmmssSSS")+"10012";
try {
String url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
RefundInfo refundInfo = createRefundInfo(mchId, randomNonceStr, outRefundNo, orderCode, money);
String md5 = getSignRefund(refundInfo, key);
refundInfo.setSign(md5);
logger.error("md5 value: " + md5);
String xml = CommonUtil.payInfoToXML(refundInfo);
// xml = xml.replace("__", "_").replace("<![CDATA[1]]>", "1");
xml = xml.replace("__", "_").replace("<![CDATA[", "").replace("]]>", "");
// String keyPath = System.getProperty("user.dir") + "/" + apiclientPath;
String keyPath = null;
StringBuffer buffer = CommonUtil.refundRequest(url,xml,mchId,keyPath);
Map<String, String> resultStr = CommonUtil.parseXml(buffer.toString());
String return_code = resultStr.get("return_code");
if(StringUtils.isNotBlank(return_code) && return_code.equals("SUCCESS")) {
//更新订单
result = true;
info = "退款成功";
jsonObject.put("resultStr", resultStr);
} else {
//更新订单
result = false;
info = "退款失败";
jsonObject.put("resultStr", resultStr);
}
} catch (Exception e) {
e.printStackTrace();
}
jsonObject.put("result", result);
jsonObject.put("info", info);
return jsonObject;
}
private RefundInfo createRefundInfo(String mchId,String nonceStr,String outRefundNo,String outTradeNo,int fee) {
RefundInfo refundInfo = new RefundInfo();
refundInfo.setAppid(appId);
refundInfo.setMch_id(mchId);
refundInfo.setNonce_str(nonceStr);
refundInfo.setSign_type("MD5"); //默认即为MD5
refundInfo.setOut_trade_no(outTradeNo);
refundInfo.setOut_refund_no(outRefundNo);
refundInfo.setTotal_fee(fee);
refundInfo.setRefund_fee(fee);
return refundInfo;
}
private String getSignRefund(RefundInfo refundInfo,String key) throws Exception {
StringBuffer sb = new StringBuffer();
sb.append("appid=" + appId)
.append("&mch_id=" + refundInfo.getMch_id())
.append("&nonce_str=" + refundInfo.getNonce_str())
.append("&out_refund_no=" + refundInfo.getOut_refund_no())
.append("&out_trade_no=" + refundInfo.getOut_trade_no())
.append("&refund_fee=" + refundInfo.getRefund_fee())
.append("&sign_type=" + refundInfo.getSign_type())
.append("&total_fee=" + refundInfo.getTotal_fee())
.append("&key=" + key);
logger.error("排序后的拼接参数:" + sb.toString());
System.out.println("排序后的拼接参数:" +sb.toString());
return CommonUtil.getMD5(sb.toString().trim()).toUpperCase();
}
}
public class PayDto implements Serializable {
private static final long serialVersionUID = 1L;
/** 微信登录的sessionKey **/
private String sessionKey;
/** 微信登录的openId **/
private String openId;
/** 订单id **/
private String orderId;
}
/**
*签名参数
**/
public class SignInfo {
private String appId;//小程序ID
private String timeStamp;//时间戳
private String nonceStr;//随机串
@XStreamAlias("package")
private String prepay_id;
private String signType;//签名方式
private String sign;//签名
}
/**
* 支付传入参数
*/
public class PayInfo {
/**
* 小程序APPID
*/
private String appid;
/**
* 商户号
*/
private String mch_id;
/**
* 设备号,小程序传"WEB"
*/
private String device_info;
private String nonce_str;
private String sign;
/**
* 签名类型
*/
private String sign_type;
/**
* 商品简单描述:腾讯充值中心-QQ会员充值
*/
private String body;
//private String detail;
/**
* 附加数据:深圳分店
*/
private String attach;
private String out_trade_no;
private int total_fee;
private String spbill_create_ip;
private String time_start;
private String time_expire;
/**
* 异步接收微信支付结果通知的回调地址
*/
private String notify_url;
/**
* 交易类型,JSAPI
*/
private String trade_type;
/**
* 指定支付方式,no_credit
*/
private String limit_pay;
/**
* 登录人openid
*/
private String openid;
/**
* 商户key
*/
private String wxKey;
}
/**
* 退款返回参数
*/
public class RefundInfo {
/**
* 小程序APPID
*/
private String appid;
/**
* 商户号
*/
private String mch_id;
/**
* 随机字符串
*/
private String nonce_str;
/**
* 签名
*/
private String sign;
/**
* 签名类型
*/
private String sign_type;
/**
* 订单号
*/
private String out_trade_no;
/**
* 退款单号
*/
private String out_refund_no;
/**
* 订单金额
*/
private int total_fee;
/**
* 退款金额
*/
private int refund_fee;
/**
* 商户key
*/
private String wxKey;
}
版权声明:本文为gust150原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。