admin管理员组

文章数量:1559079

1.首先可以下载官方sdk查看相关工具类

微信支付九游会下载官网sdk下载
其中wxpayconstants和wxpayutil会在后边使用到

import java.security.securerandom;
import java.util.*;
public class wxpayutil {
	private static final string symbols = "0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
	private static final random random = new securerandom();
	/**
	 * 获取随机字符串 32位  nonce str
	 *
	 * @return string 随机字符串
	 */
	public static string generatenoncestr() {
		char[] noncechars = new char[32];
		for (int index = 0; index < noncechars.length; index) {
			noncechars[index] = symbols.charat(random.nextint(symbols.length()));
		}
		return new string(noncechars);
	}
	
	/**
	 * 获取当前时间戳,单位秒
	 * 
	 * @return
	 */
	public static long getcurrenttimestamp() {
		return system.currenttimemillis() / 1000;
	}
	/**
	 * 获取当前时间戳,单位毫秒
	 * 
	 * @return
	 */
	public static long getcurrenttimestampms() {
		return system.currenttimemillis();
	}
}
import org.apache.http.client.httpclient;
/**
 * 常量
 */
public class wxpayconstants {
    public enum signtype {
        md5, hmacsha256
    }
    public static final string domain_api = "api.mch.weixin.qq";
    public static final string domain_api2 = "api2.mch.weixin.qq";
    public static final string domain_apihk = "apihk.mch.weixin.qq";
    public static final string domain_apius = "apius.mch.weixin.qq";
    public static final string fail     = "fail";
    public static final string success  = "success";
    public static final string hmacsha256 = "hmac-sha256";
    public static final string md5 = "md5";
    public static final string field_sign = "sign";
    public static final string field_sign_type = "sign_type";
    public static final string wxpaysdk_version = "wxpaysdk/3.0.9";
    public static final string user_agent = wxpaysdk_version 
            " ("  system.getproperty("os.arch")  " "  system.getproperty("os.name")  " "  system.getproperty("os.version") 
            ") java/"  system.getproperty("java.version")  " httpclient/"  httpclient.class.getpackage().getimplementationversion();
    public static final string micropay_url_suffix     = "/pay/micropay";
    public static final string unifiedorder_url_suffix = "/pay/unifiedorder";
    public static final string orderquery_url_suffix   = "/pay/orderquery";
    public static final string reverse_url_suffix      = "/secapi/pay/reverse";
    public static final string closeorder_url_suffix   = "/pay/closeorder";
    public static final string refund_url_suffix       = "/secapi/pay/refund";
    public static final string refundquery_url_suffix  = "/pay/refundquery";
    public static final string downloadbill_url_suffix = "/pay/downloadbill";
    public static final string report_url_suffix       = "/payitil/report";
    public static final string shorturl_url_suffix     = "/tools/shorturl";
    public static final string authcodetoopenid_url_suffix = "/tools/authcodetoopenid";
    // sandbox
    public static final string sandbox_micropay_url_suffix     = "/sandboxnew/pay/micropay";
    public static final string sandbox_unifiedorder_url_suffix = "/sandboxnew/pay/unifiedorder";
    public static final string sandbox_orderquery_url_suffix   = "/sandboxnew/pay/orderquery";
    public static final string sandbox_reverse_url_suffix      = "/sandboxnew/secapi/pay/reverse";
    public static final string sandbox_closeorder_url_suffix   = "/sandboxnew/pay/closeorder";
    public static final string sandbox_refund_url_suffix       = "/sandboxnew/secapi/pay/refund";
    public static final string sandbox_refundquery_url_suffix  = "/sandboxnew/pay/refundquery";
    public static final string sandbox_downloadbill_url_suffix = "/sandboxnew/pay/downloadbill";
    public static final string sandbox_report_url_suffix       = "/sandboxnew/payitil/report";
    public static final string sandbox_shorturl_url_suffix     = "/sandboxnew/tools/shorturl";
    public static final string sandbox_authcodetoopenid_url_suffix = "/sandboxnew/tools/authcodetoopenid";
}

2.创建商户号

创建商户号,登录商户平台配置小程序appid以及获取证书序列号、微信支付商户号、apiv3密钥,这部分比较简单不做详述

3.微信支付的三个核心步骤 预支付、验签、回调方法

微信支付接口调用方法有预支付、验签、回调方法、关闭订单以及查询订单和退款,其中的难点在验签和回调,废话不多说直接上代码。
导入依赖

