微信支付接口
方法1>>>>>>>>>>>>>>>>>>>>
public Map UnifiedOrder(String prepayId)throws Exception {
String appid =wxParameter.getAppid();
Date time =new Date();
String timeStamp = String.valueOf(time.getTime() /1000);
String SYMBOLS ="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
Random RANDOM =new SecureRandom();
char[] nonceChars =new char[32];
for (int index =0; index < nonceChars.length; ++index) {
nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
}
String nonce =new String(nonceChars);
String signType ="MD5";
Map map =new HashMap<>();
map.put("appId", appid);
map.put("timeStamp", timeStamp);
map.put("nonceStr", nonce);
map.put("package", "prepay_id=" + prepayId);
map.put("signType", signType);
String paySign = WXPayUtil.generateSignature(map, wxParameter.getApikey());
map.put("paySign", paySign);
return map;
}
方法二>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
public String getprepay_id(BigDecimal price, String str, String openid, String notify_url)throws Exception {
String appid =wxParameter.getAppid();
String mch_id =wxParameter.getMchid();
String SYMBOLS ="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
Random RANDOM =new SecureRandom();
char[] nonceChars =new char[32];
for (int index =0; index < nonceChars.length; ++index) {
nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
}
String nonce_str =new String(nonceChars);//随机字符串
String body ="充值";
String out_trade_no = str;//商品订单号
String total_fee = price.stripTrailingZeros().toPlainString();
String spbill_create_ip ="127.0.0.1";
String trade_type ="JSAPI";
// String notify_url = wxParameter.getDomain() + "/api/back/payment";
// notify_url= "https://www.yixiaodui.cn/api/back/payment";
// notify_url= "http://frp.pooke.net/xiadan/back/twoPay";
Map map =new HashMap<>();
map.put("appid", appid);
map.put("mch_id", mch_id);
map.put("nonce_str", nonce_str);
map.put("body", body);
map.put("out_trade_no", out_trade_no);
map.put("total_fee", total_fee);
map.put("spbill_create_ip", spbill_create_ip);
map.put("trade_type", trade_type);
map.put("notify_url", notify_url);
map.put("attach",这个参数是商品附加信息,需要可以传递value)
map.put("openid", openid);
String sign = WXPayUtil.generateSignature(map, wxParameter.getApikey());
map.put("sign", sign);
// 获取公众号prepay_id的链接
String prepayIdUrl ="https://api.mch.weixin.qq.com/pay/unifiedorder";
String xml = WXPayUtil.mapToXml(map);
String post =doPost(prepayIdUrl, xml);
Map stringMap = WXPayUtil.xmlToMap(post);
// 如果请求成功
if (null != post) {
try {
return stringMap.get("prepay_id");
}catch (JSONException e) {
}
}else {
System.out.println("未获取到prepay_id");
}
return null;
}
>>>>>>>>>>>>>>>use>>>>>>>>>>>>>>>>>>>>>>>
调用方法1,*************
price:需要支付的价格; str 随机字符串(订单号) ; ----随机字符串不重复,可以用时间戳拼接随机数
openid:商户openid; notify_url:支付回调地址.
String prepayId = getprepay_id(price, str, user.getOpen_id(), "https://cocoondance.hnbjx.net.cn/order_room/back/pay");
调用方法2,获得传递给前端的map
Map map = UnifiedOrder(prepayId);
接下来,可以在数据库中插入一个未支付的订单号,然后在回调中修改支付状态!!!
支付回调接口
@RequestMapping("back/pay")
@ResponseBody
public StringbackPay(HttpServletRequest request, HttpServletResponse response)throws Exception {
BufferedReader br =new BufferedReader(new InputStreamReader((ServletInputStream) request.getInputStream()));
String line =null;
StringBuilder sb =new StringBuilder();
while ((line = br.readLine()) !=null) {
sb.append(line);
}
br.close();
//sb为微信返回的xml
String notityXml = sb.toString();
String resXml ="";
//转为map
Map map = WXPayUtil.xmlToMap(notityXml);
String returnCode = map.get("return_code");
if ("SUCCESS".equals(returnCode)) {
if (WXPayUtil.isSignatureValid(WXPayUtil.mapToXml(map), wxParameter.getApikey())) {
// 回调,处理订单需要的逻辑这里直接在service中处理了
****************************************************
order_roomService.backpay(map);
**************************************************88
resXml ="<xml>" +""
+"<return_msg><![CDATA[OK]]></return_msg>" +"</xml> ";
}
}else {
resXml ="<xml>" +""
+"<return_msg><![CDATA[报文为空]]></return_msg>" +"</xml> ";
}
BufferedOutputStream out =new BufferedOutputStream(response.getOutputStream());
out.write(resXml.getBytes());
out.flush();
out.close();
return resXml;
}
使用到的工具类1
import com.ijpay.core.enums.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.InputStream;
import java.io.StringWriter;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.*;
public class WXPayUtil {
private static final StringSYMBOLS ="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final RandomRANDOM =new SecureRandom();
/**
* XML格式字符串转换为Map
*
* @param strXML XML字符串
* @return XML数据转换后的Map
* @throws Exception
*/
public static MapxmlToMap(String strXML)throws Exception {
try {
Map data =new HashMap();
DocumentBuilder documentBuilder = com.bjx.sdk.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) {
WXPayUtil.getLogger().warn("Invalid XML, can not convert to map. Error message: {}. XML content: {}", ex.getMessage(), strXML);
throw ex;
}
}
/**
* 将Map转换为XML格式的字符串
*
* @param data Map类型数据
* @return XML格式的字符串
* @throws Exception
*/
public static StringmapToXml(Map 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;
}
/**
* 将Map转换为XML格式的字符串
*
* @param data Map类型数据
* @return XML格式的字符串
* @throws Exception
*/
public static StringmapToXml2(Map 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 StringgenerateSignedXml(final Map 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 StringgenerateSignedXml(final Map 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 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 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 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 StringgenerateSignature(final Map data, String key)throws Exception {
return generateSignature(data, key, SignType.MD5);
}
/**
* 生成签名. 注意,若含有sign_type字段,必须和signType参数保持一致。
*
* @param data 待签名数据
* @param key API密钥
* @param signType 签名方式
* @return 签名
*/
public static StringgenerateSignature(final Map data, String key, SignType signType)throws Exception {
Set 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 StringgenerateNonceStr() {
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 StringMD5(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 StringHMACSHA256(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 LoggergetLogger() {
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();
}
}
工具类2
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Data
@Component
public class WxParameter {
@Value("${wx.miniapp.appid}")
private StringAppid;
@Value("${wx.miniapp.appsecret}")
private StringAppsecret;
@Value("${wx.mchid}")
private Stringmchid;
@Value("${wx.apikey}")
private Stringapikey;
}