java app微信支付接口_app微信支付java后台实现(spring mvc)

前言

由于项目需要做微信支付和支付宝支付,自己花时间研究了一下,也百度了很久,最

后发现百度上很多都讲得不是很详细,对于新手小白来说,还是比较难得,所以自己整理

了一下自己写的,也有很多是参考的,希望能给大家带来帮助

一 图示(乱画的,方便看)

java app微信支付接口_app微信支付java后台实现(spring mvc)_第1张图片

二 工具类准备

2.1由于微信支付发送的https的post请求,所以需要写个工具类来实现https的发送

发送https需要自定义一个TrustManager实现X509TrustManager类

package com.rubbish.jinzhu.utils;

import javax.net.ssl.X509TrustManager;

import java.security.cert.CertificateException;

import java.security.cert.X509Certificate;

public class TrustManager implements X509TrustManager {

@Override

public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

}

@Override

public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

}

@Override

public X509Certificate[] getAcceptedIssuers() {

return new X509Certificate[0];

}

}

发送https请求工具类

package com.rubbish.jinzhu.utils;

import javax.net.ssl.HttpsURLConnection;

import javax.net.ssl.SSLContext;

import javax.net.ssl.SSLSocketFactory;

import java.io.BufferedReader;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.io.OutputStream;

import java.net.URL;

