微信支付JAVA后台可直接使用

微信支付JAVA后台可直接使用


最近写了一个微信小程序,需求是用到微信支付,支付成功生成二维码。以便做门票使用。

微信的API的流程图 :

理解流程图特别重要,方便用来规范的写Java。

微信支付API流程图

  1. 觉得写微信支付的时候并没有那么多麻烦,最后我会附上demo供大家学习
  2. 自己的服务器后台接收到参数,服务器进行处理,然后把参数传给商户后台系统进行处理,然后返回结果等等。
  3. 商户接入微信支付,调用API必须遵循以下规则:

    表4.1 接口规则

    传输方式 为保证交易安全性,采用HTTPS传输
    提交方式 采用POST方法提交
    数据格式 提交和返回数据都为XML格式,根节点名为xml
    字符编码 统一采用UTF-8字符编码
    签名算法 MD5,后续会兼容SHA1、SHA256、HMAC等。
    签名要求 请求和接收数据均需要校验签名,详细方法请参考安全规范-签名算法
    证书要求 调用申请退款、撤销订单接口需要商户证书
    判断逻辑 先判断协议字段返回,再判断业务返回,最后判断交易状态

下面是代码讲解:

首先是三个Javabean:

OrderInfo,OrderReturnInfo,SignInfo

//OrderInfo的Java文件
 
 
 
package com.weixinpay.model;
 
/**
 * 预订单
 * 
 * @author zuoliangzhu
 *
 */
public class OrderInfo {
    private String appid;// 小程序ID    
    private String mch_id;// 商户号
    private String nonce_str;// 随机字符串
    private String sign_type;//签名类型
    private String sign;// 签名
    private String body;// 商品描述
    private String out_trade_no;// 商户订单号
    private int total_fee;// 标价金额 ,单位为分
    private String spbill_create_ip;// 终端IP
    private String notify_url;// 通知地址
    private String trade_type;// 交易类型
    private String openid;//用户标识    
 
    public String getSign_type() {
        return sign_type;
    }
 
    public void setSign_type(String sign_type) {
        this.sign_type = sign_type;
    }
 
    public String getOpenid() {
        return openid;
    }
 
    public void setOpenid(String openid) {
        this.openid = openid;
    }
 
    public String getAppid() {
        return appid;
    }
 
    public void setAppid(String appid) {
        this.appid = appid;
    }
 
    public String getMch_id() {
        return mch_id;
    }
 
    public void setMch_id(String mch_id) {
        this.mch_id = mch_id;
    }
 
    public String getNonce_str() {
        return nonce_str;
    }
 
    public void setNonce_str(String nonce_str) {
        this.nonce_str = nonce_str;
    }
 
    public String getSign() {
        return sign;
    }
 
    public void setSign(String sign) {
        this.sign = sign;
    }
 
    public String getBody() {
        return body;
    }
 
    public void setBody(String body) {
        this.body = body;
    }
 
    public String getOut_trade_no() {
        return out_trade_no;
    }
 
    public void setOut_trade_no(String out_trade_no) {
        this.out_trade_no = out_trade_no;
    }
 
    public int getTotal_fee() {
        return total_fee;
    }
 
    public void setTotal_fee(int total_fee) {
        this.total_fee = total_fee;
    }
 
    public String getSpbill_create_ip() {
        return spbill_create_ip;
    }
 
    public void setSpbill_create_ip(String spbill_create_ip) {
        this.spbill_create_ip = spbill_create_ip;
    }
 
    public String getNotify_url() {
        return notify_url;
    }
 
    public void setNotify_url(String notify_url) {
        this.notify_url = notify_url;
    }
 
    public String getTrade_type() {
        return trade_type;
    }
 
    public void setTrade_type(String trade_type) {
        this.trade_type = trade_type;
    }
 
}
//OrderReturnInfo的Java文件
 
package com.weixinpay.model;
 
public class OrderReturnInfo {
    private String return_code;
    private String return_msg;
    private String result_code;
    private String appid;
    private String mch_id;
    private String nonce_str;
    private String sign;
    private String prepay_id;
    private String trade_type;
    public String getReturn_code() {
        return return_code;
    }
    public void setReturn_code(String return_code) {
        this.return_code = return_code;
    }
    public String getReturn_msg() {
        return return_msg;
    }
    public void setReturn_msg(String return_msg) {
        this.return_msg = return_msg;
    }
    public String getResult_code() {
        return result_code;
    }
    public void setResult_code(String result_code) {
        this.result_code = result_code;
    }
    public String getAppid() {
        return appid;
    }
    public void setAppid(String appid) {
        this.appid = appid;
    }
    public String getMch_id() {
        return mch_id;
    }
    public void setMch_id(String mch_id) {
        this.mch_id = mch_id;
    }
    public String getNonce_str() {
        return nonce_str;
    }
    public void setNonce_str(String nonce_str) {
        this.nonce_str = nonce_str;
    }
    public String getSign() {
        return sign;
    }
    public void setSign(String sign) {
        this.sign = sign;
    }
    public String getPrepay_id() {
        return prepay_id;
    }
    public void setPrepay_id(String prepay_id) {
        this.prepay_id = prepay_id;
    }
    public String getTrade_type() {
        return trade_type;
    }
    public void setTrade_type(String trade_type) {
        this.trade_type = trade_type;
    }
    
}
//SingInfo的Java文件
 
