欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2024-01-22 21:45:10
...

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


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

微信的API的流程图 :

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

微信支付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

相关标签: JAVA 微信支付