最近在集成微信支付,不得不说微信文档就是坑,说的不明不白,还是支付宝简单,
流程:
1、客户端提交订单——》到(自己平台的)服务器,参数与服务端协商
2、服务端拿到请求订单信息——》参考微信统一下单接口——》把必须传的参数进行加密转XML传到微信服务器
3、如果签名正确,微信服务端会返回成功信息 ——》XML格式——》解析XML——》
拿到预支付交易会话标识(prepay_id)这个是关键
4、拿到交易会话ID后,进行二次签名 把下表数据按照第一次签名规范进行签名——》传到客户端
5、(注意)二次签名的随机字符串(noncestr)不要再次生成新的字符串,一定要是第一次签名传
微信服务器那个保持一至。(这点微信文档没有找到)
6、二次签名的数据就可以传到客户端——》客户端调用拿到数据就可以调用微信支付了
7、一定要是正式打包的apk才会有效果,否则不能调起微信支付,
8、微信开发平台设置好包名,以及应用签名就可以了
直接上代码
上面是调起微信支付关键代码,当然调用微信支付前一定要先注册到微信 建议放到onCreate中
再说下服务端 简单写的测试下,直接复制就能用,
/**
* Servlet implementation class PayHttpServlet
*/
@WebServlet("/PayHttpServlet")
public class PayHttpServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private String urlWx = "https://api.mch.weixin.qq.com/pay/unifiedorder";
private String postType = "POST";
private String result;
private int price100 = -1;
/**
* @see HttpServlet#HttpServlet()
*/
public PayHttpServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
// response.getWriter().append("Served at: ").append(request.getContextPath());
doPost(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
// 设置编码
response.setContentType("text/html;charset=utf-8");
request.setCharacterEncoding("utf-8");
String price = request.getParameter("price");
if (price == null || "".equals(price)) {
// 返回客户端数据
System.out.print("参数有误,金额不能为0");
return;
} else {
price100 = new BigDecimal(price).multiply(new BigDecimal(100)).intValue();
doconfig(request, response);
}
}
private void doconfig(HttpServletRequest request, HttpServletResponse response) {
// TODO Auto-generated method stub
Map<String, Object> resultMap = new HashMap<String, Object>();
SortedMap<String, Object> map = new TreeMap<>();
map.put("appid", PayCommonUtil.APPID);
map.put("mch_id", PayCommonUtil.MCH_ID);
map.put("nonce_str", PayCommonUtil.getRandomString(30));
// map.put("sign", value);
map.put("trade_type", "APP");
map.put("body", "APP测试支付");
map.put("out_trade_no", PayCommonUtil.getRandomString(15));
map.put("total_fee", String.valueOf(price100));
map.put("spbill_create_ip", "113.113.157.124");//ip地址
map.put("notify_url", "http://www.baidu.com");//异步通知地址
// 签名
String singA = PayCommonUtil.createSign("utf-8", map);
map.put("sign", singA);
// 请求封装
String urlData = PayCommonUtil.getRequestXml(map);
System.out.println("xml=" + "\n" + urlData);
// 调用下单接口,得到prepay_id预支付码,重新签名返回给app
String result = PayCommonUtil.httpsRequest(urlWx, postType, urlData);
// System.out.println("xml="+urlData);
System.out.println("resultXML=" + "\n" + result);
// 得到数据返回给app
try {
Map<String, Object> map2 = PayCommonUtil.doXMLParse(result);
SortedMap<String, Object> mapApp = new TreeMap<>();
mapApp.put("appid", PayCommonUtil.APPID);
mapApp.put("partnerid", PayCommonUtil.MCH_ID);
mapApp.put("prepayid", map2.get("prepay_id"));
mapApp.put("package", "Sign=WXPay");
mapApp.put("noncestr", map.get("nonce_str"));
System.out.println("nonce_str=="+map.get("nonce_str"));
// 时间戳
mapApp.put("timestamp",
String.valueOf(Long.parseLong(String.valueOf(System.currentTimeMillis()).substring(0, 10))));
String signAPP = PayCommonUtil.createSign("utf-8", mapApp);
mapApp.put("sign", signAPP);
mapApp.put("status", "1");
try {
String object = new Gson().toJson(mapApp);
JSONObject object2 = new JSONObject(object);
System.out.println("json=" + "\n" + object2);
// 返回客户端数据
PrintWriter out = response.getWriter();
out.write(object2.toString());
out.flush();
out.close();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("mapApp" + "\n" + mapApp);
} catch (JDOMException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class PayCommonUtil {
// 微信参数配置
public static String API_KEY = "";
public static String APPID = "";
public static String MCH_ID = "";
// 随机字符串生成
public static String getRandomString(int length) { // length表示生成字符串的长度
String base = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
Random random = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < length; i++) {
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
}
// 请求xml组装
public static String getRequestXml(SortedMap<String, Object> parameters) {
StringBuffer sb = new StringBuffer();
sb.append("<xml>");
Set es = parameters.entrySet();
Iterator it = es.iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String key = (String) entry.getKey();
String value = (String) entry.getValue();
if ("attach".equalsIgnoreCase(key) || "body".equalsIgnoreCase(key) || "sign".equalsIgnoreCase(key)) {
sb.append("<" + key + ">" + "<![CDATA[" + value + "]]></" + key + ">");
} else {
sb.append("<" + key + ">" + value + "</" + key + ">");
}
}
sb.append("</xml>");
return sb.toString();
}
/**
* 所有参数除sign外,按照ASCII码排序,
*/
public static String buildASCiiParams(Map<String, Object> params) {
StringBuffer stringBuffer = new StringBuffer();// 存放数据
// 按照ASCII码进行排序
Map<String, Object> sortMap = new TreeMap<String, Object>(params);
// 便利字典,拼接"key=value&key=value"
for (Map.Entry<String, Object> m : sortMap.entrySet()) {
if (stringBuffer.length() > 0) {
stringBuffer.append("&");
}
stringBuffer.append(m.getKey()).append("=").append(m.getValue());
}
return stringBuffer.toString();
}
// 生成签名
public static String createSign(String characterEncoding, SortedMap<String, Object> parameters) {
StringBuffer sb = new StringBuffer();
Set es = parameters.entrySet();
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=" + API_KEY);
String sign = MD5Utils.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
return sign;
}
// 请求方法
public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {
try {
URL url = new URL(requestUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
// 设置请求方式(GET/POST)
conn.setRequestMethod(requestMethod);
conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
// 当outputStr不为null时向输出流写数据
if (null != outputStr) {
OutputStream outputStream = (OutputStream) conn.getOutputStream();
// 注意编码格式
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
// 从输入流读取返回内容
InputStream inputStream = (InputStream) conn.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;
conn.disconnect();
return buffer.toString();
} catch (ConnectException ce) {
System.out.println("连接超时:{}" + ce);
} catch (Exception e) {
System.out.println("https请求异常:{}" + e);
}
return null;
}
// xml解析
public static Map doXMLParse(String strxml) throws JDOMException, IOException {
strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");
if (null == strxml || "".equals(strxml)) {
return null;
}
Map m = new HashMap();
InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
SAXBuilder builder = new SAXBuilder();
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 k = e.getName();
String v = "";
List children = e.getChildren();
if (children.isEmpty()) {
v = e.getTextNormalize();
} else {
v = getChildrenText(children);
}
m.put(k, v);
}
// 关闭流
in.close();
return m;
}
public static String getChildrenText(List children) {
StringBuffer sb = new StringBuffer();
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("<" + name + ">");
if (!list.isEmpty()) {
sb.append(getChildrenText(list));
}
sb.append(value);
sb.append("</" + name + ">");
}
}
return sb.toString();
}
}