package com.weixinpay.model;
 
import com.thoughtworks.xstream.annotations.XStreamAlias;
 
/**
 * 签名信息
 * @author zuoliangzhu
 *
 */
public class SignInfo {
 
    private String appId;//小程序ID    
    private String timeStamp;//时间戳    
    private String nonceStr;//随机串    
    @XStreamAlias("package")
    private String repay_id;
    private String signType;//签名方式
    
    public String getAppId() {
        return appId;
    }
    public void setAppId(String appId) {
        this.appId = appId;
    }
    public String getTimeStamp() {
        return timeStamp;
    }
    public void setTimeStamp(String timeStamp) {
        this.timeStamp = timeStamp;
    }
    public String getNonceStr() {
        return nonceStr;
    }
    public void setNonceStr(String nonceStr) {
        this.nonceStr = nonceStr;
    }
    public String getRepay_id() {
        return repay_id;
    }
    public void setRepay_id(String repay_id) {
        this.repay_id = repay_id;
    }
    public String getSignType() {
        return signType;
    }
    public void setSignType(String signType) {
        this.signType = signType;
    }
    
    
    
}
//GetOpenId.java
 
package com.weixinpay;
 
import java.io.IOException;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
 
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;
import com.weixinpay.common.Configure;
 
/**
 * Servlet implementation class GetOpenId
 */
public class GetOpenId extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public GetOpenId() {
        super();
    }
 
    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String code = request.getParameter("code");
        HttpGet httpGet = new HttpGet("https://api.weixin.qq.com/sns/jscode2session?appid="+Configure.getAppID()+"&secret="+Configure.getSecret()+"&js_code="+code+"&grant_type=authorization_code");
                //设置请求器的配置
        HttpClient httpClient = HttpClients.createDefault();
        HttpResponse res = httpClient.execute(httpGet);
        HttpEntity entity = res.getEntity();
        String result = EntityUtils.toString(entity, "UTF-8");
        response.getWriter().append(result);
    }
 
    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }
 
}

这一步,是得到code,然后将APPID,小程序秘钥和code拼接起来,发送到微信支付的服务商后台,返回的结果是一个键值对组。

openID的结果:{"session_key":"XXXXXXXXXXXXXXXXXXX==","openid":"XXXXXXXXXXXXXXXXXXXXXXXXXX"}

得到openID之后就可以预下单处理了。

package com.weixinpay;
 
import java.io.IOException;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.apache.log4j.Logger;
 
import com.alibaba.fastjson.JSONObject;
import com.thoughtworks.xstream.XStream;
import com.weixinpay.common.Configure;
import com.weixinpay.common.HttpRequest;
import com.weixinpay.common.RandomStringGenerator;
import com.weixinpay.common.Signature;
import com.weixinpay.model.OrderInfo;
import com.weixinpay.model.OrderReturnInfo;
 
/**
 * 统一下单接口
 */
public class Xiadan extends HttpServlet {
    private static final long serialVersionUID = 1L;
    private static final Logger L = Logger.getLogger(Xiadan.class);
    /**
     * @see HttpServlet#HttpServlet()
     */
    public Xiadan() {
        super();
    }
 
    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        try {
            String openid = request.getParameter("openid");   //得到openID
            OrderInfo order = new OrderInfo();
            order.setAppid(Configure.getAppID());
            order.setMch_id(Configure.getMch_id());
            order.setNonce_str(RandomStringGenerator.getRandomStringByLength(32));
            String name="asdasd";      //商品名称,如果需要中文的商品名称需要转成 UTF-8的形式,否则会报错!
            
            order.setBody(name);
            order.setOut_trade_no(RandomStringGenerator.getRandomStringByLength(32));//随机的32位字符串
            order.setTotal_fee(1);   //这里的1 是1分钱的意思,a*100就是a块钱
            
            order.setSpbill_create_ip("需要返回到你的服务器额IP地址");
            order.setNotify_url("http://localhost:8080/weixinpay/PayResult");
            order.setTrade_type("JSAPI");
            order.setOpenid(openid);
            order.setSign_type("MD5");
            //生成签名
            String sign = Signature.getSign(order);
            order.setSign(sign);
            
            
            String result = HttpRequest.sendPost("https://api.mch.weixin.qq.com/pay/unifiedorder", order);
            System.out.println("___________________________"+result);//测试看返回结果,结果是一个XML的形式
            L.info("---------下单返回:"+result);
            XStream xStream = new XStream();
            xStream.alias("xml", OrderReturnInfo.class); 
 
            OrderReturnInfo returnInfo = (OrderReturnInfo)xStream.fromXML(result);
            JSONObject json = new JSONObject();
            json.put("prepay_id", returnInfo.getPrepay_id());//从结果中读取prepay_id
            response.getWriter().append(json.toJSONString());
        } catch (Exception e) {
            e.printStackTrace();
            L.error("-------", e);
        }
        
    }
 
    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }
 
}

