一、微信APP支付接入商户服务中心

[申请流程指引] (https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419317780&token=84f23b4e9746c5963128711f225476cfd49ccf8c&lang=zh_CN)

二、开始开发

1、配置相关的配置信息

1.1、配置appid(Android)、mch_id(ios)、微信支付后的回调地址

sys.properties配置文件:
 
appid=wx***************1
mch_id=1********2
notify_url=http://6*.***.***.**/returnmsg.do 
 
//回调通知的地址,一定是要可以直接访问的地址

2、微信支付–下单

@ResponseBody
@RequestMapping(value = "/weixinpay.do", produces = "text/html;charset=UTF-8",method={RequestMethod.POST})
public static String weixinpay(String body, //商品描述
String detail, //商品详情
String attach, //附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据
String out_trade_no, //商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号
String total_price, //订单总金额,单位为分,详见支付金额
String spbill_create_ip //用户端实际ip
 
) throws Exception { 
 
WeixinConfigUtils config = new WeixinConfigUtils();
//参数组
String appid = config.appid;//微信开放平台审核通过的应用APPID
System.out.println("appid是:"+appid);
String mch_id = config.mch_id;
System.out.println("mch_id是:"+mch_id);
String nonce_str = RandCharsUtils.getRandomString(16);
System.out.println("随机字符串是:"+nonce_str);
 
 
body = body;//"测试微信支付0.01_2";
detail = detail;//"0.01_元测试开始";
//attach = attach;//"备用参数,先留着,后面会有用的";
//String out_trade_no = OrderUtil.getOrderNo();//"2015112500001000811017342394";
 
double totalfee =0;
try{
totalfee=Double.parseDouble(total_price);单位是分,即是0.01元
}catch (Exception e) {
totalfee=0;
}
int total_fee=(int) (totalfee*100);
spbill_create_ip = spbill_create_ip;//"127.0.0.1";
 
String time_start = RandCharsUtils.timeStart();
System.out.println(time_start);
String time_expire = RandCharsUtils.timeExpire();
System.out.println(time_expire);
String notify_url = config.notify_url;
System.out.println("notify_url是:"+notify_url);
String trade_type = "APP";
 
//参数:开始生成签名
SortedMap<Object,Object> parameters = new TreeMap<Object,Object>();
parameters.put("appid", appid);
parameters.put("mch_id", mch_id);
parameters.put("nonce_str", nonce_str);
parameters.put("body", body);
//parameters.put("nonce_str", nonce_str);
parameters.put("detail", detail);
parameters.put("attach", attach);
parameters.put("out_trade_no", out_trade_no);
parameters.put("total_fee", total_fee);
parameters.put("time_start", time_start);
parameters.put("time_expire", time_expire);
parameters.put("notify_url", notify_url);
parameters.put("trade_type", trade_type);
parameters.put("spbill_create_ip", spbill_create_ip);
 
String sign = WXSignUtils.createSign("UTF-8", parameters);
System.out.println("签名是:"+sign);
 
 
Unifiedorder unifiedorder = new Unifiedorder();
unifiedorder.setAppid(appid);
unifiedorder.setMch_id(mch_id);
unifiedorder.setNonce_str(nonce_str);
unifiedorder.setSign(sign);
unifiedorder.setBody(body);
unifiedorder.setDetail(detail);
unifiedorder.setAttach(attach);
unifiedorder.setOut_trade_no(out_trade_no);
unifiedorder.setTotal_fee(total_fee);
unifiedorder.setSpbill_create_ip(spbill_create_ip);
unifiedorder.setTime_start(time_start);
unifiedorder.setTime_expire(time_expire);
unifiedorder.setNotify_url(notify_url);
unifiedorder.setTrade_type(trade_type);
 
System.out.println(MD5Utils.md5("fenxiangzhuyi") + "========================");
 
//构造xml参数
String xmlInfo = HttpXmlUtils.xmlInfo(unifiedorder);
 
String wxUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder";
 
String method = "POST";
 
String weixinPost = HttpXmlUtils.httpsRequest(wxUrl, method, xmlInfo).toString();
 
System.out.println(weixinPost);
 
ParseXMLUtils.jdomParseXml(weixinPost);
 
 
 
String json = JsonUtil.xml2jsonString(weixinPost);
 
System.out.println("=========================================================");
 
Bean b = JsonUtil.getSingleBean(json, Bean.class);
if(null!=b){
WeixinOrder weixin = b.getXml();
//参数:开始生成签名
SortedMap<Object,Object> par = new TreeMap<Object,Object>();
par.put("appid", weixin.getAppid());
par.put("partnerid", weixin.getMch_id());
par.put("prepayid", weixin.getPrepay_id());
par.put("package", "Sign=WXPay");
par.put("noncestr", weixin.getNonce_str());
 
//时间戳
Date date = new Date();
long time = date.getTime();
//mysq 时间戳只有10位 要做处理
String dateline = time + "";
dateline = dateline.substring(0, 10);
 
par.put("timestamp", dateline);
 
String signnew = WXSignUtils.createSign("UTF-8", par);
System.out.println("再次签名是:"+signnew);
 
 
SetPay setPay = new SetPay();
 
setPay.setAppid(weixin.getAppid());
setPay.setPartnerid(weixin.getMch_id());
setPay.setPrepayid(weixin.getPrepay_id());
setPay.setNoncestr(weixin.getNonce_str());
 
setPay.setTimestamp(dateline);
setPay.setSign(signnew);
setPay.setPack("Sign=WXPay");
 
JSONObject js = JSONObject.fromObject(setPay);
StringBuilder msg = new StringBuilder();
msg.append("{\"code\":\"1\",");
msg.append("\"msg\":\"查询成功!\",");
msg.append("\"datas\":");
msg.append(js.toString());
msg.append("}");
 
System.out.println(js);
 
return msg.toString();
}
StringBuilder msg = new StringBuilder();
msg.append("{\"code\":\"1\",");
msg.append("\"msg\":\"查询成功!\",");
msg.append("\"datas\":");
msg.append("支付失败!");
msg.append("}");
 
 
return msg.toString();
 
}

