java如何实现微信jsApi支付,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。
标注:1、必须在微信内置浏览器进行支付;2、open id必须获取;3、获取code必须请求后台服务器,将code获取到返回前端,再请求获取openid,将openid存在自己服务器的session中
一、账户准备
1、在微信公众平台开通服务号并付费300元认证(只有企业才能开通)获取appid,在微信支付商户平台注册超级管理员并付费300认证,获取mch_id(商户id)。
2、在微信公众平台获取 appid,appsecret。在商户平台获取mch_id,api安全中获取API密钥(paternerKey)
二、平台配置
1、商户平台:产品中心开发配置,属于支付页面
2、公众平台:账户详情功能设置,配置网页授权域名,(将txt文件放在一级域名以及目录中,可通过域名/txt(文件全称)访问,测试是否可以获取txt内容。如果不行,则进行nginx配置域名访问目录)
3、公众平台:开发,基本设置,配置服务器地址(需要写接口并返回echostr,验证服务器),令牌随便写,消息密钥(随机生成),加密模式:兼容模式。
三、开发(下载javasdk。将微信中的工具类导入https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1)
1、支付前获取基本参数
/** * 微信中请求打开页面 */ @RequestMapping(value = "/toJob") public String toJob(HttpServletResponse response){ String appId = WxConstants.APPID; String tologin =redirectURL; return "redirect:https://open.weixin.qq.com/connect/oauth3/authorize?appid="+appId+"&redirect_uri="+tologin+"&response_type=code&scope=snsapi_base#wechat_redirect"; } /** * 微信请求打开页面重定向到该接口,获取code * 然后重定向到自己页面 */ @RequestMapping(value = "/tologin") public String tologin(String code ,HttpServletResponse response){ return "redirect:"+loginUrl+code; } /** * 获取open id */ @RequestMapping("/getOpenId") @ResponseBody public String getOpenId( @RequestParam("code") String code,HttpServletRequest request){ logger.info("code code:" + code); Map<String, String> result = new HashMap<>(); //页面获取openId接口 String getopenid_url = "https://api.weixin.qq.com/sns/oauth3/access_token"; Map<String, String> param = new HashMap<>(); param.put("appid", WxConstants.APPID); param.put("secret", WxConstants.SECRET); param.put("code", code); param.put("grant_type", "authorization_code"); //向微信服务器发送get请求获取openIdStr String openIdStr = HttpClientUtil.doGet(getopenid_url, param); JSONObject jsonObject = JSON.parseObject(openIdStr); logger.info("opendID JSON:" + openIdStr); String openid = jsonObject.getString("openid"); //将open id存入session。 //如果直接重定向到该接口,openid存不到session中,只会存在腾讯的session中 //微信中打开页面只能请求后台接口,后台获取到code拼接到前台页面后面 //前台获取到code,然后请求获取open id的接口,可以将open id存到我们自己服务器中 request.getSession().setAttribute("openid", openid); //返回登录页 return openid; } /** * 微信测试接口 * @param request * @return */ @RequestMapping("/Token") @ResponseBody public String Token(HttpServletRequest request){ logger.info(JSON.toJSONString(request.getParameterMap())); return request.getParameter("echostr"); }
2、支付、回调
/** * 简历微信支付 * @param request * @param isUpdate 是否是认证订单 */ @RequestMapping(value = "/wxPayJob") @ResponseBody public Map<String,String> wxpay(HttpServletRequest request, @RequestParam("isUpdate") Integer isUpdate, @RequestParam("jobUserId") Long jobUserId, @RequestParam("totalAmount") String totalAmount) { String openId = (String) request.getSession().getAttribute("openid"); logger.info("opendID pay:" + openId); //获取openId String ip = WxUtils.getIpAddress(request); //将元转化为分 String totalFee = AmountUtils.changeY2F(totalAmount); Map<String, String> result = wxService.orderPayment(openId, ip, totalFee, jobUserId, isUpdate); return result; } /** * 微信支付回调 * @param request * @param response * @return */ @RequestMapping(value = "/wxPayJobNotify") @ResponseBody public String wxPayJobNotify(HttpServletRequest request, HttpServletResponse response) { InputStream is = null; try { is = request.getInputStream();//获取请求的流信息(这里是微信发的xml格式所有只能使用流来读) String xml = IOUtils.toString(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 orderNum = notifyMap.get("out_trade_no");//商户订单号 String amountpaid = notifyMap.get("total_fee");//实际支付的订单金额:单位 分 String amount = AmountUtils.changeF2Y(amountpaid); //String openid = notifyMap.get("openid"); //如果有需要可以获取 //String trade_type = notifyMap.get("trade_type"); //修改认证状态,订单状态 jobOrderDtoService.updateState(orderNum); } } //告诉微信服务器收到信息了,不要在调用回调action了========这里很重要回复微信服务器信息用流发送一个xml即可 response.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>"); is.close(); } catch (Exception e) { e.printStackTrace(); } return null; }
3、支付统一下单主体
//微信支付----异步回调(接口:payForOrder) @Value(value = "${WxConfig.wxJObNotifyUrl}") private String wxJObNotifyUrl; /** * 调用微信支付 */ @Override public Map<String, String> orderPayment(String openId, String ip, String totalAmount, Long jobUserId, Integer isUpdate) { Map<String, String> payMap = new HashMap<String, String>(); try{ String OrderNum = OrderNumUtil.outtradeno("JOB"); String body = "认证"; Map<String, String> mapBody = setSortedMap(openId,OrderNum,body,totalAmount,ip); String xml = WXPayUtil.mapToXml(mapBody);//将所有参数(map)转xml格式 // 统一下单 String unifiedorder_url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; //发送post请求"统一下单接口"返回预支付id:prepay_id Map<String, String> xmlMap = new HashMap<>(); xmlMap.put("xml",xml); String xmlStr = HttpClientUtil.doPostJson(unifiedorder_url, xml); //返回前端页面的json数据 payMap = resultMap(xmlStr); //插入简历订单 } catch (Exception e) { e.printStackTrace(); } return payMap; } /** * 下单主体信息 */ public Map<String, String> setSortedMap(String openId,String OrderNum,String body,String totalFee,String ip) throws Exception{ //拼接统一下单地址参数 Map<String, String> paraMap = new HashMap<String, String>(); paraMap.put("appid", WxConstants.APPID); paraMap.put("body", body); paraMap.put("mch_id", WxConstants.MCHID); paraMap.put("nonce_str", WXPayUtil.generateNonceStr());//生成uuID paraMap.put("openid", openId); paraMap.put("out_trade_no", OrderNum);//订单号 paraMap.put("spbill_create_ip", ip); paraMap.put("total_fee",totalFee);//金额 单位 分 paraMap.put("trade_type", WxConstants.WX_TRADE_JSAPI); paraMap.put("notify_url",wxJObNotifyUrl);// 此路径是微信服务器调用支付结果通知路径随意写 String sign = WXPayUtil.generateSignature(paraMap, WxConstants.KEY); paraMap.put("sign", sign); return paraMap; } /** * 返回前端页面的json数据 */ public Map<String, String> resultMap(String xmlStr)throws Exception{ Map<String, String> json = WXPayUtil.xmlToMap(xmlStr); //JSONObject json = JSONObject.parseObject(xmlStr);//转成Json格式 LOGGER.info("prepay_id JSON:" + json); //获取prepay_id String prepay_id = json.get("prepay_id");//预支付id if (xmlStr.indexOf("SUCCESS") != -1) { Map<String, String> map = WXPayUtil.xmlToMap(xmlStr); prepay_id = (String) map.get("prepay_id"); } Map<String, String> payMap = new HashMap<String, String>(); payMap.put("appId", WxConstants.APPID); payMap.put("timeStamp", WXPayUtil.getCurrentTimestamp()+""); payMap.put("nonceStr", WXPayUtil.generateNonceStr()); payMap.put("signType", "MD5"); payMap.put("package", "prepay_id=" + prepay_id); String paySign = WXPayUtil.generateSignature(payMap, WxConstants.KEY); payMap.put("paySign", paySign); return payMap; }
4、工具类:
元转分,分转元
public class AmountUtils { /**金额为分的格式 */ public static final String CURRENCY_FEN_REGEX = "\\-?[0-9]+"; /** * 将分为单位的转换为元并返回金额格式的字符串 (除100) * * @param amount * @return * @throws Exception */ public static String changeF2Y(Long amount) throws Exception{ if(!amount.toString().matches(CURRENCY_FEN_REGEX)) { throw new Exception("金额格式有误"); } int flag = 0; String amString = amount.toString(); if(amString.charAt(0)=='-'){ flag = 1; amString = amString.substring(1); } StringBuffer result = new StringBuffer(); if(amString.length()==1){ result.append("0.0").append(amString); }else if(amString.length() == 2){ result.append("0.").append(amString); }else{ String intString = amString.substring(0,amString.length()-2); for(int i=1; i<=intString.length();i++){ if( (i-1)%3 == 0 && i !=1){ result.append(","); } result.append(intString.substring(intString.length()-i,intString.length()-i+1)); } result.reverse().append(".").append(amString.substring(amString.length()-2)); } if(flag == 1){ return "-"+result.toString(); }else{ return result.toString(); } } /** * 将分为单位的转换为元 (除100) * * @param amount * @return * @throws Exception */ public static String changeF2Y(String amount) throws Exception{ if(!amount.matches(CURRENCY_FEN_REGEX)) { throw new Exception("金额格式有误"); } return BigDecimal.valueOf(Long.valueOf(amount)).divide(new BigDecimal(100)).toString(); } /** * 将元为单位的转换为分 (乘100) * * @param amount * @return */ public static String changeY2F(Long amount){ return BigDecimal.valueOf(amount).multiply(new BigDecimal(100)).toString(); } /** * 将元为单位的转换为分 替换小数点,支持以逗号区分的金额 * * @param amount * @return */ public static String changeY2F(String amount){ String currency = amount.replaceAll("\\$|\\¥|\\,", ""); //处理包含, ¥ 或者$的金额 int index = currency.indexOf("."); int length = currency.length(); Long amLong = 0l; if(index == -1){ amLong = Long.valueOf(currency+"00"); }else if(length - index >= 3){ amLong = Long.valueOf((currency.substring(0, index+3)).replace(".", "")); }else if(length - index == 2){ amLong = Long.valueOf((currency.substring(0, index+2)).replace(".", "")+0); }else{ amLong = Long.valueOf((currency.substring(0, index+1)).replace(".", "")+"00"); } return amLong.toString(); } public static void main(String[] args) { // try { // System.out.println("结果:"+changeF2Y("-000a00")); // } catch(Exception e){ // System.out.println("----------->>>"+e.getMessage()); //// return e.getErrorCode(); // } // System.out.println("结果:"+changeY2F("1.00000000001E10")); System.out.println(AmountUtils.changeY2F("1.33")); try { System.out.println(AmountUtils.changeF2Y("1322")); } catch (Exception e) { e.printStackTrace(); } // System.out.println(Long.parseLong(AmountUtils.changeY2F("1000000000000000"))); // System.out.println(Integer.parseInt(AmountUtils.changeY2F("10000000"))); // System.out.println(Integer.MIN_VALUE); // long a = 0; // System.out.println(a); } }
http doPost doGet 请求
import org.apache.http.NameValuePair; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; import java.io.IOException; import java.net.URI; import java.util.ArrayList; import java.util.List; import java.util.Map; public class HttpClientUtil { public static String doGet(String url, Map<String, String> param) { // 创建Httpclient对象 CloseableHttpClient httpclient = HttpClients.createDefault(); String resultString = ""; CloseableHttpResponse response = null; try { StringBuilder sb = new StringBuilder(url+"?"); for (String key : param.keySet()) { sb.append(key+"="+param.get(key)+"&"); } sb.deleteCharAt(sb.length()-1); URI uri = new URI(sb.toString()); // 创建http GET请求 HttpGet httpGet = new HttpGet(uri); // 执行请求 response = httpclient.execute(httpGet); // 判断返回状态是否为200 if (response.getStatusLine().getStatusCode() == 200) { resultString = EntityUtils.toString(response.getEntity(), "UTF-8"); } } catch (Exception e) { e.printStackTrace(); } finally { try { if (response != null) { response.close(); } httpclient.close(); } catch (IOException e) { e.printStackTrace(); } } return resultString; } public static String doGet(String url) { return doGet(url, null); } public static String doPost(String url, Map<String, String> param) { // 创建Httpclient对象 CloseableHttpClient httpClient = HttpClients.createDefault(); CloseableHttpResponse response = null; String resultString = ""; try { // 创建Http Post请求 HttpPost httpPost = new HttpPost(url); // 创建参数列表 if (param != null) { List<NameValuePair> paramList = new ArrayList<>(); for (String key : param.keySet()) { paramList.add(new BasicNameValuePair(key, param.get(key))); } // 模拟表单 UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList); httpPost.setEntity(entity); } // 执行http请求 response = httpClient.execute(httpPost); resultString = EntityUtils.toString(response.getEntity(), "utf-8"); } catch (Exception e) { e.printStackTrace(); } finally { try { response.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return resultString; } public static String doPost(String url) { return doPost(url, null); } public static String doPostJson(String url, String json) { // 创建Httpclient对象 CloseableHttpClient httpClient = HttpClients.createDefault(); CloseableHttpResponse response = null; String resultString = ""; try { // 创建Http Post请求 HttpPost httpPost = new HttpPost(url); // 创建请求内容 StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON); httpPost.setEntity(entity); // 执行http请求 response = httpClient.execute(httpPost); resultString = EntityUtils.toString(response.getEntity(), "utf-8"); } catch (Exception e) { e.printStackTrace(); } finally { try { response.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return resultString; } }
微信工具类
import com.alibaba.fastjson.JSON; import org.apache.commons.lang3.StringUtils; import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.Element; import javax.servlet.http.HttpServletRequest; import java.util.*; public class WxUtils { //请求xml组装 public static String getRequestXml(Map<String,String> parameters){ StringBuffer sb = new StringBuffer(); sb.append("<xml>"); Set es = parameters.entrySet(); Iterator it = es.iterator(); while(it.hasNext()) { Map.Entry<String,String> entry = (Map.Entry)it.next(); sb.append("<"+entry.getKey()+">"+entry.getValue()+"</"+entry.getKey()+">"); } sb.append("</xml>"); return sb.toString(); } /** * 随机字符串生成 */ public static String getRandomString(int length) { //length表示生成字符串的长度 String base = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; Random random = new Random(); StringBuffer sb = new StringBuffer(); for (int i = 0; i < length; i++) { int number = random.nextInt(base.length()); sb.append(base.charAt(number)); } return sb.toString(); } /** * 将xml格式的字符串转换成Map对象 * * @param xmlStr xml格式的字符串 * @return Map对象 * @throws Exception 异常 */ public static Map<String, String> xmlStrToMap(String xmlStr) throws Exception { if(StringUtils.isEmpty(xmlStr)) { return null; } Map<String, String> map = new HashMap<>(); //将xml格式的字符串转换成Document对象 Document doc = DocumentHelper.parseText(xmlStr); //获取根节点 Element root = doc.getRootElement(); //获取根节点下的所有元素 List children = root.elements(); //循环所有子元素 if(children != null && children.size() > 0) { for(int i = 0; i < children.size(); i++) { Element child = (Element)children.get(i); map.put(child.getName(), child.getTextTrim()); } } return map; } public static <T> T xmlStrToBean(String xmlStr, Class<T> clazz) throws InstantiationException, IllegalAccessException { T obj = clazz.newInstance(); try { // 将xml格式的数据转换成Map对象 Map<String, String> map = xmlStrToMap(xmlStr); //将map对象的数据转换成Bean对象 obj = JSON.parseObject(JSON.toJSONString(map),clazz); } catch(Exception e) { e.printStackTrace(); } return obj; } 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; } }
微信常量类
public class WxConstants { //微信统一下单请求xml参数 public static final String APPID="wx1111111"; //appid是微信公众账号或开放平台APP的唯一标识 public static final String MCHID="111111";//商户申请微信支付后,由微信支付分配的商户收款账号 public static final String SECRET="aaaaaaaa";//AppSecret是APPID对应的接口密码 public static final String KEY="1111111111";//交易过程生成签名的密钥 同API密钥 public static final String NONCE_STR="nonce_str"; public static final String SIGN="sign";//生成签名 public static final String ATTACH="attach"; public static final String TIMESTAMP = "timeStamp"; public static final String NONCESTR = "noncestr"; public static final String PREPAYID = "prepayid"; public static final String PARTNERID = "111111";//API密钥 public static final String PACKAGE = "package"; public static final String OPENID ="OPENID";//用户唯一标识 public static final int getHttpConnectTimeoutMs = 8000;//连接时间 public static final int getHttpReadTimeoutMs = 10000; //超时时间 /** * 微信 JSAPI支付(或小程序支付)微信中调用网页支付 */ public static final String WX_TRADE_JSAPI = "JSAPI"; /** * 微信 Native支付 */ public static final String WX_TRADE_NATIVE = "NATIVE"; /** * 微信 H5支付 */ public static final String WX_TRADE_MWEB = "MWEB"; /** * 微信 app支付 */ public static final String WX_TRADE_APP = "APP"; }
看完上述内容,你们掌握java如何实现微信jsApi支付的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注亿速云行业资讯频道,感谢各位的阅读!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。