微信小程序支付(java后端) 转自 https://blog.csdn.net/qq_30641447/article/details/73222648

转自  https://blog.csdn.net/qq_30641447/article/details/73222648


第一步 

进入小程序,下单,请求下单支付,调用小程序登录API来获取Openid(https://mp.weixin.qq.com/debug/w ... .html#wxloginobject),生成商户订单,这些都是在小程序端完成的业务。 

小程序端代码 

  1. // pages/pay/pay.js
  2. var app = getApp();
  3. Page({
  4. data: {},
  5. onLoad: function (options) {
  6. // 页面初始化 options为页面跳转所带来的参数
  7. },
  8. /* 微信支付 */
  9. wxpay: function () {
  10. var that = this
  11. //登陆获取code
  12. wx.login({
  13. success: function (res) {
  14. console.log(res.code)
  15. //获取openid
  16. that.getOpenId(res.code)
  17. }
  18. });
  19. },
  20. getOpenId: function (code) {
  21. var that = this;
  22. wx.request({
  23. url: "https://api.weixin.qq.com/sns/jscode2session?appid=wxa142513e524e496c&secret=5d6a7d86048884e7c60f84f7aa85253c&js_code=" + code + "&grant_type=authorization_code",
  24. data: {},
  25. method: 'GET',
  26. success: function (res) {
  27. console.log( '返回openId')
  28. console.log(res.data)
  29. that.generateOrder(res.data.openid)
  30. },
  31. fail: function () {
  32. // fail
  33. },
  34. complete: function () {
  35. // complete
  36. }
  37. })
  38. },
  39. /**生成商户订单 */
  40. generateOrder: function (openid) {
  41. var that = this
  42. //统一支付
  43. wx.request({
  44. url: 'http://localhost:8070/RMS/pay_pay.action',
  45. method: 'GET',
  46. data: {
  47. total_fee: '5',
  48. body: '支付测试',
  49. attach: '真假酒水'
  50. },
  51. success: function (res) {
  52. console.log(res)
  53. var pay = res.data
  54. //发起支付
  55. var timeStamp = pay[ 0].timeStamp;
  56. console.log( "timeStamp:"+timeStamp)
  57. var packages = pay[ 0].package;
  58. console.log( "package:"+packages)
  59. var paySign = pay[ 0].paySign;
  60. console.log( "paySign:"+paySign)
  61. var nonceStr = pay[ 0].nonceStr;
  62. console.log( "nonceStr:"+nonceStr)
  63. var param = { "timeStamp": timeStamp, "package": packages, "paySign": paySign, "signType": "MD5", "nonceStr": nonceStr };
  64. that.pay(param)
  65. },
  66. })
  67. },
  68. /* 支付 */
  69. pay: function (param) {
  70. console.log( "支付")
  71. console.log(param)
  72. wx.requestPayment({
  73. timeStamp: param.timeStamp,
  74. nonceStr: param.nonceStr,
  75. package: param.package,
  76. signType: param.signType,
  77. paySign: param.paySign,
  78. success: function (res) {
  79. // success
  80. console.log( "支付")
  81. console.log(res)
  82. wx.navigateBack({
  83. delta: 1, // 回退前 delta(默认为1) 页面
  84. success: function (res) {
  85. wx.showToast({
  86. title: '支付成功',
  87. icon: 'success',
  88. duration: 2000
  89. })
  90. },
  91. fail: function () {
  92. // fail
  93. },
  94. complete: function () {
  95. // complete
  96. }
  97. })
  98. },
  99. fail: function (res) {
  100. // fail
  101. console.log( "支付失败")
  102. console.log(res)
  103. },
  104. complete: function () {
  105. // complete
  106. console.log( "pay complete")
  107. }
  108. })
  109. }
  110. })
第二步 
调用支付统一下单API来获取prepay_id,并将小程序调起支付数据需要签名的字段appId,timeStamp,nonceStr,package再次签名(https://pay.weixin.qq.com/wiki/d ... ter=7_7&index=3) 

后台代码 

  1. package cn.it.shop.action;
  2. import java.io.ByteArrayInputStream;
  3. import java.io.InputStream;
  4. import java.io.UnsupportedEncodingException;
  5. import java.text.SimpleDateFormat;
  6. import java.util.Date;
  7. import java.util.HashMap;
  8. import java.util.List;
  9. import java.util.Map;
  10. import org.dom4j.Document;
  11. import org.dom4j.DocumentException;
  12. import org.dom4j.Element;
  13. import org.dom4j.io.SAXReader;
  14. import cn.it.shop.util.MessageUtil;
  15. import cn.it.shop.util.PayUtil;
  16. import cn.it.shop.util.PaymentPo;
  17. import cn.it.shop.util.UUIDHexGenerator;
  18. import net.sf.json.JSONArray;
  19. import net.sf.json.JSONObject;
  20. /**
  21. * @author
  22. * @version 创建时间:2017年1月21日 下午4:59:03
  23. * 小程序端请求的后台action,返回签名后的数据传到前台
  24. */
  25. public class PayAction {
  26. private String total_fee; //总金额
  27. private String body; //商品描述
  28. private String detail; //商品详情
  29. private String attach; //附加数据
  30. private String time_start; //交易起始时间
  31. private String time_expire; //交易结束时间
  32. private String openid; //用户标识
  33. private JSONArray jsonArray= new JSONArray();
  34. public String pay() throws UnsupportedEncodingException, DocumentException{
  35. body = new String(body.getBytes( "UTF-8"), "ISO-8859-1");
  36. String appid = "替换为自己的小程序ID"; //小程序ID
  37. String mch_id = "替换为自己的商户号"; //商户号
  38. String nonce_str = UUIDHexGenerator.generate(); //随机字符串
  39. String today = new SimpleDateFormat( "yyyyMMddHHmmss").format( new Date());
  40. String code = PayUtil.createCode( 8);
  41. String out_trade_no = mch_id+today+code; //商户订单号
  42. String spbill_create_ip = "替换为自己的终端IP"; //终端IP
  43. String notify_url = "http://www.weixin.qq.com/wxpay/pay.php"; //通知地址
  44. String trade_type = "JSAPI"; //交易类型
  45. String openid= "替换为用户的openid"; //用户标识
  46. /**/
  47. PaymentPo paymentPo = new PaymentPo();
  48. paymentPo.setAppid(appid);
  49. paymentPo.setMch_id(mch_id);
  50. paymentPo.setNonce_str(nonce_str);
  51. String newbody=new String(body.getBytes("ISO-8859-1"),"UTF-8");//以utf-8编码放入paymentPo,微信支付要求字符编码统一采用UTF-8字符编码
  52. paymentPo.setBody(newbody);
  53. paymentPo.setOut_trade_no(out_trade_no);
  54. paymentPo.setTotal_fee(total_fee);
  55. paymentPo.setSpbill_create_ip(spbill_create_ip);
  56. paymentPo.setNotify_url(notify_url);
  57. paymentPo.setTrade_type(trade_type);
  58. paymentPo.setOpenid(openid);
  59. // 把请求参数打包成数组
  60. Map sParaTemp = new HashMap();
  61. sParaTemp.put("appid", paymentPo.getAppid());
  62. sParaTemp.put("mch_id", paymentPo.getMch_id());
  63. sParaTemp.put("nonce_str", paymentPo.getNonce_str());
  64. sParaTemp.put("body", paymentPo.getBody());
  65. sParaTemp.put("out_trade_no", paymentPo.getOut_trade_no());
  66. sParaTemp.put("total_fee",paymentPo.getTotal_fee());
  67. sParaTemp.put("spbill_create_ip", paymentPo.getSpbill_create_ip());
  68. sParaTemp.put("notify_url",paymentPo.getNotify_url());
  69. sParaTemp.put("trade_type", paymentPo.getTrade_type());
  70. sParaTemp.put("openid", paymentPo.getOpenid());
  71. // 除去数组中的空值和签名参数
  72. Map sPara = PayUtil.paraFilter(sParaTemp);
  73. String prestr = PayUtil.createLinkString(sPara); // 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
  74. String key = "&key=替换为商户支付密钥"; // 商户支付密钥
  75. //MD5运算生成签名
  76. String mysign = PayUtil.sign(prestr, key, "utf-8").toUpperCase();
  77. paymentPo.setSign(mysign);
  78. //打包要发送的xml
  79. String respXml = MessageUtil.messageToXML(paymentPo);
  80. // 打印respXml发现,得到的xml中有“__”不对,应该替换成“_”
  81. respXml = respXml.replace("__", "_");
  82. String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";//统一下单API接口链接
  83. String param = respXml;
  84. //String result = SendRequestForUrl.sendRequest(url, param);//发起请求
  85. String result =PayUtil.httpRequest(url, "POST", param);
  86. // 将解析结果存储在HashMap中
  87. Map map = new HashMap();
  88. InputStream in=new ByteArrayInputStream(result.getBytes());
  89. // 读取输入流
  90. SAXReader reader = new SAXReader();
  91. Document document = reader.read(in);
  92. // 得到xml根元素
  93. Element root = document.getRootElement();
  94. // 得到根元素的所有子节点
  95. @SuppressWarnings("unchecked")
  96. List elementList = root.elements();
  97. for (Element element : elementList) {
  98. map.put(element.getName(), element.getText());
  99. }
  100. // 返回信息
  101. String return_code = map.get("return_code");//返回状态码
  102. String return_msg = map.get("return_msg");//返回信息
  103. System.out.println("return_msg"+return_msg);
  104. JSONObject JsonObject=new JSONObject() ;
  105. if(return_code=="SUCCESS"||return_code.equals(return_code)){
  106. // 业务结果
  107. String prepay_id = map.get("prepay_id");//返回的预付单信息
  108. String nonceStr=UUIDHexGenerator.generate();
  109. JsonObject.put("nonceStr", nonceStr);
  110. JsonObject.put("package", "prepay_id="+prepay_id);
  111. Long timeStamp= System.currentTimeMillis()/1000;
  112. JsonObject.put("timeStamp", timeStamp+"");
  113. String stringSignTemp = "appId="+appid+"&nonceStr=" + nonceStr + "&package=prepay_id=" + prepay_id+ "&signType=MD5&timeStamp=" + timeStamp;
  114. //再次签名
  115. String paySign=PayUtil.sign(stringSignTemp, "&key=替换为自己的密钥", "utf-8").toUpperCase();
  116. JsonObject.put("paySign", paySign);
  117. jsonArray.add(JsonObject);
  118. }
  119. return "pay";
  120. }
  121. public String getTotal_fee() {
  122. return total_fee;
  123. }
  124. public void setTotal_fee(String total_fee) {
  125. this.total_fee = total_fee;
  126. }
  127. public String getBody() {
  128. return body;
  129. }
  130. public void setBody(String body) {
  131. this.body = body;
  132. }
  133. public JSONArray getJsonArray() {
  134. return jsonArray;
  135. }
  136. public void setJsonArray(JSONArray jsonArray) {
  137. this.jsonArray = jsonArray;
  138. }
  139. public String getDetail() {
  140. return detail;
  141. }
  142. public void setDetail(String detail) {
  143. this.detail = detail;
  144. }
  145. public String getAttach() {
  146. return attach;
  147. }
  148. public void setAttach(String attach) {
  149. this.attach = attach;
  150. }
  151. public String getTime_start() {
  152. return time_start;
  153. }
  154. public void setTime_start(String time_start) {
  155. this.time_start = time_start;
  156. }
  157. public String getTime_expire() {
  158. return time_expire;
  159. }
  160. public void setTime_expire(String time_expire) {
  161. this.time_expire = time_expire;
  162. }
  163. public String getOpenid() {
  164. return openid;
  165. }
  166. public void setOpenid(String openid) {
  167. this.openid = openid;
  168. }
  169. }
后台业务逻辑涉及到的工具类及参数封装类 
MessageUtil 
  1. package cn.it.shop.util;
  2. import java.io.IOException;
  3. import java.io.Writer;
  4. import java.util.HashMap;
  5. import java.util.List;
  6. import javax.servlet.http.HttpServletRequest;
  7. import org.dom4j.Document;
  8. import org.dom4j.Element;
  9. import org.dom4j.io.SAXReader;
  10. import com.thoughtworks.xstream.XStream;
  11. import com.thoughtworks.xstream.core.util.QuickWriter;
  12. import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
  13. import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
  14. import com.thoughtworks.xstream.io.xml.XppDriver;
  15. public class MessageUtil {
  16. public static HashMap parseXML(HttpServletRequest request) throws Exception, IOException{
  17. HashMap map= new HashMap();
  18. // 通过IO获得Document
  19. SAXReader reader = new SAXReader();
  20. Document doc = reader.read(request.getInputStream());
  21. //得到xml的根节点
  22. Element root=doc.getRootElement();
  23. recursiveParseXML(root,map);
  24. return map;
  25. }
  26. private static void recursiveParseXML(Element root,HashMap map){
  27. //得到根节点的子节点列表
  28. List elementList=root.elements();
  29. //判断有没有子元素列表
  30. if(elementList.size()== 0){
  31. map.put(root.getName(), root.getTextTrim());
  32. }
  33. else{
  34. //遍历
  35. for(Element e:elementList){
  36. recursiveParseXML(e,map);
  37. }
  38. }
  39. }
  40. private static XStream xstream = new XStream( new XppDriver() {
  41. public HierarchicalStreamWriter createWriter(Writer out) {
  42. return new PrettyPrintWriter(out) {
  43. // 对所有xml节点都增加CDATA标记
  44. boolean cdata = true;
  45. public void startNode(String name, Class clazz) {
  46. super.startNode(name, clazz);
  47. }
  48. protected void writeText(QuickWriter writer, String text) {
  49. if (cdata) {
  50. writer.write( " writer.write(text);
  51. writer.write("]]> ");
  52. } else {
  53. writer.write(text);
  54. }
  55. }
  56. };
  57. }
  58. });
  59. public static String messageToXML(PaymentPo paymentPo){
  60. xstream.alias("xml ",PaymentPo.class);
  61. return xstream.toXML(paymentPo);
  62. }
  63. }
PaymentPo//封装支付参数实体 
  1. package cn.it.shop.util;
  2. /**
  3. * @author
  4. * @version 创建时间:2017年1月21日 下午4:20:52
  5. * 类说明
  6. */
  7. public class PaymentPo {
  8. private String appid; //小程序ID
  9. private String mch_id; //商户号
  10. private String device_info; //设备号
  11. private String nonce_str; //随机字符串
  12. private String sign; //签名
  13. private String body; //商品描述
  14. private String detail; //商品详情
  15. private String attach; //附加数据
  16. private String out_trade_no; //商户订单号
  17. private String fee_type; //货币类型
  18. private String spbill_create_ip; //终端IP
  19. private String time_start; //交易起始时间
  20. private String time_expire; //交易结束时间
  21. private String goods_tag; //商品标记
  22. private String total_fee; //总金额
  23. private String notify_url; //通知地址
  24. private String trade_type; //交易类型
  25. private String limit_pay; //指定支付方式
  26. private String openid; //用户标识
  27. set/get //省略
  28. }
PayUtil

  1. package cn.it.shop.util;
  2. import java.io.BufferedReader;
  3. import java.io.InputStream;
  4. import java.io.InputStreamReader;
  5. import java.io.OutputStream;
  6. import java.io.UnsupportedEncodingException;
  7. import java.net.HttpURLConnection;
  8. import java.net.URL;
  9. import java.util.ArrayList;
  10. import java.util.Collections;
  11. import java.util.HashMap;
  12. import java.util.List;
  13. import java.util.Map;
  14. import org.apache.commons.codec.digest.DigestUtils;
  15. /**
  16. * @author
  17. * @version 创建时间:2017年1月17日 下午7:46:29 类说明
  18. */
  19. public class PayUtil {
  20. /**
  21. * 签名字符串
  22. * @param text需要签名的字符串
  23. * @param key 密钥
  24. * @param input_charset编码格式
  25. * @return 签名结果
  26. */
  27. public static String sign(String text, String key, String input_charset) {
  28. text = text + key;
  29. return DigestUtils.md5Hex(getContentBytes(text, input_charset));
  30. }
  31. /**
  32. * 签名字符串
  33. * @param text需要签名的字符串
  34. * @param sign 签名结果
  35. * @param key密钥
  36. * @param input_charset 编码格式
  37. * @return 签名结果
  38. */
  39. public static boolean verify(String text, String sign, String key, String input_charset) {
  40. text = text + key;
  41. String mysign = DigestUtils.md5Hex(getContentBytes(text, input_charset));
  42. if (mysign.equals(sign)) {
  43. return true;
  44. } else {
  45. return false;
  46. }
  47. }
  48. /**
  49. * @param content
  50. * @param charset
  51. * @return
  52. * @throws SignatureException
  53. * @throws UnsupportedEncodingException
  54. */
  55. public static byte[] getContentBytes(String content, String charset) {
  56. if (charset == null || "".equals(charset)) {
  57. return content.getBytes();
  58. }
  59. try {
  60. return content.getBytes(charset);
  61. } catch (UnsupportedEncodingException e) {
  62. throw new RuntimeException( "MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);
  63. }
  64. }
  65. /**
  66. * 生成6位或10位随机数 param codeLength(多少位)
  67. * @return
  68. */
  69. public static String createCode(int codeLength) {
  70. String code = "";
  71. for ( int i = 0; i < codeLength; i++) {
  72. code += ( int) (Math.random() * 9);
  73. }
  74. return code;
  75. }
  76. private static boolean isValidChar(char ch) {
  77. if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))
  78. return true;
  79. if ((ch >= 0x4e00 && ch <= 0x7fff) || (ch >= 0x8000 && ch <= 0x952f))
  80. return true; // 简体中文汉字编码
  81. return false;
  82. }
  83. /**
  84. * 除去数组中的空值和签名参数
  85. * @param sArray 签名参数组
  86. * @return 去掉空值与签名参数后的新签名参数组
  87. */
  88. public static Map paraFilter(Map sArray) {
  89. Map result = new HashMap();
  90. if (sArray == null || sArray.size() <= 0) {
  91. return result;
  92. }
  93. for (String key : sArray.keySet()) {
  94. String value = sArray.get(key);
  95. if (value == null || value.equals( "") || key.equalsIgnoreCase( "sign")
  96. || key.equalsIgnoreCase( "sign_type")) {
  97. continue;
  98. }
  99. result.put(key, value);
  100. }
  101. return result;
  102. }
  103. /**
  104. * 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
  105. * @param params 需要排序并参与字符拼接的参数组
  106. * @return 拼接后字符串
  107. */
  108. public static String createLinkString(Map params) {
  109. List keys = new ArrayList(params.keySet());
  110. Collections.sort(keys);
  111. String prestr = "";
  112. for ( int i = 0; i < keys.size(); i++) {
  113. String key = keys.get(i);
  114. String value = params.get(key);
  115. if (i == keys.size() - 1) { // 拼接时,不包括最后一个&字符
  116. prestr = prestr + key + "=" + value;
  117. } else {
  118. prestr = prestr + key + "=" + value + "&";
  119. }
  120. }
  121. return prestr;
  122. }
  123. /**
  124. *
  125. * @param requestUrl请求地址
  126. * @param requestMethod请求方法
  127. * @param outputStr参数
  128. */
  129. public static String httpRequest(String requestUrl,String requestMethod,String outputStr){
  130. // 创建SSLContext
  131. StringBuffer buffer= null;
  132. try{
  133. URL url = new URL(requestUrl);
  134. HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  135. conn.setRequestMethod(requestMethod);
  136. conn.setDoOutput( true);
  137. conn.setDoInput( true);
  138. conn.connect();
  139. //往服务器端写内容
  140. if( null !=outputStr){
  141. OutputStream os=conn.getOutputStream();
  142. os.write(outputStr.getBytes( "utf-8"));
  143. os.close();
  144. }
  145. // 读取服务器端返回的内容
  146. InputStream is = conn.getInputStream();
  147. InputStreamReader isr = new InputStreamReader(is, "utf-8");
  148. BufferedReader br = new BufferedReader(isr);
  149. buffer = new StringBuffer();
  150. String line = null;
  151. while ((line = br.readLine()) != null) {
  152. buffer.append(line);
  153. }
  154. } catch(Exception e){
  155. e.printStackTrace();
  156. }
  157. return buffer.toString();
  158. }
  159. public static String urlEncodeUTF8(String source){
  160. String result=source;
  161. try {
  162. result=java.net.URLEncoder.encode(source, "UTF-8");
  163. } catch (UnsupportedEncodingException e) {
  164. // TODO Auto-generated catch block
  165. e.printStackTrace();
  166. }
  167. return result;
  168. }
  169. }
UUIDHexGenerator 
  1. package cn.it.shop.util;
  2. import java.net.InetAddress;
  3. /**
  4. * @author
  5. * @version 创建时间:2017年1月17日 下午7:45:06 类说明
  6. */
  7. public class UUIDHexGenerator {
  8. private static String sep = "";
  9. private static final int IP;
  10. private static short counter = ( short) 0;
  11. private static final int JVM = ( int) (System.currentTimeMillis() >>>;
  12. private static UUIDHexGenerator uuidgen = new UUIDHexGenerator();
  13. static {
  14. int ipadd;
  15. try {
  16. ipadd = toInt(InetAddress.getLocalHost().getAddress());
  17. } catch (Exception e) {
  18. ipadd = 0;
  19. }
  20. IP = ipadd;
  21. }
  22. public static UUIDHexGenerator getInstance() {
  23. return uuidgen;
  24. }
  25. public static int toInt(byte[] bytes) {
  26. int result = 0;
  27. for ( int i = 0; i < 4; i++) {
  28. result = (result << - Byte.MIN_VALUE + ( int) bytes;
  29. }
  30. return result;
  31. }
  32. protected static String format(int intval) {
  33. String formatted = Integer.toHexString(intval);
  34. StringBuffer buf = new StringBuffer( "00000000");
  35. buf.replace( 8 - formatted.length(), 8, formatted);
  36. return buf.toString();
  37. }
  38. protected static String format(short shortval) {
  39. String formatted = Integer.toHexString(shortval);
  40. StringBuffer buf = new StringBuffer( "0000");
  41. buf.replace( 4 - formatted.length(), 4, formatted);
  42. return buf.toString();
  43. }
  44. protected static int getJVM() {
  45. return JVM;
  46. }
  47. protected synchronized static short getCount() {
  48. if (counter < 0) {
  49. counter = 0;
  50. }
  51. return counter++;
  52. }
  53. protected static int getIP() {
  54. return IP;
  55. }
  56. protected static short getHiTime() {
  57. return ( short) (System.currentTimeMillis() >>> 32);
  58. }
  59. protected static int getLoTime() {
  60. return ( int) System.currentTimeMillis();
  61. }
  62. public static String generate() {
  63. return new StringBuffer( 36).append(format(getIP())).append(sep).append(format(getJVM())).append(sep)
  64. .append(format(getHiTime())).append(sep).append(format(getLoTime())).append(sep)
  65. .append(format(getCount())).toString();
  66. }
  67. /**
  68. * @param args
  69. */
  70. public static void main(String[] args) {
  71. String id= "";
  72. UUIDHexGenerator uuid = UUIDHexGenerator.getInstance();
  73. /*
  74. for (int i = 0; i < 100; i++) {
  75. id = uuid.generate();
  76. }*/
  77. id = uuid.generate();
  78. System.out.println(id);
  79. }
  80. }





付源码:

链接:https://pan.baidu.com/s/1dFRVmiX 密码:dkx7



第一步 

进入小程序,下单,请求下单支付,调用小程序登录API来获取Openid(https://mp.weixin.qq.com/debug/w ... .html#wxloginobject),生成商户订单,这些都是在小程序端完成的业务。 

小程序端代码 

  1. // pages/pay/pay.js
  2. var app = getApp();
  3. Page({
  4. data: {},
  5. onLoad: function (options) {
  6. // 页面初始化 options为页面跳转所带来的参数
  7. },
  8. /* 微信支付 */
  9. wxpay: function () {
  10. var that = this
  11. //登陆获取code
  12. wx.login({
  13. success: function (res) {
  14. console.log(res.code)
  15. //获取openid
  16. that.getOpenId(res.code)
  17. }
  18. });
  19. },
  20. getOpenId: function (code) {
  21. var that = this;
  22. wx.request({
  23. url: "https://api.weixin.qq.com/sns/jscode2session?appid=wxa142513e524e496c&secret=5d6a7d86048884e7c60f84f7aa85253c&js_code=" + code + "&grant_type=authorization_code",
  24. data: {},
  25. method: 'GET',
  26. success: function (res) {
  27. console.log( '返回openId')
  28. console.log(res.data)
  29. that.generateOrder(res.data.openid)
  30. },
  31. fail: function () {
  32. // fail
  33. },
  34. complete: function () {
  35. // complete
  36. }
  37. })
  38. },
  39. /**生成商户订单 */
  40. generateOrder: function (openid) {
  41. var that = this
  42. //统一支付
  43. wx.request({
  44. url: 'http://localhost:8070/RMS/pay_pay.action',
  45. method: 'GET',
  46. data: {
  47. total_fee: '5',
  48. body: '支付测试',
  49. attach: '真假酒水'
  50. },
  51. success: function (res) {
  52. console.log(res)
  53. var pay = res.data
  54. //发起支付
  55. var timeStamp = pay[ 0].timeStamp;
  56. console.log( "timeStamp:"+timeStamp)
  57. var packages = pay[ 0].package;
  58. console.log( "package:"+packages)
  59. var paySign = pay[ 0].paySign;
  60. console.log( "paySign:"+paySign)
  61. var nonceStr = pay[ 0].nonceStr;
  62. console.log( "nonceStr:"+nonceStr)
  63. var param = { "timeStamp": timeStamp, "package": packages, "paySign": paySign, "signType": "MD5", "nonceStr": nonceStr };
  64. that.pay(param)
  65. },
  66. })
  67. },
  68. /* 支付 */
  69. pay: function (param) {
  70. console.log( "支付")
  71. console.log(param)
  72. wx.requestPayment({
  73. timeStamp: param.timeStamp,
  74. nonceStr: param.nonceStr,
  75. package: param.package,
  76. signType: param.signType,
  77. paySign: param.paySign,
  78. success: function (res) {
  79. // success
  80. console.log( "支付")
  81. console.log(res)
  82. wx.navigateBack({
  83. delta: 1, // 回退前 delta(默认为1) 页面
  84. success: function (res) {
  85. wx.showToast({
  86. title: '支付成功',
  87. icon: 'success',
  88. duration: 2000
  89. })
  90. },
  91. fail: function () {
  92. // fail
  93. },
  94. complete: function () {
  95. // complete
  96. }
  97. })
  98. },
  99. fail: function (res) {
  100. // fail
  101. console.log( "支付失败")
  102. console.log(res)
  103. },
  104. complete: function () {
  105. // complete
  106. console.log( "pay complete")
  107. }
  108. })
  109. }
  110. })
第二步 
调用支付统一下单API来获取prepay_id,并将小程序调起支付数据需要签名的字段appId,timeStamp,nonceStr,package再次签名(https://pay.weixin.qq.com/wiki/d ... ter=7_7&index=3) 

后台代码 

  1. package cn.it.shop.action;
  2. import java.io.ByteArrayInputStream;
  3. import java.io.InputStream;
  4. import java.io.UnsupportedEncodingException;
  5. import java.text.SimpleDateFormat;
  6. import java.util.Date;
  7. import java.util.HashMap;
  8. import java.util.List;
  9. import java.util.Map;
  10. import org.dom4j.Document;
  11. import org.dom4j.DocumentException;
  12. import org.dom4j.Element;
  13. import org.dom4j.io.SAXReader;
  14. import cn.it.shop.util.MessageUtil;
  15. import cn.it.shop.util.PayUtil;
  16. import cn.it.shop.util.PaymentPo;
  17. import cn.it.shop.util.UUIDHexGenerator;
  18. import net.sf.json.JSONArray;
  19. import net.sf.json.JSONObject;
  20. /**
  21. * @author
  22. * @version 创建时间:2017年1月21日 下午4:59:03
  23. * 小程序端请求的后台action,返回签名后的数据传到前台
  24. */
  25. public class PayAction {
  26. private String total_fee; //总金额
  27. private String body; //商品描述
  28. private String detail; //商品详情
  29. private String attach; //附加数据
  30. private String time_start; //交易起始时间
  31. private String time_expire; //交易结束时间
  32. private String openid; //用户标识
  33. private JSONArray jsonArray= new JSONArray();
  34. public String pay() throws UnsupportedEncodingException, DocumentException{
  35. body = new String(body.getBytes( "UTF-8"), "ISO-8859-1");
  36. String appid = "替换为自己的小程序ID"; //小程序ID
  37. String mch_id = "替换为自己的商户号"; //商户号
  38. String nonce_str = UUIDHexGenerator.generate(); //随机字符串
  39. String today = new SimpleDateFormat( "yyyyMMddHHmmss").format( new Date());
  40. String code = PayUtil.createCode( 8);
  41. String out_trade_no = mch_id+today+code; //商户订单号
  42. String spbill_create_ip = "替换为自己的终端IP"; //终端IP
  43. String notify_url = "http://www.weixin.qq.com/wxpay/pay.php"; //通知地址
  44. String trade_type = "JSAPI"; //交易类型
  45. String openid= "替换为用户的openid"; //用户标识
  46. /**/
  47. PaymentPo paymentPo = new PaymentPo();
  48. paymentPo.setAppid(appid);
  49. paymentPo.setMch_id(mch_id);
  50. paymentPo.setNonce_str(nonce_str);
  51. String newbody=new String(body.getBytes("ISO-8859-1"),"UTF-8");//以utf-8编码放入paymentPo,微信支付要求字符编码统一采用UTF-8字符编码
  52. paymentPo.setBody(newbody);
  53. paymentPo.setOut_trade_no(out_trade_no);
  54. paymentPo.setTotal_fee(total_fee);
  55. paymentPo.setSpbill_create_ip(spbill_create_ip);
  56. paymentPo.setNotify_url(notify_url);
  57. paymentPo.setTrade_type(trade_type);
  58. paymentPo.setOpenid(openid);
  59. // 把请求参数打包成数组
  60. Map sParaTemp = new HashMap();
  61. sParaTemp.put("appid", paymentPo.getAppid());
  62. sParaTemp.put("mch_id", paymentPo.getMch_id());
  63. sParaTemp.put("nonce_str", paymentPo.getNonce_str());
  64. sParaTemp.put("body", paymentPo.getBody());
  65. sParaTemp.put("out_trade_no", paymentPo.getOut_trade_no());
  66. sParaTemp.put("total_fee",paymentPo.getTotal_fee());
  67. sParaTemp.put("spbill_create_ip", paymentPo.getSpbill_create_ip());
  68. sParaTemp.put("notify_url",paymentPo.getNotify_url());
  69. sParaTemp.put("trade_type", paymentPo.getTrade_type());
  70. sParaTemp.put("openid", paymentPo.getOpenid());
  71. // 除去数组中的空值和签名参数
  72. Map sPara = PayUtil.paraFilter(sParaTemp);
  73. String prestr = PayUtil.createLinkString(sPara); // 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
  74. String key = "&key=替换为商户支付密钥"; // 商户支付密钥
  75. //MD5运算生成签名
  76. String mysign = PayUtil.sign(prestr, key, "utf-8").toUpperCase();
  77. paymentPo.setSign(mysign);
  78. //打包要发送的xml
  79. String respXml = MessageUtil.messageToXML(paymentPo);
  80. // 打印respXml发现,得到的xml中有“__”不对,应该替换成“_”
  81. respXml = respXml.replace("__", "_");
  82. String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";//统一下单API接口链接
  83. String param = respXml;
  84. //String result = SendRequestForUrl.sendRequest(url, param);//发起请求
  85. String result =PayUtil.httpRequest(url, "POST", param);
  86. // 将解析结果存储在HashMap中
  87. Map map = new HashMap();
  88. InputStream in=new ByteArrayInputStream(result.getBytes());
  89. // 读取输入流
  90. SAXReader reader = new SAXReader();
  91. Document document = reader.read(in);
  92. // 得到xml根元素
  93. Element root = document.getRootElement();
  94. // 得到根元素的所有子节点
  95. @SuppressWarnings("unchecked")
  96. List elementList = root.elements();
  97. for (Element element : elementList) {
  98. map.put(element.getName(), element.getText());
  99. }
  100. // 返回信息
  101. String return_code = map.get("return_code");//返回状态码
  102. String return_msg = map.get("return_msg");//返回信息
  103. System.out.println("return_msg"+return_msg);
  104. JSONObject JsonObject=new JSONObject() ;
  105. if(return_code=="SUCCESS"||return_code.equals(return_code)){
  106. // 业务结果
  107. String prepay_id = map.get("prepay_id");//返回的预付单信息
  108. String nonceStr=UUIDHexGenerator.generate();
  109. JsonObject.put("nonceStr", nonceStr);
  110. JsonObject.put("package", "prepay_id="+prepay_id);
  111. Long timeStamp= System.currentTimeMillis()/1000;
  112. JsonObject.put("timeStamp", timeStamp+"");
  113. String stringSignTemp = "appId="+appid+"&nonceStr=" + nonceStr + "&package=prepay_id=" + prepay_id+ "&signType=MD5&timeStamp=" + timeStamp;
  114. //再次签名
  115. String paySign=PayUtil.sign(stringSignTemp, "&key=替换为自己的密钥", "utf-8").toUpperCase();
  116. JsonObject.put("paySign", paySign);
  117. jsonArray.add(JsonObject);
  118. }
  119. return "pay";
  120. }
  121. public String getTotal_fee() {
  122. return total_fee;
  123. }
  124. public void setTotal_fee(String total_fee) {
  125. this.total_fee = total_fee;
  126. }
  127. public String getBody() {
  128. return body;
  129. }
  130. public void setBody(String body) {
  131. this.body = body;
  132. }
  133. public JSONArray getJsonArray() {
  134. return jsonArray;
  135. }
  136. public void setJsonArray(JSONArray jsonArray) {
  137. this.jsonArray = jsonArray;
  138. }
  139. public String getDetail() {
  140. return detail;
  141. }
  142. public void setDetail(String detail) {
  143. this.detail = detail;
  144. }
  145. public String getAttach() {
  146. return attach;
  147. }
  148. public void setAttach(String attach) {
  149. this.attach = attach;
  150. }
  151. public String getTime_start() {
  152. return time_start;
  153. }
  154. public void setTime_start(String time_start) {
  155. this.time_start = time_start;
  156. }
  157. public String getTime_expire() {
  158. return time_expire;
  159. }
  160. public void setTime_expire(String time_expire) {
  161. this.time_expire = time_expire;
  162. }
  163. public String getOpenid() {
  164. return openid;
  165. }
  166. public void setOpenid(String openid) {
  167. this.openid = openid;
  168. }
  169. }
后台业务逻辑涉及到的工具类及参数封装类 
MessageUtil 
  1. package cn.it.shop.util;
  2. import java.io.IOException;
  3. import java.io.Writer;
  4. import java.util.HashMap;
  5. import java.util.List;
  6. import javax.servlet.http.HttpServletRequest;
  7. import org.dom4j.Document;
  8. import org.dom4j.Element;
  9. import org.dom4j.io.SAXReader;
  10. import com.thoughtworks.xstream.XStream;
  11. import com.thoughtworks.xstream.core.util.QuickWriter;
  12. import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
  13. import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
  14. import com.thoughtworks.xstream.io.xml.XppDriver;
  15. public class MessageUtil {
  16. public static HashMap parseXML(HttpServletRequest request) throws Exception, IOException{
  17. HashMap map= new HashMap();
  18. // 通过IO获得Document
  19. SAXReader reader = new SAXReader();
  20. Document doc = reader.read(request.getInputStream());
  21. //得到xml的根节点
  22. Element root=doc.getRootElement();
  23. recursiveParseXML(root,map);
  24. return map;
  25. }
  26. private static void recursiveParseXML(Element root,HashMap map){
  27. //得到根节点的子节点列表
  28. List elementList=root.elements();
  29. //判断有没有子元素列表
  30. if(elementList.size()== 0){
  31. map.put(root.getName(), root.getTextTrim());
  32. }
  33. else{
  34. //遍历
  35. for(Element e:elementList){
  36. recursiveParseXML(e,map);
  37. }
  38. }
  39. }
  40. private static XStream xstream = new XStream( new XppDriver() {
  41. public HierarchicalStreamWriter createWriter(Writer out) {
  42. return new PrettyPrintWriter(out) {
  43. // 对所有xml节点都增加CDATA标记
  44. boolean cdata = true;
  45. public void startNode(String name, Class clazz) {
  46. super.startNode(name, clazz);
  47. }
  48. protected void writeText(QuickWriter writer, String text) {
  49. if (cdata) {
  50. writer.write( " writer.write(text);
  51. writer.write("]]> ");
  52. } else {
  53. writer.write(text);
  54. }
  55. }
  56. };
  57. }
  58. });
  59. public static String messageToXML(PaymentPo paymentPo){
  60. xstream.alias("xml ",PaymentPo.class);
  61. return xstream.toXML(paymentPo);
  62. }
  63. }
PaymentPo//封装支付参数实体 
  1. package cn.it.shop.util;
  2. /**
  3. * @author
  4. * @version 创建时间:2017年1月21日 下午4:20:52
  5. * 类说明
  6. */
  7. public class PaymentPo {
  8. private String appid; //小程序ID
  9. private String mch_id; //商户号
  10. private String device_info; //设备号
  11. private String nonce_str; //随机字符串
  12. private String sign; //签名
  13. private String body; //商品描述
  14. private String detail; //商品详情
  15. private String attach; //附加数据
  16. private String out_trade_no; //商户订单号
  17. private String fee_type; //货币类型
  18. private String spbill_create_ip; //终端IP
  19. private String time_start; //交易起始时间
  20. private String time_expire; //交易结束时间
  21. private String goods_tag; //商品标记
  22. private String total_fee; //总金额
  23. private String notify_url; //通知地址
  24. private String trade_type; //交易类型
  25. private String limit_pay; //指定支付方式
  26. private String openid; //用户标识
  27. set/get //省略
  28. }
PayUtil

  1. package cn.it.shop.util;
  2. import java.io.BufferedReader;
  3. import java.io.InputStream;
  4. import java.io.InputStreamReader;
  5. import java.io.OutputStream;
  6. import java.io.UnsupportedEncodingException;
  7. import java.net.HttpURLConnection;
  8. import java.net.URL;
  9. import java.util.ArrayList;
  10. import java.util.Collections;
  11. import java.util.HashMap;
  12. import java.util.List;
  13. import java.util.Map;
  14. import org.apache.commons.codec.digest.DigestUtils;
  15. /**
  16. * @author
  17. * @version 创建时间:2017年1月17日 下午7:46:29 类说明
  18. */
  19. public class PayUtil {
  20. /**
  21. * 签名字符串
  22. * @param text需要签名的字符串
  23. * @param key 密钥
  24. * @param input_charset编码格式
  25. * @return 签名结果
  26. */
  27. public static String sign(String text, String key, String input_charset) {
  28. text = text + key;
  29. return DigestUtils.md5Hex(getContentBytes(text, input_charset));
  30. }
  31. /**
  32. * 签名字符串
  33. * @param text需要签名的字符串
  34. * @param sign 签名结果
  35. * @param key密钥
  36. * @param input_charset 编码格式
  37. * @return 签名结果
  38. */
  39. public static boolean verify(String text, String sign, String key, String input_charset) {
  40. text = text + key;
  41. String mysign = DigestUtils.md5Hex(getContentBytes(text, input_charset));
  42. if (mysign.equals(sign)) {
  43. return true;
  44. } else {
  45. return false;
  46. }
  47. }
  48. /**
  49. * @param content
  50. * @param charset
  51. * @return
  52. * @throws SignatureException
  53. * @throws UnsupportedEncodingException
  54. */
  55. public static byte[] getContentBytes(String content, String charset) {
  56. if (charset == null || "".equals(charset)) {
  57. return content.getBytes();
  58. }
  59. try {
  60. return content.getBytes(charset);
  61. } catch (UnsupportedEncodingException e) {
  62. throw new RuntimeException( "MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);
  63. }
  64. }
  65. /**
  66. * 生成6位或10位随机数 param codeLength(多少位)
  67. * @return
  68. */
  69. public static String createCode(int codeLength) {
  70. String code = "";
  71. for ( int i = 0; i < codeLength; i++) {
  72. code += ( int) (Math.random() * 9);
  73. }
  74. return code;
  75. }
  76. private static boolean isValidChar(char ch) {
  77. if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))
  78. return true;
  79. if ((ch >= 0x4e00 && ch <= 0x7fff) || (ch >= 0x8000 && ch <= 0x952f))
  80. return true; // 简体中文汉字编码
  81. return false;
  82. }
  83. /**
  84. * 除去数组中的空值和签名参数
  85. * @param sArray 签名参数组
  86. * @return 去掉空值与签名参数后的新签名参数组
  87. */
  88. public static Map paraFilter(Map sArray) {
  89. Map result = new HashMap();
  90. if (sArray == null || sArray.size() <= 0) {
  91. return result;
  92. }
  93. for (String key : sArray.keySet()) {
  94. String value = sArray.get(key);
  95. if (value == null || value.equals( "") || key.equalsIgnoreCase( "sign")
  96. || key.equalsIgnoreCase( "sign_type")) {
  97. continue;
  98. }
  99. result.put(key, value);
  100. }
  101. return result;
  102. }
  103. /**
  104. * 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
  105. * @param params 需要排序并参与字符拼接的参数组
  106. * @return 拼接后字符串
  107. */
  108. public static String createLinkString(Map params) {
  109. List keys = new ArrayList(params.keySet());
  110. Collections.sort(keys);
  111. String prestr = "";
  112. for ( int i = 0; i < keys.size(); i++) {
  113. String key = keys.get(i);
  114. String value = params.get(key);
  115. if (i == keys.size() - 1) { // 拼接时,不包括最后一个&字符
  116. prestr = prestr + key + "=" + value;
  117. } else {
  118. prestr = prestr + key + "=" + value + "&";
  119. }
  120. }
  121. return prestr;
  122. }
  123. /**
  124. *
  125. * @param requestUrl请求地址
  126. * @param requestMethod请求方法
  127. * @param outputStr参数
  128. */
  129. public static String httpRequest(String requestUrl,String requestMethod,String outputStr){
  130. // 创建SSLContext
  131. StringBuffer buffer= null;
  132. try{
  133. URL url = new URL(requestUrl);
  134. HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  135. conn.setRequestMethod(requestMethod);
  136. conn.setDoOutput( true);
  137. conn.setDoInput( true);
  138. conn.connect();
  139. //往服务器端写内容
  140. if( null !=outputStr){
  141. OutputStream os=conn.getOutputStream();
  142. os.write(outputStr.getBytes( "utf-8"));
  143. os.close();
  144. }
  145. // 读取服务器端返回的内容
  146. InputStream is = conn.getInputStream();
  147. InputStreamReader isr = new InputStreamReader(is, "utf-8");
  148. BufferedReader br = new BufferedReader(isr);
  149. buffer = new StringBuffer();
  150. String line = null;
  151. while ((line = br.readLine()) != null) {
  152. buffer.append(line);
  153. }
  154. } catch(Exception e){
  155. e.printStackTrace();
  156. }
  157. return buffer.toString();
  158. }
  159. public static String urlEncodeUTF8(String source){
  160. String result=source;
  161. try {
  162. result=java.net.URLEncoder.encode(source, "UTF-8");
  163. } catch (UnsupportedEncodingException e) {
  164. // TODO Auto-generated catch block
  165. e.printStackTrace();
  166. }
  167. return result;
  168. }
  169. }
UUIDHexGenerator 
  1. package cn.it.shop.util;
  2. import java.net.InetAddress;
  3. /**
  4. * @author
  5. * @version 创建时间:2017年1月17日 下午7:45:06 类说明
  6. */
  7. public class UUIDHexGenerator {
  8. private static String sep = "";
  9. private static final int IP;
  10. private static short counter = ( short) 0;
  11. private static final int JVM = ( int) (System.currentTimeMillis() >>>;
  12. private static UUIDHexGenerator uuidgen = new UUIDHexGenerator();
  13. static {
  14. int ipadd;
  15. try {
  16. ipadd = toInt(InetAddress.getLocalHost().getAddress());
  17. } catch (Exception e) {
  18. ipadd = 0;
  19. }
  20. IP = ipadd;
  21. }
  22. public static UUIDHexGenerator getInstance() {
  23. return uuidgen;
  24. }
  25. public static int toInt(byte[] bytes) {
  26. int result = 0;
  27. for ( int i = 0; i < 4; i++) {
  28. result = (result << - Byte.MIN_VALUE + ( int) bytes;
  29. }
  30. return result;
  31. }
  32. protected static String format(int intval) {
  33. String formatted = Integer.toHexString(intval);
  34. StringBuffer buf = new StringBuffer( "00000000");
  35. buf.replace( 8 - formatted.length(), 8, formatted);
  36. return buf.toString();
  37. }
  38. protected static String format(short shortval) {
  39. String formatted = Integer.toHexString(shortval);
  40. StringBuffer buf = new StringBuffer( "0000");
  41. buf.replace( 4 - formatted.length(), 4, formatted);
  42. return buf.toString();
  43. }
  44. protected static int getJVM() {
  45. return JVM;
  46. }
  47. protected synchronized static short getCount() {
  48. if (counter < 0) {
  49. counter = 0;
  50. }
  51. return counter++;
  52. }
  53. protected static int getIP() {
  54. return IP;
  55. }
  56. protected static short getHiTime() {
  57. return ( short) (System.currentTimeMillis() >>> 32);
  58. }
  59. protected static int getLoTime() {
  60. return ( int) System.currentTimeMillis();
  61. }
  62. public static String generate() {
  63. return new StringBuffer( 36).append(format(getIP())).append(sep).append(format(getJVM())).append(sep)
  64. .append(format(getHiTime())).append(sep).append(format(getLoTime())).append(sep)
  65. .append(format(getCount())).toString();
  66. }
  67. /**
  68. * @param args
  69. */
  70. public static void main(String[] args) {
  71. String id= "";
  72. UUIDHexGenerator uuid = UUIDHexGenerator.getInstance();
  73. /*
  74. for (int i = 0; i < 100; i++) {
  75. id = uuid.generate();
  76. }*/
  77. id = uuid.generate();
  78. System.out.println(id);
  79. }
  80. }





付源码:

链接:https://pan.baidu.com/s/1dFRVmiX 密码:dkx7

猜你喜欢

转载自blog.csdn.net/y19910825/article/details/80965676