public class HttpsUtil {

/**

*

* @param requestUrl

* @param requestMethod

* @param outputStr

* @return

* 发送https请求

*/

public static String httpsRequest(String requestUrl,String requestMethod,String outputStr){

StringBuffer buffer=null;

try{

SSLContext sslContext=SSLContext.getInstance("SSL");

TrustManager[] tm={new TrustManager()};

sslContext.init(null, tm, new java.security.SecureRandom());;

SSLSocketFactory ssf=sslContext.getSocketFactory();

URL url=new URL(requestUrl);

HttpsURLConnection conn=(HttpsURLConnection)url.openConnection();

conn.setDoOutput(true);

conn.setDoInput(true);

conn.setUseCaches(false);

conn.setRequestMethod(requestMethod);

conn.setSSLSocketFactory(ssf);

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();

}

}

2.2 微信统一下单需要的参数(接口文档地址https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1)

2.2.1 随机字符串生成,签名,xml转换工具类

package com.rubbish.jinzhu.utils;

import org.jdom.JDOMException;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.xml.sax.SAXException;

import javax.xml.parsers.ParserConfigurationException;

import java.io.IOException;

import java.util.Iterator;

import java.util.Map;

import java.util.Map.Entry;

import java.util.Random;

import java.util.SortedMap;

public class PayCommonUtil {

private static Logger logger = LoggerFactory.getLogger(PayCommonUtil.class);

/**

* 自定义长度随机字符串

* @param length

* @return

*/

public static String createConceStr(int length) {

String strs = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

String str = "";

for (int i = 0; i < length; i++) {

// str +=strs.substring(0, new Random().nextInt(strs.length()));

char achar = strs.charAt(new Random().nextInt(strs.length() - 1));

str += achar;

}

return str;

}

/**

* 默认16 位随机字符串

* @return

*/

public static String CreateNoncestr() {

String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

String res = "";

for (int i = 0; i < 16; i++) {

Random rd = new Random();

res += chars.charAt(rd.nextInt(chars.length() - 1));

}

return res;

}

/**

* 签名工具

* @date 2014-12-5下午2:29:34

* @Description:sign签名

* @param characterEncoding

* 编码格式 UTF-8

* @param parameters

* 请求参数

* @return

*/

public static String createSign(String characterEncoding,

Map parameters) {

StringBuffer sb = new StringBuffer();

Iterator> it = parameters.entrySet().iterator();

while (it.hasNext()) {

Entry entry = (Entry) it.next();

String key = (String) entry.getKey();

Object value = entry.getValue();//去掉带sign的项

if (null != value && !"".equals(value) && !"sign".equals(key)

&& !"key".equals(key)) {

sb.append(key + "=" + value + "&");

}

}

sb.append("key=" + ConfigUtil.API_KEY);

//注意sign转为大写

return MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();

}

/**

* @date

* @Description:将请求参数转换为xml格式的string

* @param parameters

* 请求参数

* @return

*/

public static String getRequestXml(SortedMap parameters) {

StringBuffer sb = new StringBuffer();

sb.append("");

Iterator> iterator = parameters.entrySet().iterator();

while (iterator.hasNext()) {

Entry entry = (Entry) iterator.next();

String key = (String) entry.getKey();

String value = (String) entry.getValue();

sb.append("" + value + "" + key + ">");

}

sb.append("");

return sb.toString();

}

public static String setXML(String return_code, String return_msg) {

return "

+ "]]>

+ "]]>

";

}

/**

* 检验API返回的数据里面的签名是否合法

*

* @param responseString API返回的XML数据字符串

* @return API签名是否合法

* @throws ParserConfigurationException

* @throws IOException

* @throws SAXException

*/

public static boolean checkIsSignValidFromResponseString(String responseString) {

try {

SortedMap map = XMLUtil.doXMLParse(responseString);

logger.debug(map.toString());

String signFromAPIResponse = map.get("sign").toString();

if ("".equals(signFromAPIResponse) || signFromAPIResponse == null) {

logger.debug("API返回的数据签名数据不存在,有可能被第三方篡改!!!");

return false;

}

logger.debug("服务器回包里面的签名是:" + signFromAPIResponse);

map.put("sign", "");

String signForAPIResponse = PayCommonUtil.createSign("UTF-8", map);

if (!signForAPIResponse.equals(signFromAPIResponse)) {

logger.debug("数据签名验证不通过");

return false;

}

logger.debug("恭喜,数据签名验证通过!!!");

return true;

} catch (Exception e) {

return false;

}

}

}

微信的一些固定参数

packagecom.rubbish.jinzhu.utils;public classConfigUtil {

/**

* 服务号相关信息

*/

public final static String APPID = "xxxxxxx";// 应用号

public final static String APP_SECRECT = "xxxxx";// 应用密码

public final static String MCH_ID = "xxxxx";// 商户号 xxxx 公众号商户id

public final static String API_KEY = "xxxxxx";// API密钥

public final static String SIGN_TYPE = "MD5";// 签名加密方式

public final static String TRADE_TYPE = "APP";// 支付类型

public final static String UNIFIED_ORDER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder"; // 微信支付统一接口(POST)

}

xml读取的工具类

packagecom.rubbish.jinzhu.utils;importorg.jdom.Document;importorg.jdom.Element;importorg.jdom.JDOMException;importorg.jdom.input.SAXBuilder;importjava.io.ByteArrayInputStream;importjava.io.IOException;importjava.io.InputStream;importjava.util.Iterator;importjava.util.List;importjava.util.SortedMap;importjava.util.TreeMap;public classXMLUtil {/*** 解析xml,返回第一级元素键值对。

* 如果第一级元素有子节点,

* 则此节点的值是子节点的xml数据。

*

*@paramstrxml

*@return*@throwsJDOMException

*@throwsIOException*/

public static SortedMapdoXMLParse(String strxml)throwsJDOMException, IOException {

strxml= strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");if (null == strxml || "".equals(strxml)) {return null;

}

SortedMap map = new TreeMap();

InputStream in= new ByteArrayInputStream(strxml.getBytes("UTF-8"));

SAXBuilder builder= newSAXBuilder();

Document doc=builder.build(in);

Element root=doc.getRootElement();

List list=root.getChildren();

Iterator it=list.iterator();while(it.hasNext()) {

Element e=(Element) it.next();

String key=e.getName();

String value= "";

List children=e.getChildren();if(children.isEmpty()) {

value=e.getTextNormalize();

}else{

value=XMLUtil.getChildrenText(children);

}

map.put(key, value);

}//关闭流

in.close();returnmap;

}/*** 获取子结点的xml

*@paramchildren

*@return

*/

public staticString getChildrenText(List children) {

StringBuffer sb= newStringBuffer();if (!children.isEmpty()) {

Iterator it=children.iterator();while(it.hasNext()) {

Element e=(Element) it.next();

String name=e.getName();

String value=e.getTextNormalize();

List list=e.getChildren();

sb.append("");if (!list.isEmpty()) {

sb.append(XMLUtil.getChildrenText(list));

}

sb.append(value);

sb.append("" + name + ">");

}

}returnsb.toString();

}

}

根据key值对map进行ascii排序

packagecom.rubbish.jinzhu.utils;import java.util.*;importjava.util.Map.Entry;public classMapUtils {/*** 对map根据key进行排序 ASCII 顺序

*

*@param无序的map

*@return

*/

public static SortedMap sortMap(Mapmap) {

List> infoIds = new ArrayList>(

map.entrySet());

Collections.sort(infoIds, new Comparator>() {public int compare(Entryo1,

Entryo2) {//return (o2.getValue() - o1.getValue());//value处理

return(o1.getKey()).toString().compareTo(o2.getKey());

}

});

SortedMap sortmap = new TreeMap();for (int i = 0; i < infoIds.size(); i++) {

String[] split= infoIds.get(i).toString().split("=");

sortmap.put(split[0], split[1]);

}returnsortmap;

}}

三  controller 类