2.1、微信支付签名算法sign

package com.wx.weixincontroller.pay.weixin.Utils;
 
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
 
import com.wx.weixin.utils.MD5Utils;
 
/**
* 微信支付签名
* @author iYjrg_xiebin
* @date 2016年10月25日下午4:47:07
*/
public class WXSignUtils {
//http://mch.weixin.qq.com/wiki/doc/api/index.php?chapter=4_3
//商户Key:改成公司申请的即可
//32位密码设置地址:http://www.sexauth.com/
 
private static String Key = "***cb**e**ef**c*e*d***e*fd***cb*";
 
/**
* 微信支付签名算法sign
* @param characterEncoding
* @param parameters
* @return
*/
@SuppressWarnings("rawtypes")
public static String createSign(String characterEncoding,SortedMap<Object,Object> parameters){
 
 
StringBuffer sb = new StringBuffer();
Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序(升序)
Iterator it = es.iterator();
while(it.hasNext()) {
Map.Entry entry = (Map.Entry)it.next();
String k = (String)entry.getKey();
Object v = entry.getValue();
if(null != v && !"".equals(v) 
&& !"sign".equals(k) && !"key".equals(k)) {
sb.append(k + "=" + v + "&");
}
}
sb.append("key=" + Key);
System.out.println("字符串拼接后是:"+sb.toString());
String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
return sign;
}
 
}

2.2、POST提交XML格式的参数

package com.wx.weixincontroller.pay.weixin.Utils;
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
 
import javax.net.ssl.HttpsURLConnection;
 
import com. com.wx.weixin.wxcontroller.pay.weixin.entity.Unifiedorder;
 