<dependency>
            <groupid>com.github.wechatpay-apiv3</groupid>
            <artifactid>wechatpay-apache-httpclient</artifactid>
            <version>0.4.4</version>
</dependency>

将需要的密钥导入项目,也可以添加到properties文件中方便后期修改

    //小程序appid
	public static final string appid = "***************";
	//商户号
	public static final string mchid = "*****************";
	//证书序列号
	public static final string mchserialno = "***********";
	//v3密钥
	public static final string apiv3key = "**************";
	//支付通知回调
	public static final string notifyurl = "http://******";
	//小程序密钥
	public static final string secret="******************";
	//证书密钥
	public static final string privatekey = "************";
	//http客户端
	public static closeablehttpclient httpclient;
	//退款通知回调
	public static final string refundnotifyurl="http://**";
	public static autoupdatecertificatesverifier verifier;

1.预支付

public static void setup() throws ioexception {
		// 加载商户私钥(privatekey:私钥字符串)
		privatekey merchantprivatekey = pemutil.loadprivatekey(new bytearrayinputstream(privatekey.getbytes("utf-8")));
		// 加载平台证书(mchid:商户号,mchserialno:商户证书序列号,apiv3key:v3密钥)
		 verifier = new autoupdatecertificatesverifier(
				new wechatpay2credentials(mchid, new privatekeysigner(mchserialno, merchantprivatekey)),
				apiv3key.getbytes("utf-8"));
		// 初始化httpclient
		httpclient = wechatpayhttpclientbuilder.create().withmerchant(mchid, mchserialno, merchantprivatekey)
				.withvalidator(new wechatpay2validator(verifier)).build();
}
/**
	 * 获取小程序请求用户openid
	 * @param jscode
	 * @return
	 * @throws urisyntaxexception
	 * @throws ioexception
	 */
	public static string getopenid(string jscode) throws urisyntaxexception, ioexception {
		string url = "https://api.weixin.qq/sns/jscode2session?appid="
				appid"&secret="secret"&js_code="jscode"&grant_type=authorization_code";
		uribuilder uribuilder = new uribuilder(url);
		httpget httpget = new httpget(uribuilder.build());
		httpget.addheader("accept", "application/json");
		closeablehttpresponse response = httpclient.execute(httpget);
		string openidparse = entityutils.tostring(response.getentity());
		map<string,string> parse = (map) json.parse(openidparse);
		string openid = parse.get("openid");
		return openid;
}
//预支付方法,返回prepay_id(预支付id)paybean是用于接收前端数据的实体类
public static string order(paybean paybean,string outtradeno) throws ioexception, urisyntaxexception {
        setup();
		//url: 哪一种支付
		httppost httppost = new httppost("https://api.mch.weixin.qq/v3/pay/transactions/jsapi");
		httppost.addheader("accept", "application/json");
		httppost.addheader("content-type", "application/json; charset=utf-8");
		bytearrayoutputstream bos = new bytearrayoutputstream();
		objectmapper objectmapper = new objectmapper();
		string openid = getopenid(paybean.getjscode());
		objectnode rootnode = objectmapper.createobjectnode();
		rootnode.put("mchid", mchid)
		        .put("appid", appid)
		        .put("description", "")
				.put("notify_url",notifyurl )//异步通知 yrl
				.put("out_trade_no", outtradeno);//自己平台的商户号
		rootnode.putobject("amount").put("total", 1).put("currency", "cny");
		rootnode.putobject("payer").put("openid", openid);
		objectmapper.writevalue(bos, rootnode);
		httppost.setentity(new stringentity(bos.tostring("utf-8"), "utf-8"));
		closeablehttpresponse response = httpclient.execute(httppost);
		string bodyasstring = entityutils.tostring(response.getentity());
		system.out.println(bodyasstring);
		return bodyasstring;
}

