微信支付-Java-SpringMVC基础一些代码支持

原创
2016/07/05 15:26
阅读数 2K

官网文档和demo代码下载地址

https://mp.weixin.qq.com/htmledition/res/bussiness-faq/wx_app_pay.zip

  1. 基础常量代码

    package com.xiaoshuai.util;
    /**
     * 配置类
     * @author 小帅帅
     * @date  2016-7-5下午01:40:53
     */
    public class ConfigUtil {
    	/**
    	 * 服务号相关信息
    	 */
    	 public final static String APPID = "";//服务号的应用号
    	 public final static String APP_SECRECT = "";//服务号的应用密码
    	 public final static String TOKEN = "weixinCourse";//服务号的配置token
    	 public final static String MCH_ID = "";//商户号
    	 public final static String API_KEY = "";//API密钥
    	 public final static String SIGN_TYPE = "MD5";//签名加密方式
    	 public final static String CERT_PATH = "";//微信支付证书存放路径地址
    	//微信支付统一接口的回调action
    	 public final static String NOTIFY_URL = "";
    	//微信支付成功支付后跳转的地址
    	 public final static String SUCCESS_URL = "http://www.xiaoshuaishuai.com";
    	 //oauth2授权时回调action
    	 public final static String REDIRECT_URI = "";
    	/**
    	 * 微信基础接口地址
    	 */
    	 //获取token接口(GET)
    	 public final static String TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
    	 //oauth2授权接口(GET)
    	 public final static String OAUTH2_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
    	 //刷新access_token接口(GET)
    	 public final static String REFRESH_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN";
    	
    	/**
    	 * 微信支付接口地址
    	 */
    	//微信支付统一接口(POST)
    	public final static String UNIFIED_ORDER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    	//微信退款接口(POST)
    	public final static String REFUND_URL = "https://api.mch.weixin.qq.com/secapi/pay/refund";
    	//订单查询接口(POST)
    	public final static String CHECK_ORDER_URL = "https://api.mch.weixin.qq.com/pay/orderquery";
    	//关闭订单接口(POST)
    	public final static String CLOSE_ORDER_URL = "https://api.mch.weixin.qq.com/pay/closeorder";
    	//退款查询接口(POST)
    	public final static String CHECK_REFUND_URL = "https://api.mch.weixin.qq.com/pay/refundquery";
    	//对账单接口(POST)
    	public final static String DOWNLOAD_BILL_URL = "https://api.mch.weixin.qq.com/pay/downloadbill";
    	//短链接转换接口(POST)
    	public final static String SHORT_URL = "https://api.mch.weixin.qq.com/tools/shorturl";
    	//接口调用上报接口(POST)
    	public final static String REPORT_URL = "https://api.mch.weixin.qq.com/payitil/report";
    }
    

     

  2. 支付工具类代码

    package com.xiaoshuai.util;
    
    import java.util.Date;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Random;
    import java.util.Set;
    import java.util.SortedMap;
    import java.util.TreeMap;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import com.alibaba.fastjson.*;
    
    
    /**
     * 支付类
     * @author 小帅帅
     * @date  2016-7-5下午01:41:54
     */
    public class PayCommonUtil {
    	@SuppressWarnings("unused")
    	private static Logger log = LoggerFactory.getLogger(PayCommonUtil.class);
    	public static String CreateNoncestr(int length) {
    		String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    		String res = "";
    		for (int i = 0; i < length; i++) {
    			Random rd = new Random();
    			res += chars.indexOf(rd.nextInt(chars.length() - 1));
    		}
    		return res;
    	}
    
    	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;
    	}
    	/**
    	 * @author 小帅帅
    	 * @date  2016-7-5下午01:41:54
    	 * @Description:sign签名
    	 * @param characterEncoding 编码格式
    	 * @param parameters 请求参数
    	 * @return
    	 */
    	@SuppressWarnings("unchecked")
    	public static 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=" + ConfigUtil.API_KEY);
    		String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
    		return sign;
    	}
    	/**
    	 * @author 小帅帅
    	 * @date  2016-7-5下午01:41:54
    	 * @Description:将请求参数转换为xml格式的string
    	 * @param parameters  请求参数
    	 * @return
    	 */
    	@SuppressWarnings("unchecked")
    	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();
    	}
    	/**
    	 * @author 小帅帅
    	 * @date  2016-7-5下午01:41:54
    	 * @Description:返回给微信的参数
    	 * @param return_code 返回编码
    	 * @param return_msg  返回信息
    	 * @return
    	 */
    	public static String setXML(String return_code, String return_msg) {
    		return "<xml><return_code><![CDATA[" + return_code
    				+ "]]></return_code><return_msg><![CDATA[" + return_msg
    				+ "]]></return_msg></xml>";
    	}
    	
    	
    	/**
    	 * 
    	 * getPrepayId(调用微信统一下单接口,生成微信预支付id)
    	 * @param totalFee    支付金额
    	 * @param ipAddress   ip地址
    	 * @param orderNumber 订单号
    	 * @param body        商品或支付单简要描述
    	 * @param openid      trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识
    	 * @return
    	 * @throws Exception 
    	 * @throws
    	 * @author 小帅帅
    	 * @date  2016-7-5下午01:41:54
    	 */
    	@SuppressWarnings("unchecked")
    	public static Map<String, String>  getPrepayId(String totalFee,String ipAddress,String orderNumber,String body,String openid) throws Exception{
    		SortedMap<Object,Object> parameters = new TreeMap<Object,Object>();
    		parameters.put("appid", ConfigUtil.APPID);
    		parameters.put("mch_id", ConfigUtil.MCH_ID);
    		parameters.put("nonce_str", CreateNoncestr());
    		parameters.put("body", body);
    		parameters.put("out_trade_no", orderNumber);
    		parameters.put("total_fee", totalFee);
    		parameters.put("spbill_create_ip",ipAddress);
    		parameters.put("notify_url", ConfigUtil.NOTIFY_URL);
    		parameters.put("trade_type", "JSAPI");
    		parameters.put("openid", openid);
    		String sign = PayCommonUtil.createSign("UTF-8", parameters);
    		parameters.put("sign", sign);
    		String requestXML = PayCommonUtil.getRequestXml(parameters);
    		String result =CommonUtil.httpsRequest(ConfigUtil.UNIFIED_ORDER_URL, "POST", requestXML);
    		Map<String, String> map = XMLUtil.doXMLParse(result);//解析微信返回的信息,以Map形式存储便于取值
    		return map;
    	}
    	
    	/**
    	 * 
    	 * queryWeiXinOrder(微信订单查询)
    	 * @param orderNumber  订单号
    	 * @return   当返回  return_code="SUCCESS"  
    	 *           和result_code="SUCCESS" 时 获取交易状态SUCCESS—支付成功
                                                       REFUND—转入退款
                                                       NOTPAY—未支付
                                                       CLOSED—已关闭
                                                       REVOKED—已撤销(刷卡支付)
                                                       USERPAYING--用户支付中
                                                       PAYERROR--支付失败(其他原因,如银行返回失败)
    	 * @throws Exception 
    	 * @throws
    	 * @author 小帅帅
    	 * @date  2016-7-5下午01:41:54
    	 */
    	@SuppressWarnings("unchecked")
    	public static Map<String, String>  queryWeiXinOrder(String orderNumber) throws Exception{
    		SortedMap<Object,Object> parameters = new TreeMap<Object,Object>();
    		parameters.put("appid", ConfigUtil.APPID);
    		parameters.put("mch_id", ConfigUtil.MCH_ID);
    		parameters.put("nonce_str", CreateNoncestr());
    		parameters.put("out_trade_no", orderNumber);
    		String sign = PayCommonUtil.createSign("UTF-8", parameters);
    		parameters.put("sign", sign);
    		String requestXML = PayCommonUtil.getRequestXml(parameters);
    		String result =CommonUtil.httpsRequest(ConfigUtil.CHECK_ORDER_URL, "POST", requestXML);
    		Map<String, String> map = XMLUtil.doXMLParse(result);//解析微信返回的信息,以Map形式存储便于取值
    		return map;
    	}
    	
    	
    	
    	/**
    	 * 
    	 * createPackageValue(调起支付)
    	 * @param appid
    	 * @param appKey
    	 * @param prepay_id
    	 * @return 
    	 * @throws
    	 * @author 小帅帅
    	 * @date  2016-7-5下午01:41:54
    	 */
    	 public static String createPackageValue(String prepay_id)  {  
    		    SortedMap<Object,Object> params = new TreeMap<Object,Object>();
    	        params.put("appId", ConfigUtil.APPID);
    	        params.put("timeStamp", Long.toString(new Date().getTime()));
    	        params.put("nonceStr", PayCommonUtil.CreateNoncestr());
    	        params.put("package", "prepay_id="+prepay_id);
    	        params.put("signType", ConfigUtil.SIGN_TYPE);
    	        String paySign =  PayCommonUtil.createSign("UTF-8", params);
    	        params.put("packageValue", "prepay_id="+prepay_id);    //这里用packageValue是预防package是关键字在js获取值出错
    	        params.put("paySign", paySign);                                                          //paySign的生成规则和Sign的生成规则一致
    	        params.put("sendUrl", ConfigUtil.SUCCESS_URL);                               //付款成功后跳转的页面     
    	        String json = JSONObject.toJSONString(params);
    	        return json;
    	    }  
    }
    

     

  3. 请求业务代码

    package com.xiaoshuai.controller;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.math.BigDecimal;
    import java.util.Map;
    import java.util.Random;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.jdom.JDOMException;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import com.xiaoshuai.util.CommonUtil;
    import com.xiaoshuai.util.PayCommonUtil;
    /**
     * 支付请求Controller
     * @author 小帅帅
     * @date  2016-7-5下午02:08:47
     */
    @Controller
    @RequestMapping(value="pay")
    public class WeiXinPayController {
    	
    	/**
    	 * 
    	 * index(支付首页)
    	 * @return 
    	 */
    	@RequestMapping(value="index")
    	public  String   index(){
    		return "pay";
    	}
    	
    	
    	/**
    	 * 
    	 * payOrder(调起微信支付)
    	 * @param request
    	 * @param totalFee   //支付金额
    	 * @param body       //支付描述
    	 * @return 
    	 * @throws Exception 
    	 */
        @RequestMapping(value="payOrder")
        @ResponseBody
    	public String payOrder(HttpServletRequest request,double totalFee,String body) throws Exception{
    		String resultString=null;
    		BigDecimal fee = new BigDecimal(totalFee); // 微信支付参数以分为单位。
    		fee = fee.multiply(new BigDecimal(100));
    		String payFee=fee.longValue()+"";
    		//1 生成预支付id
    		String ipAddress=request.getRemoteAddr();
    		String orderNumber=System.currentTimeMillis()+new Random().nextInt(100)+"";
    		String openid="o2VKNju8JqCeGVoEWJ1S8Ue_up8E";  //调用网页授权接口获取
    		try {
    			Map<String, String> map=PayCommonUtil.getPrepayId(payFee, ipAddress, orderNumber, body, openid);
    			String  prepay_id=map.get("prepay_id");
    			//2 给H5页面传递参数  调起微信支付
    			resultString=PayCommonUtil.createPackageValue(prepay_id);
    			
    		} catch (JDOMException e) {
    			e.printStackTrace();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    		return   resultString;
    	}
        
    	/**
    	 * 
    	 * updateOrderState(异步回调通知)
    	 * 
    	 * @param request
    	 */
        @RequestMapping(value="noticePay")
    	public void updateOrderState(HttpServletRequest request,HttpServletResponse response) {
    		try {
    			PrintWriter out= response.getWriter();
    			// xml请求解析
    			Map<String, Object> requestMap = CommonUtil.parseXml(request);
    			String orderNumber = (String) requestMap.get("out_trade_no");
    			if (orderNumber != null) {
    				// 调用微信查询订单接口,
    				Map<String, String> orderMap = PayCommonUtil.queryWeiXinOrder(orderNumber);
    				if (orderMap.get("return_code") != null&& orderMap.get("return_code").equalsIgnoreCase("SUCCESS")) {
    					if (orderMap.get("result_code") != null&& orderMap.get("result_code").equalsIgnoreCase("SUCCESS")) {
    						if (orderMap.get("trade_state") != null&& orderMap.get("trade_state").equalsIgnoreCase("SUCCESS")) {
    							// 支付成功。。。。开始更新你的订单状态吧 根据自己的业务去修改
    							String resultXml="<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
    							out.println(resultXml);
    						}
    					}
    				}
    			}
    
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    
    	}
     
    }
    
  4. 项目结构。只是简单的基础代码                                                                                                                                

5.pay.jsp

<%@ page language="java" contentType="text/html; charset=utf-8"
	pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
		<meta name="viewport"
			content="initial-scale=1, maximum-scale=3, minimum-scale=1, user-scalable=no">
		<title>微信支付</title>
	</head>
	<body>
		<div style="text-align: center; padding: 10px 10px 10px 10px">
			<span
				style="color: red; font-size: 20px; font-weight: bold; display: none">请在微信浏览器中打开</span>
		</div>
		支付金额:
		<input type="text" id="totalFee" style="width: 80%; height: 30px;" />
		<br>
		<br>
		支付描述:
		<input type="text" id="body" style="width: 80%; height: 30px;" />
		<br>
		<br>
		<input type="button" value="确定" id="pay"
			style="width: 150px; height: 80px;">
		<script src="<%=basePath%>resources/js/jquery.min.js"
			type="text/javascript"></script>
		<script type="text/javascript">
var basePath = "<%=basePath%>";  
$(function(){
	$("#pay").click(payOrder);
	if(!isWeiXin()){
		$("span").show();
		alert("请在微信浏览器中打开");
	}else{
		$("span").hide();
	}
})


function isWeiXin(){
    var ua = window.navigator.userAgent.toLowerCase();
    if(ua.match(/MicroMessenger/i) == 'micromessenger'){
        return true;
    }else{
        return false;
    }
}


function  payOrder(){
	if(!isWeiXin()){
		alert("请在微信浏览器中打开")
		$("span").show();
		return;
	}else{
		$("span").hide();
	}
	
	var totalFee=$("#totalFee").val();
	var body=$("#body").val();
	$.ajax({
        type: "post",
        url:basePath+"pay/payOrder" ,
        data: {'totalFee':totalFee, 'body':body},
        dataType: "json",
        success: function(data){
        	WeixinJSBridge.invoke('getBrandWCPayRequest',{  
                "appId" : data.appId,                  //公众号名称,由商户传入  
                "timeStamp":data.timeStamp,          //时间戳,自 1970 年以来的秒数  
                "nonceStr" : data.nonceStr,         //随机串  
                "package" : data.packageValue,      //<span style="font-family:微软雅黑;">商品包信息</span>  
                "signType" : data.signType,        //微信签名方式:  
                "paySign" : data.paySign           //微信签名  
                },function(res){       
                if(res.err_msg == "get_brand_wcpay_request:ok" ) {  
                    window.location.href=data.sendUrl;  
                }else{  
                    alert("fail");  
                  //  window.location.href="http://183.45.18.197:8016/wxweb/config/oauth!execute.action";     
                                 
                }  
            });  
        	
           }
    });
}





</script>
	</body>
</html>

展开阅读全文
加载中
点击加入讨论🔥(3) 发布并加入讨论🔥
3 评论
11 收藏
2
分享
返回顶部
顶部