/**
* post提交xml格式的参数
* @author iYjrg_xiebin
* @date 2016年10月25日下午3:33:38
*/
public class HttpXmlUtils {
 
/**
* 开始post提交参数到接口
* 并接受返回
* @param url
* @param xml
* @param method
* @param contentType
* @return
*/
public static String xmlHttpProxy(String url,String xml,String method,String contentType){
InputStream is = null;
OutputStreamWriter os = null;
 
try {
URL _url = new URL(url);
HttpURLConnection conn = (HttpURLConnection) _url.openConnection();
conn.setDoInput(true);  
conn.setDoOutput(true);  
conn.setRequestProperty("Content-type", "text/xml");
conn.setRequestProperty("Pragma:", "no-cache"); 
conn.setRequestProperty("Cache-Control", "no-cache"); 
conn.setRequestMethod("POST");
os = new OutputStreamWriter(conn.getOutputStream());
os.write(new String(xml.getBytes(contentType)));
os.flush();
 
//返回值
is = conn.getInputStream();
return getContent(is, "utf-8");
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
try {
if(os!=null){os.close();}
if(is!=null){is.close();}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
 
/**
* 解析返回的值
* @param is
* @param charset
* @return
*/
public static String getContent(InputStream is, String charset) {
String pageString = null;
InputStreamReader isr = null;
BufferedReader br = null;
StringBuffer sb = null;
try {
isr = new InputStreamReader(is, charset);
br = new BufferedReader(isr);
sb = new StringBuffer();
String line = null;
while ((line = br.readLine()) != null) {
sb.append(line + "\n");
}
pageString = sb.toString();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (is != null){
is.close();
}
if(isr!=null){
isr.close();
}
if(br!=null){
br.close();
}
} catch (IOException e) {
e.printStackTrace();
}
sb = null;
}
return pageString;
}
 
/**
* 构造xml参数
* @param xml
* @return
*/
public static String xmlInfo(Unifiedorder unifiedorder){
//构造xml参数的时候,至少又是个必传参数
/*
* <xml>
<appid>wx2421b1c4370ec43b</appid>
<attach>支付测试</attach>
<body>JSAPI支付测试</body>
<mch_id>10000100</mch_id>
<nonce_str>1add1a30ac87aa2db72f57a2375d8fec</nonce_str>
<notify_url>http://wxpay.weixin.qq.com/pub_v2/pay/notify.v2.php</notify_url>
<openid>oUpF8uMuAJO_M2pxb1Q9zNjWeS6o</openid>
<out_trade_no>1415659990</out_trade_no>
<spbill_create_ip>14.23.150.211</spbill_create_ip>
<total_fee>1</total_fee>
<trade_type>JSAPI</trade_type>
<sign>0CB01533B8C1EF103065174F50BCA001</sign>
</xml>
*/
 
if(unifiedorder!=null){
StringBuffer bf = new StringBuffer();
bf.append("<xml>");
 
bf.append("<appid><![CDATA[");
bf.append(unifiedorder.getAppid());
bf.append("]]></appid>");
 
bf.append("<mch_id><![CDATA[");
bf.append(unifiedorder.getMch_id());
bf.append("]]></mch_id>");
 
bf.append("<nonce_str><![CDATA[");
bf.append(unifiedorder.getNonce_str());
bf.append("]]></nonce_str>");
 
bf.append("<sign><![CDATA[");
bf.append(unifiedorder.getSign());
bf.append("]]></sign>");
 
bf.append("<body><![CDATA[");
bf.append(unifiedorder.getBody());
bf.append("]]></body>");
 
bf.append("<detail><![CDATA[");
bf.append(unifiedorder.getDetail());
bf.append("]]></detail>");
 
bf.append("<attach><![CDATA[");
bf.append(unifiedorder.getAttach());
bf.append("]]></attach>");
 
bf.append("<out_trade_no><![CDATA[");
bf.append(unifiedorder.getOut_trade_no());
bf.append("]]></out_trade_no>");
 
bf.append("<total_fee><![CDATA[");
bf.append(unifiedorder.getTotal_fee());
bf.append("]]></total_fee>");
 
bf.append("<spbill_create_ip><![CDATA[");
bf.append(unifiedorder.getSpbill_create_ip());
bf.append("]]></spbill_create_ip>");
 
bf.append("<time_start><![CDATA[");
bf.append(unifiedorder.getTime_start());
bf.append("]]></time_start>");
 
bf.append("<time_expire><![CDATA[");
bf.append(unifiedorder.getTime_expire());
bf.append("]]></time_expire>");
 
bf.append("<notify_url><![CDATA[");
bf.append(unifiedorder.getNotify_url());
bf.append("]]></notify_url>");
 
bf.append("<trade_type><![CDATA[");
bf.append(unifiedorder.getTrade_type());
bf.append("]]></trade_type>");
 
 
bf.append("</xml>");
return bf.toString();
}
 
return "";
}
 
 
 
 
/**
* post请求并得到返回结果
* @param requestUrl
* @param requestMethod
* @param output
* @return
*/
public static String httpsRequest(String requestUrl, String requestMethod, String output) {
try{
URL url = new URL(requestUrl);
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setUseCaches(false);
connection.setRequestMethod(requestMethod);
if (null != output) {
OutputStream outputStream = connection.getOutputStream();
outputStream.write(output.getBytes("UTF-8"));
outputStream.close();
}
// 从输入流读取返回内容
InputStream inputStream = connection.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
StringBuffer buffer = new StringBuffer();
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
inputStream = null;
connection.disconnect();
return buffer.toString();
}catch(Exception ex){
ex.printStackTrace();
}
 
return "";
}
 
}

3、微信支付–回调通知业务处理

//通知处理类
@ResponseBody
@RequestMapping(value = "/returnmsg.do", produces = "text/html;charset=UTF-8",method={RequestMethod.POST})
public String returnmsg(HttpServletRequest request, HttpServletResponse response) throws Exception {
 
// 解析结果存储在HashMap
Map<String, String> map = new HashMap<String, String>();
InputStream inputStream = request.getInputStream();
 
// 读取输入流
SAXReader reader = new SAXReader();
Document document = reader.read(inputStream);
// 得到xml根元素
Element root = document.getRootElement();
// 得到根元素的所有子节点
List<Element> elementList = root.elements();
 
// 遍历所有子节点
for (Element e : elementList) {
map.put(e.getName(), e.getText());
}
 
JSONObject json = JSONObject.fromObject(map);
 
System.out.println("===消息通知的结果:" + json.toString() + "==========================");
System.out.println("===return_code===" + map.get("return_code"));
System.out.println("===return_msg===" + map.get("return_msg"));
System.out.println("===out_trade_no===" + map.get("out_trade_no"));
 
//验证签名的过程
 
//判断是否支付成功
if(map.get("return_code").equals("SUCCESS")) {
 
/**
*支付成功之后的业务处理
*/
 
// 释放资源
inputStream.close();
inputStream = null;
 
 
//bis.close();
return "SUCCESS";
}
 
}
if (map.get("return_code").equals("FAIL")) {
 
/**
*支付失败后的业务处理
*/
 
// 释放资源
inputStream.close();
 
inputStream = null;
 
return "SUCCESS";
}
 
 
}
 
// 释放资源
inputStream.close();
inputStream = null;
 
return "SUCCESS";
 
}

如有不足请指教.