2.验签(v3加密方式只有rsa非对称性加密)

	public ajaxresult pay(paybean paybean) throws exception {
	//后端生成
	string outtradeno = "ly"  system.currenttimemillis();// 平台商品号码
		string order = "";
		try {
			order = order(paybean, outtradeno);
		} catch (ioexception e) {
			// todo auto-generated catch block
			e.printstacktrace();
		} catch (urisyntaxexception e) {
			// todo auto-generated catch block
			e.printstacktrace();
		}
		//生成时间戳
		long timestamp = wxpayutil.getcurrenttimestamp();
		生成随机数订单号
		string generatenoncestr = wxpayutil.generatenoncestr();
		map<string, string> parse = (map) json.parse(order);
		// 需要签名的
		stringbuilder builder = new stringbuilder();
		builder.append(appid  "\n");
		builder.append(timestamp  "\n");
		builder.append(generatenoncestr  "\n");
		builder.append("prepay_id="  parse.get("prepay_id")  "\n");// 加签 商户号一致
		byte[] signbytes = builder.tostring().getbytes("utf-8");
		//加密方法
		string paysign = sign(signbytes);
		hashmap<string, string> signdata = new hashmap<string, string>(8);
		signdata.put("mchid", wechatpay.mchid);
		signdata.put("appid", wechatpay.appid);
		signdata.put("package", "prepay_id="  parse.get("prepay_id"));
		signdata.put("noncestr", generatenoncestr);// 随机字符串32位
		signdata.put("timestamp", timestamp.tostring());// 时间戳
		signdata.put("sign", paysign);
		return ajaxresult.success(signdata);
	}
/**
	    stringbuilder builder = new stringbuilder();
		builder.append(wechatpay.appid   "\n");
		builder.append(timestamp   "\n");
		builder.append(generatenoncestr   "\n");
		builder.append("prepay_id="   parse.get("prepay_id")   "\n");// 加签 商户号一致
		byte[] message = builder.tostring().getbytes("utf-8");
	 * @param message  需要签名的字符传byte数组
	 * @return
	 * @throws ioexception
	 * @throws nosuchalgorithmexception
	 * @throws invalidkeyexception
	 * @throws signatureexception
	 */
	public string sign(byte[] message) throws ioexception, nosuchalgorithmexception, invalidkeyexception, signatureexception {
		// 加载商户私钥(privatekey:私钥字符串)
		privatekey merchantprivatekey = wechatpay.getprivatekey();
		signature sign = signature.getinstance("sha256withrsa");
		sign.initsign(merchantprivatekey);
		sign.update(message);
		return base64.getencoder().encodetostring(sign.sign());
	}

3.回调方法

public map callback(httpservletrequest request, httpservletresponse response)
			throws ioexception, generalsecurityexception {
		map<string, string> result = new hashmap<string, string>();
		// 响应接口
		result.put("code", "fail");
		/** 从请求头获取验签字段 */
		// 时间戳
		string timestamp = request.getheader("wechatpay-timestamp");
		string nonce = request.getheader("wechatpay-nonce");// 字符数按
		string signature = request.getheader("wechatpay-signature");
		string serial = request.getheader("wechatpay-serial");
		system.out.println("开始读取请求头的信息");
		// 请求头
		system.out.println("wechatpay-timestamp="  timestamp);
		system.out.println("wechatpay-nonce="  nonce);
		system.out.println("wechatpay-signature="  signature);
		system.out.println("wechatpay-serial="  serial);
		// 加载商户私钥(privatekey:私钥字符串)
		privatekey merchantprivatekey = pemutil
				.loadprivatekey(new bytearrayinputstream(privatekey.getbytes("utf-8")));
		// 加载平台证书(mchid:商户号,mchserialno:商户证书序列号,apiv3key:v3密钥)
		autoupdatecertificatesverifier verifier = new autoupdatecertificatesverifier(
				new wechatpay2credentials(mchid,
				new privatekeysigner(mchserialno, merchantprivatekey)),
				apiv3key.getbytes("utf-8"));
				// 读取请求体的信息
		system.out.println("开始读取请求体的信息");
		servletinputstream inputstream = request.getinputstream();
		stringbuffer stringbuffer = new stringbuffer();
		bufferedreader bufferedreader = new bufferedreader(new inputstreamreader(inputstream));
		string s;
		// 读取回调请求体
		while ((s = bufferedreader.readline()) != null) {
			stringbuffer.append(s);
		}
		string s1 = stringbuffer.tostring();
		system.out.println("请求体"  s1);
		map<string, string> requestmap = (map) json.parse(s1);
		// 开始按照验签进行拼接
		string id = requestmap.get("id");
		system.out.println("id="  id);
		string resource = string.valueof(requestmap.get("resource"));
		system.out.println("resource="  resource);
		map<string, string> requestmap2 = (map) json.parse(resource);
		string associated_data = requestmap2.get("associated_data");
		string nonce = requestmap2.get("nonce");
		string ciphertext = requestmap2.get("ciphertext");// 数据密文
		// 按照文档要求拼接验签串
		string verifysignature = timestamp  "\n"  nonce  "\n"  s1  "\n";
		system.out.println("拼接后的验签串="  verifysignature);
		// 使用官方验签工具进行验签
		boolean verify = verifier.verify(serial, verifysignature.getbytes(), signature);
		system.out.println("官方工具验签="  verify);
		// 判断验签的结果
		system.out.println("=======判断验签结果=======");
		if (verify == false) {
			result.put("message", "sign error");
			return result;
		}
		system.out.println("验签成功后,开始进行解密");
		// 解密,如果这里报错,就一定是apiv3密钥错误
		aesutil aesutil = new aesutil(apiv3key.getbytes("utf-8"));
		string aes = aesutil.decrypttostring(associated_data.getbytes(), nonce.getbytes(), ciphertext);
		system.out.println("解密后="  aes);
		map<string, string> callbackdata = getcallbackdata(aes);
		string tradestate = callbackdata.get("trade_state");
		if ("success".equals(tradestate)) {
			result.put("code", "success");
			result.put("message", "成功");
		} else {
			result.put("message", "trade_state error");
		}
		return result;	
}
public static map<string,string> getcallbackdata(string body){
		map<string,string> resmap=new hashmap<>();
		map<string,object> strtomap = (map) json.parse(body);
		resmap.put("out_trade_no",strtomap.get("out_trade_no").tostring());
		resmap.put("transaction_id",strtomap.get("transaction_id").tostring());
		resmap.put("trade_state",strtomap.get("trade_state").tostring());
		map<string,object> payermap = (map) json.parse(strtomap.get("payer").tostring());
		map<string,object> amountmap = (map) json.parse(strtomap.get("amount").tostring());
		resmap.put("openid",payermap.get("openid").tostring());
		resmap.put("total",amountmap.get("total").tostring());
		resmap.put("payer_total",amountmap.get("payer_total").tostring());
		return resmap;
}