packagecom.rubbish.jinzhu.controller;importcom.google.common.base.Charsets;importcom.google.common.base.Strings;importcom.google.common.collect.ImmutableMap;import com.rubbish.jinzhu.utils.*;import org.springframework.web.bind.annotation.*;importjava.io.UnsupportedEncodingException;importjava.net.InetAddress;importjava.net.UnknownHostException;importjava.util.Map;importjava.util.SortedMap;import staticcom.rubbish.jinzhu.utils.MapUtils.sortMap;

@RestControllerpublic classTradeController {@RequestMapping("/trade/prepare_pay")public SortedMappreparePay(@RequestParam String ip,

@RequestParam String tradeId,

@RequestParamintprice) {if(Strings.isNullOrEmpty(ip)) {try{

InetAddress addr=InetAddress.getLocalHost();

ip=addr.getHostAddress().toString();

}catch(UnknownHostException e) {

e.printStackTrace();

}

}

SortedMap parameters =prepareOrder(ip, tradeId, price);

parameters.put("sign", PayCommonUtil.createSign(Charsets.UTF_8.toString(), parameters));//sign签名 key

String requestXML = PayCommonUtil.getRequestXml(parameters);//生成xml格式字符串

String responseStr = HttpUtil.httpsRequest(ConfigUtil.UNIFIED_ORDER_URL, "POST", requestXML);try{

SortedMap resultMap =XMLUtil.doXMLParse(responseStr);

SortedMap map =buildClientJson(resultMap);returnmap;

}catch(Exception e) {

e.printStackTrace();return null;

}

}//预支付成功,返回给app的参数private SortedMapbuildClientJson(

Map resutlMap) throwsUnsupportedEncodingException {

Map params = ImmutableMap.builder()

.put("appid", ConfigUtil.APPID)//应用号

.put("noncestr", PayCommonUtil.CreateNoncestr())//随机字符串

.put("package", "Sign=WXPay")//固定的字符串,不需要改变

.put("partnerid", ConfigUtil.MCH_ID)//商户号

.put("prepayid", resutlMap.get("prepay_id"))//预支付微信返回的id

.put("timestamp", DateUtils.getTimeStamp()) //10 位时间戳

.build();

SortedMap sortMap =sortMap(params);

sortMap.put("package", "Sign=WXPay");

String paySign=PayCommonUtil.createSign(Charsets.UTF_8.toString(), sortMap);

sortMap.put("sign", paySign);returnsortMap;

}

//预支付参数准备private SortedMapprepareOrder(String ip, String tradeId,intprice) {

Map oparams = ImmutableMap.builder()

.put("appid", ConfigUtil.APPID)//应用号

.put("mch_id", ConfigUtil.MCH_ID)//商户号

.put("nonce_str", PayCommonUtil.CreateNoncestr())//16随机字符串(大小写字母加数字)

.put("body", "金株互联支付")//商品描述

.put("out_trade_no", tradeId)//商户订单号

.put("total_fee", price)

.put("spbill_create_ip", ip)//IP地址

.put("notify_url", "http://127.0.0.1:8082/api/trade/paid/wx") //微信回调地址

.put("trade_type", ConfigUtil.TRADE_TYPE)//支付类型 APP

.build();//支付金额

returnsortMap(oparams);

}privateString callback(String responseStr) {try{

Map map =XMLUtil.doXMLParse(responseStr);

if (!PayCommonUtil.checkIsSignValidFromResponseString(responseStr)) {return PayCommonUtil.setXML(WeixinConstant.FAIL, "invalid sign");

}if (WeixinConstant.FAIL.equalsIgnoreCase(map.get("result_code")

.toString())) {return PayCommonUtil.setXML(WeixinConstant.FAIL, "weixin pay fail");

}if (WeixinConstant.SUCCESS.equalsIgnoreCase(map.get("result_code")

.toString())) {//对数据库的操作

String outTradeNo = (String) map.get("out_trade_no");

String transactionId= (String) map.get("transaction_id");

String totlaFee= (String) map.get("total_fee");

Integer totalPrice= Integer.valueOf(totlaFee) / 100;//服务器这边记录的是钱的元

// Trade trade =tradeBiz.get(Integer.valueOf(outTradeNo));

// trade.setTransactionId(transactionId);

//boolean isOk =tradeBiz.paid(trade);

//if(isOk) {

//return PayCommonUtil.setXML(WeixinConstant.SUCCESS, "OK");

// }else{

//returnPayCommonUtil

// .setXML(WeixinConstant.FAIL,"update bussiness outTrade fail");

//}

}

}catch(Exception e) {returnPayCommonUtil.setXML(WeixinConstant.FAIL,"weixin pay server exception");

}return PayCommonUtil.setXML(WeixinConstant.FAIL, "weixin pay fail");

}

}

你可能感兴趣的:(java,app微信支付接口)