已上传至github库 https://github.com/gaoruiqiang2017/weixinpay.git
/**
登录+支付 code
流程大概分为几步:
1)登录,获取code(一个code只能用一次)
2)通过code获取openid(通过请求服务器,由服务器请求微信获取并返回小程序)。微信登录+获取openid接口
3)小程序请求服务器进行预下单,上传商品详情、金额、openid。
4)服务器端接收请求,根据请求订单数据、生成第三方订单号,调用微信的统一下单接口,返回prepay_id。
5)服务器收到预下单信息后,签名并组装支付数据,返回给小程序。
6)小程序前端发起支付,并支付完成
7)服务器收到回调。
*/
wx.login({
success(res) {
if (res.code) {
// 发起网络请求
wx.request({
url: 'https://test.com/onLogin',
data: {
code: res.code
}
})
} else {
console.log('登录失败!' + res.errMsg)
}
}
})
getOpenId:function(that, code){
console.log(code);
let operFlag = "getOpenid";
console.log(operFlag);
wx.request({
url: 'https://xxx/weixinAppletpay/getOpenid',
data: {
code:code,
operFlag:operFlag
},
header: { 'content-type': 'application/json' },
success: function (res) {
console.log(res);
var openid = res.data.openid;
console.log(openid);
that.paypay(that, openid); //预下单并支付
},
fail: function (res) {
console.log(res.data.errmsg);
console.log(res.data.errcode);
},
complete:function(res){
}
})
},
**还需要下订单,获取订单id,这里省略**
@RestController
@RequestMapping("/weixinAppletpay")
public class WeixinAppletPay {
@Value("${wxAppletAppId}")
private String wxAppletAppId; //小程序账号id
@Value("${mchid}")
private String mchId; //商户号
@Value("${weixinKey}")
private String weixinKey; //密匙
@Value("${wxAppletAppSercet}")
private String wxAppletAppSercet; // 小程序的appsecret
@Value("https://api.weixin.qq.com/sns/jscode2session")
private String wxCode2SeesionUrl; // 小程序的appsecret
@Value("https://api.mch.weixin.qq.com/pay/unifiedorder")
private String unifiedorderUrl; //统一下单接口
@Value("https://127.0.0.1:8080/weixinAppletpay/AppletPay")
private String redirectUrl; //授权后重定向的回调链接地址, 请使用 urlEncode 对链接进行处理
/**
* //第一步:登录,获取code(一个code只能用一次),通过code获取openid
* 获取code参考:https://developers.weixin.qq.com/miniprogram/dev/api/wx.login.html
*
* @param code
* @param httpServletRequest
* @param httpServletResponse
*/
public String getOpenid(HttpServletRequest httpServletRequest, HttpServletResponse
httpServletResponse, String code, Writer writer) {
String openid = "";
try {
//封装参数
HashMap data = new HashMap<>();
data.put("appid", wxAppletAppId);
data.put("secret", wxAppletAppSercet);
data.put("js_code", code);
data.put("grant_type", "authorization_code");
//将类型为map的参数转换为xml
String requestXml = WXPayUtil.mapToXml(data);
//发送参数,调用微信统一下单接口,返回xml
String responseXml = HttpUtil.doPost(wxCode2SeesionUrl, requestXml);
Map map = WXPayUtil.xmlToMap(responseXml);
if (null != map.get("errmsg")) {
return "操作失败";
} else {
//成功可以先把openid缓存起来,可以设置自己的小程序登录有效时间,也可以直接下订单
String session_key = map.get("session_key");
openid = map.get("openid");
String unionid = map.get("unionid");
}
} catch (Exception e) {
return "异常";
}
return openid;
}
/**
* 支付
* @param httpServletRequest
* @param httpServletResponse
* @param openid
* @param orderId 订单id(可以在这个接口里下订单,不用另写接口,这里是另写的)
* @param writer
* @param model
* @return
*/
public String appletPay(HttpServletRequest httpServletRequest, HttpServletResponse
httpServletResponse, String openid, String orderId, Writer writer, Model
model) {
String mapStr = "";
try {
**通过订单id可以拿到订单信息**
//获得openid调用微信统一下单接口
HashMap dataMap = new HashMap<>();
dataMap.put("appid", wxAppletAppId); //公众账号ID
dataMap.put("mch_id", mchId); //商户号
dataMap.put("nonce_str", WXPayUtil.generateNonceStr()); //随机字符串,长度要求在32位以内。
dataMap.put("body", "手机"); //商品描述,通过订单id获得
dataMap.put("out_trade_no", orderId); //商品订单号,用户下订单后台生成
dataMap.put("total_fee", "1"); //商品金,通过订单id获得
dataMap.put("spbill_create_ip", HttpUtil.getIpAddress(httpServletRequest)); //客户端ip
//通知地址(需要是外网可以访问的)
dataMap.put("notify_url", "https://127.0.0.1:8080/weixinAppletpay/notifyUrl");
dataMap.put("trade_type", "JSAPI"); //交易类型
dataMap.put("openid", openid); //商户号
//生成签名
String signature = WXPayUtil.generateSignature(dataMap, weixinKey);
dataMap.put("sign", signature);//签名
//将类型为map的参数转换为xml
String requestXml = WXPayUtil.mapToXml(dataMap);
//发送参数,调用微信统一下单接口,返回xml
String responseXml = HttpUtil.doPost(unifiedorderUrl, requestXml);
Map responseMap = WXPayUtil.xmlToMap(responseXml);
if ("FAIL".equals(responseMap.get("return_code"))) {
mapStr = responseMap.get("return_msg");
writer.write(mapStr);
return "";
}
if ("FAIL".equals(responseMap.get("result_code"))) {
mapStr = responseMap.get("err_code_des");
writer.write(mapStr);
return "";
}
if ("".equals(responseMap.get("prepay_id")) || responseMap.get("prepay_id") ==
null) {
writer.write("prepay_id 为空");
return "";
}
//成功之后,提取prepay_id,重点就是这个
HashMap params = new HashMap<>();
params.put("appId", wxAppletAppId);
params.put("nonceStr", WXPayUtil.generateNonceStr());
params.put("package", responseMap.get("prepay_id"));
params.put("signType", "MD5");
params.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
//重新签名
String paySign = WXPayUtil.generateSignature(params, weixinKey);
params.put("paySign", paySign);
//传给前端页面
//在微信浏览器里面打开H5网页中执行JS调起支付。接口输入输出数据格式为JSON。
mapStr = params.toString();
//前端接受参数调用wx.requestPayment(OBJECT)发起微信支付
//返回requestPayment:ok,支付成功
} catch (Exception e) {
}
return mapStr;
}
/**
* 异步回调(必须有,得发布到外网)
*
* @param unifiedorderUrl
* @param requestXml
* @return
*/
@RequestMapping("/notifyUrl")
public String notifyUrl(String unifiedorderUrl, String requestXml) {
System.out.print("进入支付h5回调=====================");
//判断接受到的result_code是不是SUCCESS,如果是,则返回成功,具体业务具体分析,修改订单状态
// 通知微信.异步确认成功.必写.不然会一直通知后台.
String resXml = "" + " " +
" " + " ";
return resXml; //或者 return "success";
}
}
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.1.1.RELEASE
com.weixinpay
demo
0.0.1-SNAPSHOT
demo
Demo project for Spring Boot
1.8
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
com.github.wxpay
wxpay-sdk
0.0.3
org.apache.httpcomponents
httpclient
4.5.5
com.alibaba
fastjson
1.2.47
com.google.zxing
core
3.3.0
com.google.zxing
javase
3.0.0
commons-io
commons-io
2.6
org.springframework.boot
spring-boot-maven-plugin
demo
src/main/resources
true
**/*.properties
src/main/resources
false
**
/**
* @Description
* @Date:03
*/
public class HttpUtil {
public static String doPost(String url, String requestXml) {
CloseableHttpClient httpClient = null;
CloseableHttpResponse httpResponse = null;
//创建httpClient连接对象
httpClient = HttpClients.createDefault();
//创建post请求连接对象
HttpPost httpPost = new HttpPost(url);
//创建连接请求对象,并设置连接参数
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(15000) //连接服务区主机超时时间
.setConnectionRequestTimeout(60000) //连接请求超时时间
.setSocketTimeout(60000).build(); //设置读取响应数据超时时间
//为httppost请求设置参数
httpPost.setConfig(requestConfig);
//将上传参数放到entity属性中
httpPost.setEntity(new StringEntity(requestXml, "UTF-8"));
//添加头信息
httpPost.addHeader("Content-type", "text/xml");
String result = "";
try {
//发送请求
httpResponse = httpClient.execute(httpPost);
//从相应对象中获取返回内容
HttpEntity entity = httpResponse.getEntity();
result = EntityUtils.toString(entity, "UTF-8");
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
/**
* 获取IP地址
*
* @param request
* @return
*/
public static String getIpAddress(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
}
appid=wx12822223?22sss
mchId=149232323312333sss
weixinKey=34234234er2werwerwer
unifiedorderUrl=https://api.mch.weixin.qq.com/pay/unifiedorder