4.查询订单

/**
	 * 查询订单 
	 * @param outtradeno 商户订单号(本地平台的订单号)
	 * @return
	 * @throws urisyntaxexception
	 * @throws ioexception
	 * 
	 */
	public static string findorder(string outtradeno) throws urisyntaxexception, ioexception {
		string url = "https://api.mch.weixin.qq/v3/pay/transactions/out-trade-no/"  outtradeno  "?mchid="  mchid;
		uribuilder uribuilder = new uribuilder(url);
		httpget httpget = new httpget(uribuilder.build());
		httpget.addheader("accept", "application/json");
		closeablehttpresponse response = httpclient.execute(httpget);
		string bodyasstring = entityutils.tostring(response.getentity());
		return bodyasstring;
	}

5.退款与退款通知
退款是前端用户退款时请求的方法,退款通知是微信平台收到退款请求的回调

    /**
	 * 退款(api)
	 */
	public map refund(string outtradeno){
		map<string, object> result = new hashmap<string, object>();
		string out_refund_no = "tb"  system.currenttimemillis();// 平台商品号码
		shachargerecord recode = shachargerecordservice.selectshachargerecordbyouttradeno(outtradeno);
		long price = recode.getrealtotalprice().longvalueexact();
		try {
			jsonobject order = new jsonobject();
			order.put("out_trade_no", outtradeno);//商户订单号
			order.put("out_refund_no", out_refund_no);//商户退款单号
//			order.put("reason", reason);//退款原因
			order.put("notify_url", refundnotifyurl);//退款通知
			jsonobject amount = new jsonobject();
			amount.put("refund", price * 100);//退款金额 price * 100
			amount.put("currency", "cny");
			amount.put("total", price * 100);//原订单金额
			order.put("amount", amount);
			// 加载商户私钥(privatekey:私钥字符串)
		privatekey merchantprivatekey = pemutil
				.loadprivatekey(new bytearrayinputstream(wechatpay.privatekey.getbytes("utf-8")));
				// 加载平台证书(mchid:商户号,mchserialno:商户证书序列号,apiv3key:v3密钥)
		autoupdatecertificatesverifier verifier = new autoupdatecertificatesverifier(
					new wechatpay2credentials(mchid,
							new privatekeysigner(mchserialno, merchantprivatekey)),
					apiv3key.getbytes("utf-8"));
		// 初始化httpclient
		closeablehttpclient httpclient = wechatpayhttpclientbuilder.create().withmerchant(mchid, mchserialno, merchantprivatekey)
					.withvalidator(new wechatpay2validator(verifier)).build();
		httppost httppost = new httppost("https://api.mch.weixin.qq/v3/refund/domestic/refunds");
		httppost.addheader("accept", "application/json");
		httppost.addheader("content-type","application/json; charset=utf-8");
		httppost.setentity(new stringentity(order.tojsonstring(), "utf-8"));
		httpresponse response = httpclient.execute(httppost);
		//获取返回数据
		string bodyasstring = entityutils.tostring(response.getentity());
		jsonobject bodyasjson = jsonobject.parseobject(bodyasstring);
		logger.info(bodyasjson.tojsonstring());
		final string status = bodyasjson.getstring("status");
		result.put("status", status);
		if("success".equals(status)){
				logger.info("退款成功");
				result.put("message", "退款成功");
			}else if("closed".equals(status)){
				logger.info("退款关闭");
				result.put("message", "退款关闭");
			}else if("processing".equals(status)){
				logger.info("退款处理中");
				result.put("message", "退款处理中");
				result.put("code", 200);
			}else if("abnormal".equals(status)){
				result.put("message", "退款异常");
				logger.info("退款异常");
			}
		} catch (exception e) {
			logger.info(e.tostring());
			e.printstacktrace();
		}
		return result;
	}	
    /**
	 * 退款通知(api)
	 */
	public map refundnotice(httpservletrequest request, httpservletresponse response) {
		map<string, string> result = new hashmap<string, string>();
		result.put("code", "fail");
		try {
			string reqparams = wechatpay.read(request.getinputstream());
			logger.info("-------支付结果:"  reqparams);
			jsonobject json = jsonobject.parseobject(reqparams);
			string ciphertext = json.getjsonobject("resource").getstring("ciphertext");
			final string associated_data = json.getjsonobject("resource").getstring("associated_data");
			final string nonce = json.getjsonobject("resource").getstring("nonce");
			aesutil aesutil = new aesutil(apiv3key.getbytes("utf-8"));
			//解密数据
			ciphertext = aesutil.decrypttostring(associated_data.getbytes(), nonce.getbytes(), ciphertext);
			map<string, object> resmap = new hashmap<>();
			map<string, object> strtomap = (map) json.parse(ciphertext);
			string outtradeno = (string) strtomap.get("out_trade_no");
			final string eventtype = json.getstring("event_type");
			if ("refund.success".equals(eventtype)) {
				result.put("code", "success");
				result.put("message", "退款成功");
			} else if ("refund.abnormal".equals(eventtype)) {
				result.put("message", "退款异常");
			} else if ("refund.closed".equals(eventtype)) {
				result.put("message", "退款关闭");
			}
		} catch (exception e) {
			e.printstacktrace();
		}
		return result;
	}
	/**
	 * 查询单笔退款订单
	 * 
	 * @param outtradeno
	 * @return
	 * @throws ioexception
	 * @throws urisyntaxexception
	 * 
	 * 微信开发文档 https://pay.weixin.qq/wiki/doc/apiv3/apis/chapter3_1_10.shtml
	 */
	 public ajaxresult getrefundsorderbyouttradeno(string outtradeno) throws ioexception, urisyntaxexception {
		string order = getrefundsorderbyouttradeno(outtradeno);
		map<string,object> resmap=new hashmap<>();
		map<string,object> strtomap = (map) json.parse(order);
		resmap.put("status", strtomap.get("status"));
		if ("success".equals(strtomap.get("status"))) {
		}
		return ajaxresult.success(resmap);
	}	
	
	/**
	 * 查询订单 
	 * @param outtradeno 商户订单号(力云平台的订单号)
	 * @return
	 * @throws urisyntaxexception
	 * @throws ioexception
	 * 
	 */
	public static string getrefundsorderbyouttradeno(string outtradeno) throws urisyntaxexception, ioexception {
		string url = "https://api.mch.weixin.qq/v3/refund/domestic/refunds/"  outtradeno ;
		uribuilder uribuilder = new uribuilder(url);
		httpget httpget = new httpget(uribuilder.build());
		httpget.addheader("accept", "application/json");
		closeablehttpresponse response = httpclient.execute(httpget);
		string bodyasstring = entityutils.tostring(response.getentity());
		return bodyasstring;
	}
	
	public static string read(inputstream is){
		try {
			bytearrayoutputstream baos = new bytearrayoutputstream();
			int len = 0;
			byte[] buffer = new byte[512];
			while((len = is.read(buffer)) != -1){
				baos.write(buffer, 0, len);
			}
			return new string(baos.tobytearray(), 0, baos.size(), "utf-8");
		}catch (exception e) {
			e.printstacktrace();
		}
		return "";
	}

本文标签: