**
小程序代码
const APP_ID = '****************'; //输入小程序appid
const APP_SECRET = '********************'; //输入小程序app_secret
var OPEN_ID = '' //储存获取到openid
var SESSION_KEY = '' //储存获取到session_key
wxPay() {
var that = this;
wx.login({
success: function(res) {
wx.request({
//获取openid接口
url: 'https://api.weixin.qq.com/sns/jscode2session',
data: {
appid: APP_ID,
secret: APP_SECRET,
js_code: res.code,
grant_type: 'authorization_code'
},
method: 'GET',
success: function(res) {
OPEN_ID = res.data.openid; //获取到的openid
SESSION_KEY = res.data.session_key; //获取到session_key
wx.request({
url: BASE_URL + 'qrOrder/WXSmallProceduresPay',
data: {
openid: OPEN_ID,
session_key: SESSION_KEY,
mobile: ‘10086’,//手机号
commodityId: ‘1’,//商品id
commodityType:‘2’,//商品类型
},
success(res) {
wx.requestPayment({
'timeStamp': res.data.timeStamp,
'nonceStr': res.data.nonceStr,
'package': res.data.package,
'signType': 'MD5',
'paySign': res.data.paySign,
'success': function(res) {
wx.navigateTo({
url: 'msg_success',
})
},
'fail': function(res) {
wx.navigateTo({
url: 'msg_fail',
})
},
'complete': function(res) {}
})
}
})
}
})
}
})
}
java代码(暂时写在Controller里 - -)
/**
* 微信小程序支付
*/
@RequestMapping(value = "WXSmallProceduresPay")
@ResponseBody
@CrossOrigin
public Map<String,String> WXSmallProceduresPay(@RequestParam Map<String, Object> params, HttpServletRequest request){
String mobile=(String) params.get("mobile");
String commodityId=(String) params.get("commodityId");
String commodityType=(String) params.get("commodityType");
QrOrder qrOrderL=new QrOrder();
//获取订单信息
qrOrderL=qrOrderService.insertPrepayOrder(mobile,commodityId,commodityType);
Boolean b=qrOrderService.findOrderByUserIsBuy(qrOrderL);
if (b){
Map<String,String> map=new HashMap<>();
map.put("isBuy","true");
return map;
}
//小程序ID appid
String APPID = WXPayConstants.SmallAPPID;
//商户ID mch_id
String MERID = WXPayConstants.MERID;
//密钥
String SIGNKEY =WXPayConstants.SIGNKEY;
//appAPPSECRET
String APPSECRET=WXPayConstants.SmallAPPSECRET;
//获取ip地址
String spbill_create_ip = GetAddressByIp.getIpAddress(request);
//获取openId
String openId=(String) params.get("openid");
//支付方式
String tradeType = "JSAPI";
//虽然官方文档不是必须参数,但是不送有时候会验签失败
String MD5 = "MD5";
//商品主题
String body = "图书";
//金额转化为分为单位 微信支付以分为单位
BigDecimal fen=new BigDecimal("100");
String finalmoneys="";
BigDecimal finalmoney=qrOrderL.getTransactionAmount().multiply(fen).setScale(0);
finalmoneys=finalmoney.toString();
int randomNum = (int) (Math.random() * 1999+5000);
//我要获取当前的日期
Date date = new Date();
//设置要获取到什么样的时间
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//获取String类型的时间
String Time = sdf.format(date);
String out_trade_no = qrOrderService.generatorOrderNo();
//随机数
String nonce_str=WXPayUtil.generateNonceStr();
//获取回调地址
SignLetion ss = SignLetion.getInstance();
String notify_url= ss.getUrl();
if (notify_url==null || notify_url==""){
QrSystemConstantConfigure qsc= qrSystemConstantConfigureService.findConfigList();
notify_url=qsc.getSysParam9();
ss.setUrl(notify_url);
}
//签名数据
Map<String, String> map=new HashMap<>();
map.put("appid",APPID);
map.put("body",body);
map.put("mch_id",MERID);
map.put("nonce_str",nonce_str);
map.put("notify_url",notify_url);
map.put("out_trade_no",out_trade_no);
map.put("sign_type","MD5");
map.put("spbill_create_ip",spbill_create_ip);
map.put("total_fee",finalmoneys);
map.put("trade_type",tradeType);
map.put("openid",openId);
String sign="";
try {
sign =WXPayUtil.generateSignature(map,SIGNKEY);// "把sb.toString()做MD5操作并且toUpperCase()一下,至于怎么MD5,百度一下或者看官方文档";
}catch (Exception e){
logger.error("获取sign签名失败");
}
map.put("sign",sign);
logger.info(map.toString());
//封装xml报文
String xml="";
try {
xml=WXPayUtil.mapToXml(map);
}catch (Exception e){
logger.error("xml"+xml);
}
String URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";//微信统一下单接口
String res= httpRequestutil.sendPost(URL,xml);
Map<String,String> XTM;
String prepay_id=null;
try {
XTM=WXPayUtil.xmlToMap(res);
System.out.println("统一下单接口"+XTM);
prepay_id=XTM.get("prepay_id");
}catch (Exception e){
logger.error(prepay_id+"prepay_id",e);
}
Map<String,String> map1=new HashMap<>();
map1.put("appId",APPID);
map1.put("timeStamp",String.valueOf(WXPayUtil.getCurrentTimestamp()));
map1.put("nonceStr",WXPayUtil.generateNonceStr());
map1.put("signType","MD5");
map1.put("package", "prepay_id=".concat(prepay_id));
String paySign="";
try {
paySign=WXPayUtil.generateSignature(map1,SIGNKEY);
}catch (Exception e){
logger.error("paySign:"+paySign, e);
}
map1.put("paySign",paySign);
map1.put("prepay_id", prepay_id);
Date date1=new Date();
String time=sdf.format(date1);
qrOrderL.setNumber(out_trade_no);
qrOrderL.setCreateTime(sdf.format(new Date()));
qrOrderL.setState("0");
qrOrderL.setIp(GetAddressByIp.getIpAddress(request));
qrOrderL.setCreateTime(time);
qrOrderL.setTerminal(String.valueOf(params.get("terminal")));
qrOrderL.setTransactionMode("微信");
qrOrderService.insertOrder(qrOrderL);
return map1;
}
(一)微信支付工具类
package com.github.pig.admin.common.util;
import com.github.pig.admin.common.util.WXPayConstants.SignType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.StringWriter;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.*;
public class WXPayUtil {
private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final Random RANDOM = new SecureRandom();
/**
* XML格式字符串转换为Map
*
* @param strXML XML字符串
* @return XML数据转换后的Map
* @throws Exception
*/
public static Map<String, String> xmlToMap(String strXML) throws Exception {
try {
Map<String, String> data = new HashMap<String, String>();
DocumentBuilder documentBuilder = WXPayXmlUtil.newDocumentBuilder();
InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
org.w3c.dom.Document doc = documentBuilder.parse(stream);
doc.getDocumentElement().normalize();
NodeList nodeList = doc.getDocumentElement().getChildNodes();
for (int idx = 0; idx < nodeList.getLength(); ++idx) {
Node node = nodeList.item(idx);
if (node.getNodeType() == Node.ELEMENT_NODE) {
org.w3c.dom.Element element = (org.w3c.dom.Element) node;
data.put(element.getNodeName(), element.getTextContent());
}
}
try {
stream.close();
} catch (Exception ex) {
// do nothing
}
return data;
} catch (Exception ex) {
throw ex;
}
}
/**
* 将Map转换为XML格式的字符串
*
* @param data Map类型数据
* @return XML格式的字符串
* @throws Exception
*/
public static String mapToXml(Map<String, String> data) throws Exception {
org.w3c.dom.Document document = WXPayXmlUtil.newDocument();
org.w3c.dom.Element root = document.createElement("xml");
document.appendChild(root);
for (String key: data.keySet()) {
String value = data.get(key);
if (value == null) {
value = "";
}
value = value.trim();
org.w3c.dom.Element filed = document.createElement(key);
filed.appendChild(document.createTextNode(value));
root.appendChild(filed);
}
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
DOMSource source = new DOMSource(document);
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
transformer.transform(source, result);
String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", "");
try {
writer.close();
}
catch (Exception ex) {
}
return output;
}
/**
* 生成带有 sign 的 XML 格式字符串
*
* @param data Map类型数据
* @param key API密钥
* @return 含有sign字段的XML
*/
public static String generateSignedXml(final Map<String, String> data, String key) throws Exception {
return generateSignedXml(data, key, SignType.MD5);
}
/**
* 生成带有 sign 的 XML 格式字符串
*
* @param data Map类型数据
* @param key API密钥
* @param signType 签名类型
* @return 含有sign字段的XML
*/
public static String generateSignedXml(final Map<String, String> data, String key, SignType signType) throws Exception {
String sign = generateSignature(data, key, signType);
data.put(WXPayConstants.FIELD_SIGN, sign);
return mapToXml(data);
}
/**
* 判断签名是否正确
*
* @param xmlStr XML格式数据
* @param key API密钥
* @return 签名是否正确
* @throws Exception
*/
public static boolean isSignatureValid(String xmlStr, String key) throws Exception {
Map<String, String> data = xmlToMap(xmlStr);
if (!data.containsKey(WXPayConstants.FIELD_SIGN) ) {
return false;
}
String sign = data.get(WXPayConstants.FIELD_SIGN);
return generateSignature(data, key).equals(sign);
}
/**
* 判断签名是否正确,必须包含sign字段,否则返回false。使用MD5签名。
*
* @param data Map类型数据
* @param key API密钥
* @return 签名是否正确
* @throws Exception
*/
public static boolean isSignatureValid(Map<String, String> data, String key) throws Exception {
return isSignatureValid(data, key, SignType.MD5);
}
/**
* 判断签名是否正确,必须包含sign字段,否则返回false。
*
* @param data Map类型数据
* @param key API密钥
* @param signType 签名方式
* @return 签名是否正确
* @throws Exception
*/
public static boolean isSignatureValid(Map<String, String> data, String key, SignType signType) throws Exception {
if (!data.containsKey(WXPayConstants.FIELD_SIGN) ) {
return false;
}
String sign = data.get(WXPayConstants.FIELD_SIGN);
return generateSignature(data, key, signType).equals(sign);
}
/**
* 生成签名
*
* @param data 待签名数据
* @param key API密钥
* @return 签名
*/
public static String generateSignature(final Map<String, String> data, String key) throws Exception {
return generateSignature(data, key, SignType.MD5);
}
/**
* 生成签名. 注意,若含有sign_type字段,必须和signType参数保持一致。
*
* @param data 待签名数据
* @param key API密钥
* @param signType 签名方式
* @return 签名
*/
public static String generateSignature(final Map<String, String> data, String key, SignType signType) throws Exception {
Set<String> keySet = data.keySet();
String[] keyArray = keySet.toArray(new String[keySet.size()]);
Arrays.sort(keyArray);
StringBuilder sb = new StringBuilder();
for (String k : keyArray) {
if (k.equals(WXPayConstants.FIELD_SIGN)) {
continue;
}
if (data.get(k).trim().length() > 0) // 参数值为空,则不参与签名
sb.append(k).append("=").append(data.get(k).trim()).append("&");
}
sb.append("key=").append(key);
if (SignType.MD5.equals(signType)) {
return MD5(sb.toString()).toUpperCase();
}
else if (SignType.HMACSHA256.equals(signType)) {
return HMACSHA256(sb.toString(), key);
}
else {
throw new Exception(String.format("Invalid sign_type: %s", signType));
}
}
/**
* 获取随机字符串 Nonce Str
*
* @return String 随机字符串
*/
public static String generateNonceStr() {
char[] nonceChars = new char[32];
for (int index = 0; index < nonceChars.length; ++index) {
nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
}
return new String(nonceChars);
}
/**
* 生成 MD5
*
* @param data 待处理数据
* @return MD5结果
*/
public static String MD5(String data) throws Exception {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] array = md.digest(data.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (byte item : array) {
sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
}
return sb.toString().toUpperCase();
}
/**
* 生成 HMACSHA256
* @param data 待处理数据
* @param key 密钥
* @return 加密结果
* @throws Exception
*/
public static String HMACSHA256(String data, String key) throws Exception {
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
sha256_HMAC.init(secret_key);
byte[] array = sha256_HMAC.doFinal(data.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (byte item : array) {
sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
}
return sb.toString().toUpperCase();
}
/**
* 日志
* @return
*/
public static Logger getLogger() {
Logger logger = LoggerFactory.getLogger("wxpay java sdk");
return logger;
}
/**
* 获取当前时间戳,单位秒
* @return
*/
public static long getCurrentTimestamp() {
return System.currentTimeMillis()/1000;
}
/**
* 获取当前时间戳,单位毫秒
* @return
*/
public static long getCurrentTimestampMs() {
return System.currentTimeMillis();
}
/** auth:wtao *
* InputStream流转换成String字符串 *
* @param inStream InputStream流 *
* @param encoding 编码格式 *
* @return String字符串
*/
public static String inputStream2String(InputStream inStream, String encoding){
String result = null;
ByteArrayOutputStream outStream = null;
try {
if(inStream != null){
outStream = new ByteArrayOutputStream();
byte[] tempBytes = new byte[1024];
int count = 0;
while((count = inStream.read(tempBytes)) != -1){
outStream.write(tempBytes, 0, count);
}
tempBytes = null;
outStream.flush();
result = new String(outStream.toByteArray(), encoding);
outStream.close();
}
} catch (Exception e) {
result = null;
}
return result;
}
}
(二)微信支付工具类
package com.github.pig.admin.common.util;
import sun.net.www.http.HttpClient;
/**
* 常量
*/
public class WXPayConstants {
public enum SignType {
MD5, HMACSHA256
}
public static final String APPID = "***";
//小程序id
public static final String SmallAPPID = "***";
public static final String MERID = "***";
public static final String SIGNKEY ="***";
public static final String APPSECRET="****";
public static final String SmallAPPSECRET="***";
public static final String DOMAIN_API = "api.mch.weixin.qq.com";
public static final String DOMAIN_API2 = "api2.mch.weixin.qq.com";
public static final String DOMAIN_APIHK = "apihk.mch.weixin.qq.com";
public static final String DOMAIN_APIUS = "apius.mch.weixin.qq.com";
public static final String FAIL = "FAIL";
public static final String SUCCESS = "SUCCESS";
public static final String HMACSHA256 = "HMAC-SHA256";
public static final String MD5 = "MD5";
public static final String FIELD_SIGN = "sign";
public static final String FIELD_SIGN_TYPE = "sign_type";
public static final String WXPAYSDK_VERSION = "WXPaySDK/3.0.9";
public static final String USER_AGENT = WXPAYSDK_VERSION +
" (" + System.getProperty("os.arch") + " " + System.getProperty("os.name") + " " + System.getProperty("os.version") +
") Java/" + System.getProperty("java.version") + " HttpClient/" + HttpClient.class.getPackage().getImplementationVersion();
public static final String MICROPAY_URL_SUFFIX = "/pay/micropay";
public static final String UNIFIEDORDER_URL_SUFFIX = "/pay/unifiedorder";
public static final String ORDERQUERY_URL_SUFFIX = "/pay/orderquery";
public static final String REVERSE_URL_SUFFIX = "/secapi/pay/reverse";
public static final String CLOSEORDER_URL_SUFFIX = "/pay/closeorder";
public static final String REFUND_URL_SUFFIX = "/secapi/pay/refund";
public static final String REFUNDQUERY_URL_SUFFIX = "/pay/refundquery";
public static final String DOWNLOADBILL_URL_SUFFIX = "/pay/downloadbill";
public static final String REPORT_URL_SUFFIX = "/payitil/report";
public static final String SHORTURL_URL_SUFFIX = "/tools/shorturl";
public static final String AUTHCODETOOPENID_URL_SUFFIX = "/tools/authcodetoopenid";
// sandbox
public static final String SANDBOX_MICROPAY_URL_SUFFIX = "/sandboxnew/pay/micropay";
public static final String SANDBOX_UNIFIEDORDER_URL_SUFFIX = "/sandboxnew/pay/unifiedorder";
public static final String SANDBOX_ORDERQUERY_URL_SUFFIX = "/sandboxnew/pay/orderquery";
public static final String SANDBOX_REVERSE_URL_SUFFIX = "/sandboxnew/secapi/pay/reverse";
public static final String SANDBOX_CLOSEORDER_URL_SUFFIX = "/sandboxnew/pay/closeorder";
public static final String SANDBOX_REFUND_URL_SUFFIX = "/sandboxnew/secapi/pay/refund";
public static final String SANDBOX_REFUNDQUERY_URL_SUFFIX = "/sandboxnew/pay/refundquery";
public static final String SANDBOX_DOWNLOADBILL_URL_SUFFIX = "/sandboxnew/pay/downloadbill";
public static final String SANDBOX_REPORT_URL_SUFFIX = "/sandboxnew/payitil/report";
public static final String SANDBOX_SHORTURL_URL_SUFFIX = "/sandboxnew/tools/shorturl";
public static final String SANDBOX_AUTHCODETOOPENID_URL_SUFFIX = "/sandboxnew/tools/authcodetoopenid";
}
一整套都到这里为止了