String result = HttpRequest.sendPost("https://api.mch.weixin.qq.com/pay/unifiedorder", order);

把内容保存为一个对象,

传过去这个对象,返回的结果是xml的形式,取出prepay_id,json传输

下面是签名sign

//签名
package com.weixinpay;
 
import java.io.IOException;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.apache.log4j.Logger;
 
import com.alibaba.fastjson.JSONObject;
import com.weixinpay.common.Configure;
import com.weixinpay.common.RandomStringGenerator;
import com.weixinpay.common.Signature;
import com.weixinpay.model.SignInfo;
 
/**
 * 再签名
 */
public class Sign extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private static final Logger L = Logger.getLogger(Sign.class);
    public Sign() {
        super();
    }
 
	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	    try {
			String repay_id = request.getParameter("repay_id");
			SignInfo signInfo = new SignInfo();
			signInfo.setAppId(Configure.getAppID());
			long time = System.currentTimeMillis()/1000;
			signInfo.setTimeStamp(String.valueOf(time));
			signInfo.setNonceStr(RandomStringGenerator.getRandomStringByLength(32));
			signInfo.setRepay_id("prepay_id="+repay_id);
			signInfo.setSignType("MD5");
			//生成签名
			System.out.println("_________________________________________________________");
			String sign = Signature.getSign(signInfo);
			
			JSONObject json = new JSONObject();
			json.put("timeStamp", signInfo.getTimeStamp());
			json.put("nonceStr", signInfo.getNonceStr());
			json.put("package", signInfo.getRepay_id());
			json.put("signType", signInfo.getSignType());
			json.put("paySign", sign);
			L.info("-------再签名:"+json.toJSONString());
			response.getWriter().append(json.toJSONString());
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			L.error("-------", e);
		}
	}
 
	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}
 
}

MD5 是一种摘要生成算法, 通过在签名原始串后加上商户通信密钥的内容进行 MD5 运算, 形成的摘要字符串即为签名结果。

 最后进行支付结果的判断:

package com.weixinpay;
 
import java.io.DataInputStream;
import java.io.IOException;
import java.io.StringReader;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.apache.log4j.Logger;
 
import com.weixinpay.common.StreamUtil;
 
/**
 * 接收支付结果
 */
public class PayResult extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private static final Logger L = Logger.getLogger(PayResult.class);
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public PayResult() {
        super();
        // TODO Auto-generated constructor stub
    }
 
	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		//response.getWriter().append("Served at: ").append(request.getContextPath());
		
		String reqParams = StreamUtil.read(request.getInputStream());
	
	    
	     
		L.info("-------支付结果:"+reqParams);		
		StringBuffer sb = new StringBuffer("<xml><return_code>SUCCESS</return_code><return_msg>OK</return_msg></xml>");
		response.getWriter().append(sb.toString());
		L.error("___________________________________");
		 L.error("微信支付----验证签名成功"); 
		
	}
 
	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}
 
}

支付完成后,微信会把相关支付结果和用户信息发送给商户,商户需要接收处理,并返回应答。

对后台通知交互时,如果微信收到商户的应答不是成功或超时,微信认为通知失败,微信会通过一定的策略定期重新发起通知,尽可能提高通知的成功率,但微信不保证通知最终能成功。 (通知频率为15/15/30/180/1800/1800/1800/1800/3600,单位:秒)

注意:同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。

推荐的做法是,当收到通知进行处理时,首先检查对应业务数据的状态,判断该通知是否已经处理过,如果没有处理过再进行处理,如果处理过直接返回结果成功。在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。

特别提醒:商户系统对于支付结果通知的内容一定要做签名验证,并校验返回的订单金额是否与商户侧的订单金额一致,防止数据泄漏导致出现“假通知”,造成资金损失。

通知参数

字段名 变量名 必填 类型 示例值 描述
返回状态码 return_code String(16) SUCCESS

SUCCESS/FAIL

此字段是通信标识,非交易标识,交易是否成功需要查看result_code来判断

返回信息 return_msg String(128) 签名失败

返回信息,如非空,为错误原因

签名失败

参数格式校验错误

StringBuffer sb = new StringBuffer("<xml><return_code>SUCCESS</return_code><return_msg>OK</return_msg></xml>");

就像这样。

大概就是这么些东西,以后等我再研究研究就在更新下。

github还没发过东西,暂时先在CSDN上发一下代码吧。

大二新手做的,如果有错误,欢迎指出,谢谢大家!

代码链接:

https://download.csdn.net/download/lzjstudy/10548783

猜你喜欢

转载自blog.csdn.net/lzjstudy/article/details/81097679