Java 微信公众号支付(JSAPI)
发表时间:2020-10-19
发布人:葵宇科技
浏览次数:41
1:微信公众平台:https://mp.weixin.qq.com/ 企业邮箱账号注册申请;
2:找到接口权限,设置网页授权;
网页授权域名:
这里重点注意 设置域名:需要下载这个txt文件,微信会在设置完域名之后调用域名下的文件访问内容。
注:这里提供一个小得解决方案:
内网穿透设置免费域名: natapp.exe;百度教程。设置一个当前开发项目端口得免费域名。
下载微信得txt文件拿到里面得内容,提供一个Get接口。
@RestController
@RequestMapping("/MP_verify_RiguI1gGI9QyALmH.txt")
public class WxTxtController {
@GetMapping()
public String txt() {
return "RiguI1gGI9QyALmH";
}
这样就可以保证网页授权域名通过微信验证。
3.微信商户平台申请开通支付:https://pay.weixin.qq.com/
通过之后,需要得配置:账户中心-API证书;产品中心-开发配置-公众号支付授权目录 可以是:"http:natapp.exe生成得免费域名/index/",
参数介绍:
APPID:公共号ID;
SECRET:公众号secret;
MCH_ID:支付商户ID;
PATER_NER_KEY:支付密钥;就是API安全这个里面那个32位得;
接下来进入贴代码:
获取code:CALL_BACK_URL:就是生成得免费域名;
/**
* 微信公众平台授权登录
*
* @param response
* @return
* @throws IOException
*/
@PostMapping("/publicLogin")
@ResponseBody
public AjaxResult login(HttpServletResponse response) throws IOException {
//回调的url
String redirect_uri = URLEncoder.encode(CALL_BACK_URL + "/api/wxBusiness/publicCallBack", "UTF-8");
String url = "https://open.weixin.qq.com/connect/oauth2/authorize?" +
"appid=APPID" +
"&redirect_uri=REDIRECT_URI" +
"&response_type=code" +
"&scope=SCOPE" +
"&state=123#wechat_redirect";
return AjaxResult.success(url.replace("APPID", APPID).replace("REDIRECT_URI", redirect_uri).replace("SCOPE", "snsapi_userinfo"));
}
/**
* 微信公众平台回调
*
* @param modelMap
* @param req
* @param resp
* @return
* @throws Exception
*/
@RequestMapping(value = "/publicCallBack", method = RequestMethod.GET)
@ResponseBody
public AjaxResult callBack(ModelMap modelMap, HttpServletRequest req, HttpServletResponse resp) throws Exception {
String code = req.getParameter("code");
return AjaxResult.success(code);
}
其实这些代码前端写 也是没问题得。
拿到code:调用微信统一下单接口:
JSAPI:官方文档 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1
下载Java包 然后把那些wxPay得文件引入项目;
/**
* @param request
* @param code
* @return Map
* @Description 微信浏览器内微信支付/公众号支付(JSAPI)
*/
@RequestMapping(value = "/orders", method = RequestMethod.GET)
@ResponseBody
public AjaxResult orders(HttpServletRequest request, String code) {
try {
//订单号
String orderNumber = DateUtils.dateTimeNow(DateUtils.YYYYMMDDHHMMSS + "" + (int) (Math.random() * 10000));
//页面获取openId接口
String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + APPID
+ "&secret=" + SECRET
+ "&code=" + code
+ "&grant_type=authorization_code";
JSONObject jsonObject = HttpUtils.doGetJson(url);
/*
{ "access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE"
}
*/
String openid = jsonObject.getString("openid");
LOGGER.info("openId:" + openid);
//拼接统一下单地址参数
Map<String, String> paraMap = new HashMap<String, String>();
//获取请求ip地址
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.getRemoteAddr();
}
if (ip.indexOf(",") != -1) {
String[] ips = ip.split(",");
ip = ips[0].trim();
}
String nonceStr = WXPayUtil.generateNonceStr();
LOGGER.info("nonce_str:"+nonceStr);
paraMap.put("appid", APPID);
paraMap.put("body", ORDER_BODY);
paraMap.put("mch_id", MCH_ID);
paraMap.put("nonce_str", nonceStr);
paraMap.put("openid", openid);
paraMap.put("out_trade_no", orderNumber);//订单号
paraMap.put("spbill_create_ip", ip);
paraMap.put("total_fee", "1");
paraMap.put("trade_type", "JSAPI");
paraMap.put("notify_url", " http://dtpbuf.natappfree.cc/api/wxBusiness/callback");// 此路径是微信服务器调用支付结果通知路径随意写
String sign = WXPayUtil.generateSignature(paraMap, PATER_NER_KEY);
LOGGER.info("微信sign:" + sign);/*
LOGGER.info("验签:"+WXPayUtil.isSignatureValid(sign,PATER_NER_KEY));*/
paraMap.put("sign", sign);
String xml = WXPayUtil.mapToXml(paraMap);//将所有参数(map)转xml格式
// 统一下单 https://api.mch.weixin.qq.com/pay/unifiedorder
String unifiedorder_url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
String xmlStr = HttpUtils.sendPost(unifiedorder_url, xml);//发送post请求"统一下单接口"返回预支付id:prepay_id
LOGGER.info("xml:" + xmlStr);
//以下内容是返回前端页面的json数据
String prepay_id = "";//预支付id
String nonce_str="";
if (xmlStr.indexOf("SUCCESS") != -1) {
Map<String, String> map = WXPayUtil.xmlToMap(xmlStr);
prepay_id = (String) map.get("prepay_id");
nonce_str=(String) map.get("nonce_str");
}
Map<String, String> payMap = new HashMap<String, String>();
payMap.put("appId", APPID);
payMap.put("timeStamp", WXPayUtil.getCurrentTimestamp() + "");
payMap.put("nonceStr", nonceStr);
payMap.put("package", "prepay_id=" + prepay_id);
payMap.put("signType", "MD5");
String paySign = WXPayUtil.generateSignature(payMap, PATER_NER_KEY);
payMap.put("paySign", paySign);
/**
* 订单初始化
*/
SysOrderInfo orderInfo = new SysOrderInfo();
orderInfo.setOrderNumber(orderNumber);
orderInfo.setOrderBody(OrderConstants.ORDER_CLASS_BODY);
orderInfo.setOpenId(openid);
orderInfo.setOrderStatus(OrderConstants.ORDER_STATUS_NOT);
orderInfo.setOrderType(OrderConstants.ORDER_TYPE_LEARN);
orderInfo.setOrderTradeType(OrderConstants.ORDER_TRADE_JS_API);
orderInfo.setOrderPrice(BigDecimal.valueOf(OrderConstants.ORDER_PRICE));
orderInfoService.insertSysOrderInfo(orderInfo);
orderWxVo orderWxVo = new orderWxVo();
orderWxVo.setAppId(APPID);
orderWxVo.setTimeStamp(WXPayUtil.getCurrentTimestamp() + "");
orderWxVo.setNonceStr(nonceStr);
orderWxVo.setSignType("MD5");
orderWxVo.setPackages("prepay_id=" + prepay_id);
orderWxVo.setPaySign(paySign);
return AjaxResult.success(orderWxVo);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
直接拿着用就可以。这里几个小坑:①:nonceStr 这个参数 统一下单 签名 和返回前端得参数二次签名 得是同一个字符串。
②:code只能用一次;③:SignType必须是MD5;修改微信提供得wxPay里得
public WXPay(final WXPayConfig config, final String notifyUrl, final boolean autoReport, final boolean useSandbox) throws Exception {
this.config = config;
this.notifyUrl = notifyUrl;
this.autoReport = autoReport;
this.useSandbox = useSandbox;
if (useSandbox) {
this.signType = SignType.MD5; // 沙箱环境
}
else {
this.signType = SignType.MD5;
}
this.wxPayRequest = new WXPayRequest(config);
}
重点:else {
this.signType = SignType.MD5;
}
回调:
/**
* 支付回调
*
* @param request
* @param response
* @return
*/
@RequestMapping("callback")
public String callBack(HttpServletRequest request, HttpServletResponse response) {
InputStream is = null;
try {
is = request.getInputStream();//获取请求的流信息(这里是微信发的xml格式所有只能使用流来读)
String xml = WXPayUtil.inputStream2String(is, "UTF-8");
Map<String, String> notifyMap = WXPayUtil.xmlToMap(xml);//将微信发的xml转map
if (notifyMap.get("return_code").equals("SUCCESS")) {
if (notifyMap.get("result_code").equals("SUCCESS")) {
String orderNumber = notifyMap.get("out_trade_no");//商户订单号
LOGGER.info("回调订单号:"+orderNumber);
/**
* 自己的业务处理
*/
}
}
//告诉微信服务器收到信息了,不要在调用回调action了========这里很重要回复微信服务器信息用流发送一个xml即可
response.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>");
is.close();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
js得代码 官网里有:
这个只有在微信内置浏览器能识别这个方法。WeixinJSBridge..invoke。