您好,登錄后才能下訂單哦!
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進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。