微信小程序订单支付、退款

微信小程序订单支付及退款功能

源码:

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("&notify_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版权协议,转载请附上原文出处链接和本声明。