第一步
进入小程序,下单,请求下单支付,调用小程序登录API来获取Openid(https://mp.weixin.qq.com/debug/w ... .html#wxloginobject),生成商户订单,这些都是在小程序端完成的业务。
小程序端代码
-
// pages/pay/pay.js
-
var app = getApp();
-
Page({
-
data: {},
-
onLoad: function (options) {
-
// 页面初始化 options为页面跳转所带来的参数
-
},
-
/* 微信支付 */
-
wxpay: function () {
-
var that = this
-
//登陆获取code
-
wx.login({
-
success: function (res) {
-
console.log(res.code)
-
//获取openid
-
that.getOpenId(res.code)
-
}
-
});
-
},
-
getOpenId: function (code) {
-
var that = this;
-
wx.request({
-
url: "https://api.weixin.qq.com/sns/jscode2session?appid=wxa142513e524e496c&secret=5d6a7d86048884e7c60f84f7aa85253c&js_code=" + code + "&grant_type=authorization_code",
-
data: {},
-
method: 'GET',
-
success: function (res) {
-
console.log( '返回openId')
-
console.log(res.data)
-
that.generateOrder(res.data.openid)
-
},
-
fail: function () {
-
// fail
-
},
-
complete: function () {
-
// complete
-
}
-
})
-
},
-
/**生成商户订单 */
-
generateOrder: function (openid) {
-
var that = this
-
//统一支付
-
wx.request({
-
url: 'http://localhost:8070/RMS/pay_pay.action',
-
method: 'GET',
-
data: {
-
total_fee: '5',
-
body: '支付测试',
-
attach: '真假酒水'
-
},
-
success: function (res) {
-
console.log(res)
-
var pay = res.data
-
//发起支付
-
var timeStamp = pay[ 0].timeStamp;
-
console.log( "timeStamp:"+timeStamp)
-
var packages = pay[ 0].package;
-
console.log( "package:"+packages)
-
var paySign = pay[ 0].paySign;
-
console.log( "paySign:"+paySign)
-
var nonceStr = pay[ 0].nonceStr;
-
console.log( "nonceStr:"+nonceStr)
-
var param = { "timeStamp": timeStamp, "package": packages, "paySign": paySign, "signType": "MD5", "nonceStr": nonceStr };
-
that.pay(param)
-
},
-
})
-
},
-
/* 支付 */
-
pay: function (param) {
-
console.log( "支付")
-
console.log(param)
-
wx.requestPayment({
-
timeStamp: param.timeStamp,
-
nonceStr: param.nonceStr,
-
package: param.package,
-
signType: param.signType,
-
paySign: param.paySign,
-
success: function (res) {
-
// success
-
console.log( "支付")
-
console.log(res)
-
wx.navigateBack({
-
delta: 1, // 回退前 delta(默认为1) 页面
-
success: function (res) {
-
wx.showToast({
-
title: '支付成功',
-
icon: 'success',
-
duration: 2000
-
})
-
},
-
fail: function () {
-
// fail
-
},
-
complete: function () {
-
// complete
-
}
-
})
-
},
-
fail: function (res) {
-
// fail
-
console.log( "支付失败")
-
console.log(res)
-
},
-
complete: function () {
-
// complete
-
console.log( "pay complete")
-
}
-
})
-
}
-
})
调用支付统一下单API来获取prepay_id,并将小程序调起支付数据需要签名的字段appId,timeStamp,nonceStr,package再次签名(https://pay.weixin.qq.com/wiki/d ... ter=7_7&index=3)
后台代码
-
package cn.it.shop.action;
-
import java.io.ByteArrayInputStream;
-
import java.io.InputStream;
-
import java.io.UnsupportedEncodingException;
-
import java.text.SimpleDateFormat;
-
import java.util.Date;
-
import java.util.HashMap;
-
import java.util.List;
-
import java.util.Map;
-
import org.dom4j.Document;
-
import org.dom4j.DocumentException;
-
import org.dom4j.Element;
-
import org.dom4j.io.SAXReader;
-
import cn.it.shop.util.MessageUtil;
-
import cn.it.shop.util.PayUtil;
-
import cn.it.shop.util.PaymentPo;
-
import cn.it.shop.util.UUIDHexGenerator;
-
import net.sf.json.JSONArray;
-
import net.sf.json.JSONObject;
-
/**
-
* @author
-
* @version 创建时间:2017年1月21日 下午4:59:03
-
* 小程序端请求的后台action,返回签名后的数据传到前台
-
*/
-
public class PayAction {
-
private String total_fee; //总金额
-
private String body; //商品描述
-
private String detail; //商品详情
-
private String attach; //附加数据
-
private String time_start; //交易起始时间
-
private String time_expire; //交易结束时间
-
private String openid; //用户标识
-
private JSONArray jsonArray= new JSONArray();
-
public String pay() throws UnsupportedEncodingException, DocumentException{
-
body = new String(body.getBytes( "UTF-8"), "ISO-8859-1");
-
String appid = "替换为自己的小程序ID"; //小程序ID
-
String mch_id = "替换为自己的商户号"; //商户号
-
String nonce_str = UUIDHexGenerator.generate(); //随机字符串
-
String today = new SimpleDateFormat( "yyyyMMddHHmmss").format( new Date());
-
String code = PayUtil.createCode( 8);
-
String out_trade_no = mch_id+today+code; //商户订单号
-
String spbill_create_ip = "替换为自己的终端IP"; //终端IP
-
String notify_url = "http://www.weixin.qq.com/wxpay/pay.php"; //通知地址
-
String trade_type = "JSAPI"; //交易类型
-
String openid= "替换为用户的openid"; //用户标识
-
/**/
-
PaymentPo paymentPo = new PaymentPo();
-
paymentPo.setAppid(appid);
-
paymentPo.setMch_id(mch_id);
-
paymentPo.setNonce_str(nonce_str);
-
String newbody=new String(body.getBytes("ISO-8859-1"),"UTF-8");//以utf-8编码放入paymentPo,微信支付要求字符编码统一采用UTF-8字符编码
-
paymentPo.setBody(newbody);
-
paymentPo.setOut_trade_no(out_trade_no);
-
paymentPo.setTotal_fee(total_fee);
-
paymentPo.setSpbill_create_ip(spbill_create_ip);
-
paymentPo.setNotify_url(notify_url);
-
paymentPo.setTrade_type(trade_type);
-
paymentPo.setOpenid(openid);
-
// 把请求参数打包成数组
-
Map sParaTemp = new HashMap();
-
sParaTemp.put("appid", paymentPo.getAppid());
-
sParaTemp.put("mch_id", paymentPo.getMch_id());
-
sParaTemp.put("nonce_str", paymentPo.getNonce_str());
-
sParaTemp.put("body", paymentPo.getBody());
-
sParaTemp.put("out_trade_no", paymentPo.getOut_trade_no());
-
sParaTemp.put("total_fee",paymentPo.getTotal_fee());
-
sParaTemp.put("spbill_create_ip", paymentPo.getSpbill_create_ip());
-
sParaTemp.put("notify_url",paymentPo.getNotify_url());
-
sParaTemp.put("trade_type", paymentPo.getTrade_type());
-
sParaTemp.put("openid", paymentPo.getOpenid());
-
// 除去数组中的空值和签名参数
-
Map sPara = PayUtil.paraFilter(sParaTemp);
-
String prestr = PayUtil.createLinkString(sPara); // 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
-
String key = "&key=替换为商户支付密钥"; // 商户支付密钥
-
//MD5运算生成签名
-
String mysign = PayUtil.sign(prestr, key, "utf-8").toUpperCase();
-
paymentPo.setSign(mysign);
-
//打包要发送的xml
-
String respXml = MessageUtil.messageToXML(paymentPo);
-
// 打印respXml发现,得到的xml中有“__”不对,应该替换成“_”
-
respXml = respXml.replace("__", "_");
-
String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";//统一下单API接口链接
-
String param = respXml;
-
//String result = SendRequestForUrl.sendRequest(url, param);//发起请求
-
String result =PayUtil.httpRequest(url, "POST", param);
-
// 将解析结果存储在HashMap中
-
Map map = new HashMap();
-
InputStream in=new ByteArrayInputStream(result.getBytes());
-
// 读取输入流
-
SAXReader reader = new SAXReader();
-
Document document = reader.read(in);
-
// 得到xml根元素
-
Element root = document.getRootElement();
-
// 得到根元素的所有子节点
-
@SuppressWarnings("unchecked")
-
List elementList = root.elements();
-
for (Element element : elementList) {
-
map.put(element.getName(), element.getText());
-
}
-
// 返回信息
-
String return_code = map.get("return_code");//返回状态码
-
String return_msg = map.get("return_msg");//返回信息
-
System.out.println("return_msg"+return_msg);
-
JSONObject JsonObject=new JSONObject() ;
-
if(return_code=="SUCCESS"||return_code.equals(return_code)){
-
// 业务结果
-
String prepay_id = map.get("prepay_id");//返回的预付单信息
-
String nonceStr=UUIDHexGenerator.generate();
-
JsonObject.put("nonceStr", nonceStr);
-
JsonObject.put("package", "prepay_id="+prepay_id);
-
Long timeStamp= System.currentTimeMillis()/1000;
-
JsonObject.put("timeStamp", timeStamp+"");
-
String stringSignTemp = "appId="+appid+"&nonceStr=" + nonceStr + "&package=prepay_id=" + prepay_id+ "&signType=MD5&timeStamp=" + timeStamp;
-
//再次签名
-
String paySign=PayUtil.sign(stringSignTemp, "&key=替换为自己的密钥", "utf-8").toUpperCase();
-
JsonObject.put("paySign", paySign);
-
jsonArray.add(JsonObject);
-
}
-
return "pay";
-
}
-
public String getTotal_fee() {
-
return total_fee;
-
}
-
public void setTotal_fee(String total_fee) {
-
this.total_fee = total_fee;
-
}
-
public String getBody() {
-
return body;
-
}
-
public void setBody(String body) {
-
this.body = body;
-
}
-
public JSONArray getJsonArray() {
-
return jsonArray;
-
}
-
public void setJsonArray(JSONArray jsonArray) {
-
this.jsonArray = jsonArray;
-
}
-
public String getDetail() {
-
return detail;
-
}
-
public void setDetail(String detail) {
-
this.detail = detail;
-
}
-
public String getAttach() {
-
return attach;
-
}
-
public void setAttach(String attach) {
-
this.attach = attach;
-
}
-
public String getTime_start() {
-
return time_start;
-
}
-
public void setTime_start(String time_start) {
-
this.time_start = time_start;
-
}
-
public String getTime_expire() {
-
return time_expire;
-
}
-
public void setTime_expire(String time_expire) {
-
this.time_expire = time_expire;
-
}
-
public String getOpenid() {
-
return openid;
-
}
-
public void setOpenid(String openid) {
-
this.openid = openid;
-
}
-
}
MessageUtil
-
package cn.it.shop.util;
-
import java.io.IOException;
-
import java.io.Writer;
-
import java.util.HashMap;
-
import java.util.List;
-
import javax.servlet.http.HttpServletRequest;
-
import org.dom4j.Document;
-
import org.dom4j.Element;
-
import org.dom4j.io.SAXReader;
-
import com.thoughtworks.xstream.XStream;
-
import com.thoughtworks.xstream.core.util.QuickWriter;
-
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
-
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
-
import com.thoughtworks.xstream.io.xml.XppDriver;
-
public class MessageUtil {
-
public static HashMap parseXML(HttpServletRequest request) throws Exception, IOException{
-
HashMap map= new HashMap();
-
// 通过IO获得Document
-
SAXReader reader = new SAXReader();
-
Document doc = reader.read(request.getInputStream());
-
//得到xml的根节点
-
Element root=doc.getRootElement();
-
recursiveParseXML(root,map);
-
return map;
-
}
-
private static void recursiveParseXML(Element root,HashMap map){
-
//得到根节点的子节点列表
-
List elementList=root.elements();
-
//判断有没有子元素列表
-
if(elementList.size()== 0){
-
map.put(root.getName(), root.getTextTrim());
-
}
-
else{
-
//遍历
-
for(Element e:elementList){
-
recursiveParseXML(e,map);
-
}
-
}
-
}
-
private static XStream xstream = new XStream( new XppDriver() {
-
public HierarchicalStreamWriter createWriter(Writer out) {
-
return new PrettyPrintWriter(out) {
-
// 对所有xml节点都增加CDATA标记
-
boolean cdata = true;
-
public void startNode(String name, Class clazz) {
-
super.startNode(name, clazz);
-
}
-
protected void writeText(QuickWriter writer, String text) {
-
if (cdata) {
-
writer.write( " writer.write(text);
-
writer.write("]]> ");
-
} else {
-
writer.write(text);
-
}
-
}
-
};
-
}
-
});
-
public static String messageToXML(PaymentPo paymentPo){
-
xstream.alias("xml ",PaymentPo.class);
-
return xstream.toXML(paymentPo);
-
}
-
}
-
package cn.it.shop.util;
-
/**
-
* @author
-
* @version 创建时间:2017年1月21日 下午4:20:52
-
* 类说明
-
*/
-
public class PaymentPo {
-
private String appid; //小程序ID
-
private String mch_id; //商户号
-
private String device_info; //设备号
-
private String nonce_str; //随机字符串
-
private String sign; //签名
-
private String body; //商品描述
-
private String detail; //商品详情
-
private String attach; //附加数据
-
private String out_trade_no; //商户订单号
-
private String fee_type; //货币类型
-
private String spbill_create_ip; //终端IP
-
private String time_start; //交易起始时间
-
private String time_expire; //交易结束时间
-
private String goods_tag; //商品标记
-
private String total_fee; //总金额
-
private String notify_url; //通知地址
-
private String trade_type; //交易类型
-
private String limit_pay; //指定支付方式
-
private String openid; //用户标识
-
set/get //省略
-
}
-
package cn.it.shop.util;
-
import java.io.BufferedReader;
-
import java.io.InputStream;
-
import java.io.InputStreamReader;
-
import java.io.OutputStream;
-
import java.io.UnsupportedEncodingException;
-
import java.net.HttpURLConnection;
-
import java.net.URL;
-
import java.util.ArrayList;
-
import java.util.Collections;
-
import java.util.HashMap;
-
import java.util.List;
-
import java.util.Map;
-
import org.apache.commons.codec.digest.DigestUtils;
-
/**
-
* @author
-
* @version 创建时间:2017年1月17日 下午7:46:29 类说明
-
*/
-
public class PayUtil {
-
/**
-
* 签名字符串
-
* @param text需要签名的字符串
-
* @param key 密钥
-
* @param input_charset编码格式
-
* @return 签名结果
-
*/
-
public static String sign(String text, String key, String input_charset) {
-
text = text + key;
-
return DigestUtils.md5Hex(getContentBytes(text, input_charset));
-
}
-
/**
-
* 签名字符串
-
* @param text需要签名的字符串
-
* @param sign 签名结果
-
* @param key密钥
-
* @param input_charset 编码格式
-
* @return 签名结果
-
*/
-
public static boolean verify(String text, String sign, String key, String input_charset) {
-
text = text + key;
-
String mysign = DigestUtils.md5Hex(getContentBytes(text, input_charset));
-
if (mysign.equals(sign)) {
-
return true;
-
} else {
-
return false;
-
}
-
}
-
/**
-
* @param content
-
* @param charset
-
* @return
-
* @throws SignatureException
-
* @throws UnsupportedEncodingException
-
*/
-
public static byte[] getContentBytes(String content, String charset) {
-
if (charset == null || "".equals(charset)) {
-
return content.getBytes();
-
}
-
try {
-
return content.getBytes(charset);
-
} catch (UnsupportedEncodingException e) {
-
throw new RuntimeException( "MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);
-
}
-
}
-
/**
-
* 生成6位或10位随机数 param codeLength(多少位)
-
* @return
-
*/
-
public static String createCode(int codeLength) {
-
String code = "";
-
for ( int i = 0; i < codeLength; i++) {
-
code += ( int) (Math.random() * 9);
-
}
-
return code;
-
}
-
private static boolean isValidChar(char ch) {
-
if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))
-
return true;
-
if ((ch >= 0x4e00 && ch <= 0x7fff) || (ch >= 0x8000 && ch <= 0x952f))
-
return true; // 简体中文汉字编码
-
return false;
-
}
-
/**
-
* 除去数组中的空值和签名参数
-
* @param sArray 签名参数组
-
* @return 去掉空值与签名参数后的新签名参数组
-
*/
-
public static Map paraFilter(Map sArray) {
-
Map result = new HashMap();
-
if (sArray == null || sArray.size() <= 0) {
-
return result;
-
}
-
for (String key : sArray.keySet()) {
-
String value = sArray.get(key);
-
if (value == null || value.equals( "") || key.equalsIgnoreCase( "sign")
-
|| key.equalsIgnoreCase( "sign_type")) {
-
continue;
-
}
-
result.put(key, value);
-
}
-
return result;
-
}
-
/**
-
* 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
-
* @param params 需要排序并参与字符拼接的参数组
-
* @return 拼接后字符串
-
*/
-
public static String createLinkString(Map params) {
-
List keys = new ArrayList(params.keySet());
-
Collections.sort(keys);
-
String prestr = "";
-
for ( int i = 0; i < keys.size(); i++) {
-
String key = keys.get(i);
-
String value = params.get(key);
-
if (i == keys.size() - 1) { // 拼接时,不包括最后一个&字符
-
prestr = prestr + key + "=" + value;
-
} else {
-
prestr = prestr + key + "=" + value + "&";
-
}
-
}
-
return prestr;
-
}
-
/**
-
*
-
* @param requestUrl请求地址
-
* @param requestMethod请求方法
-
* @param outputStr参数
-
*/
-
public static String httpRequest(String requestUrl,String requestMethod,String outputStr){
-
// 创建SSLContext
-
StringBuffer buffer= null;
-
try{
-
URL url = new URL(requestUrl);
-
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-
conn.setRequestMethod(requestMethod);
-
conn.setDoOutput( true);
-
conn.setDoInput( true);
-
conn.connect();
-
//往服务器端写内容
-
if( null !=outputStr){
-
OutputStream os=conn.getOutputStream();
-
os.write(outputStr.getBytes( "utf-8"));
-
os.close();
-
}
-
// 读取服务器端返回的内容
-
InputStream is = conn.getInputStream();
-
InputStreamReader isr = new InputStreamReader(is, "utf-8");
-
BufferedReader br = new BufferedReader(isr);
-
buffer = new StringBuffer();
-
String line = null;
-
while ((line = br.readLine()) != null) {
-
buffer.append(line);
-
}
-
} catch(Exception e){
-
e.printStackTrace();
-
}
-
return buffer.toString();
-
}
-
public static String urlEncodeUTF8(String source){
-
String result=source;
-
try {
-
result=java.net.URLEncoder.encode(source, "UTF-8");
-
} catch (UnsupportedEncodingException e) {
-
// TODO Auto-generated catch block
-
e.printStackTrace();
-
}
-
return result;
-
}
-
}
-
package cn.it.shop.util;
-
import java.net.InetAddress;
-
/**
-
* @author
-
* @version 创建时间:2017年1月17日 下午7:45:06 类说明
-
*/
-
public class UUIDHexGenerator {
-
private static String sep = "";
-
private static final int IP;
-
private static short counter = ( short) 0;
-
private static final int JVM = ( int) (System.currentTimeMillis() >>>;
-
private static UUIDHexGenerator uuidgen = new UUIDHexGenerator();
-
static {
-
int ipadd;
-
try {
-
ipadd = toInt(InetAddress.getLocalHost().getAddress());
-
} catch (Exception e) {
-
ipadd = 0;
-
}
-
IP = ipadd;
-
}
-
public static UUIDHexGenerator getInstance() {
-
return uuidgen;
-
}
-
public static int toInt(byte[] bytes) {
-
int result = 0;
-
for ( int i = 0; i < 4; i++) {
-
result = (result << - Byte.MIN_VALUE + ( int) bytes;
-
}
-
return result;
-
}
-
protected static String format(int intval) {
-
String formatted = Integer.toHexString(intval);
-
StringBuffer buf = new StringBuffer( "00000000");
-
buf.replace( 8 - formatted.length(), 8, formatted);
-
return buf.toString();
-
}
-
protected static String format(short shortval) {
-
String formatted = Integer.toHexString(shortval);
-
StringBuffer buf = new StringBuffer( "0000");
-
buf.replace( 4 - formatted.length(), 4, formatted);
-
return buf.toString();
-
}
-
protected static int getJVM() {
-
return JVM;
-
}
-
protected synchronized static short getCount() {
-
if (counter < 0) {
-
counter = 0;
-
}
-
return counter++;
-
}
-
protected static int getIP() {
-
return IP;
-
}
-
protected static short getHiTime() {
-
return ( short) (System.currentTimeMillis() >>> 32);
-
}
-
protected static int getLoTime() {
-
return ( int) System.currentTimeMillis();
-
}
-
public static String generate() {
-
return new StringBuffer( 36).append(format(getIP())).append(sep).append(format(getJVM())).append(sep)
-
.append(format(getHiTime())).append(sep).append(format(getLoTime())).append(sep)
-
.append(format(getCount())).toString();
-
}
-
/**
-
* @param args
-
*/
-
public static void main(String[] args) {
-
String id= "";
-
UUIDHexGenerator uuid = UUIDHexGenerator.getInstance();
-
/*
-
for (int i = 0; i < 100; i++) {
-
id = uuid.generate();
-
}*/
-
id = uuid.generate();
-
System.out.println(id);
-
}
-
}
付源码:
链接:https://pan.baidu.com/s/1dFRVmiX 密码:dkx7