Java开发微信支付流程及容易入坑的点
本人琢磨微信支付好幾天了,終于完成了,下面是開發(fā)微信支付的流程:
1.先要有認(rèn)證后的微信服務(wù)號,然后申請開通微信支付功能,通過之后,騰訊會跟你發(fā)一封郵件,如下圖:
?2.配置好微信支付的支付授權(quán)目錄(配置錯誤,支付時微信會返回:http://ki.hdh.com/kjjk/jh未注冊錯誤)
3.我們要參照微信傳的參數(shù),如下圖:
4.生成prepay_id(在WeiXinUtils工具類里)
String getPrepayId = WeiXinUtils.getPayOrderByWeiXin(openid,String.valueOf(sumPrice*100),userIp,url,body,num+timeStamp);
?
?public static String getPayOrderByWeiXin(String opentId, String total_fee, String userIp, String notifyUrl, String body, String orderNumber) {
SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
parameters.put("appid", APP_ID);
System.out.println("appid:"+APP_ID);
parameters.put("mch_id", MCH_ID);
System.out.println("mch_id:"+MCH_ID);
parameters.put("nonce_str", nonceStr);
System.out.println("nonce_str:"+"HZNAONAOCOM");
parameters.put("body", body);
System.out.println("body:"+body);
parameters.put("out_trade_no", orderNumber);
System.out.println("out_trade_no:"+orderNumber);
parameters.put("total_fee", total_fee.substring(0, total_fee.indexOf(".")));
System.out.println("total_fee="+total_fee.substring(0, total_fee.indexOf(".")));
parameters.put("spbill_create_ip", userIp);
System.out.println("spbill_create_ip="+userIp);
parameters.put("notify_url",notifyUrl );
System.out.println("notify_url="+notifyUrl);
parameters.put("trade_type", "JSAPI");
System.out.println("trade_type=JSAPI");
parameters.put("openid", opentId);
System.out.println("openid="+opentId);
String sign = Sign.createSign("UTF-8", parameters);
System.out.println("sign="+sign);
parameters.put("sign", sign);
String requestXML = Utils.getRequestXml(parameters);
System.out.println("requestXML="+requestXML);
String result = PostRequest.httpsRequest(unifiedOrder, "POST", requestXML);
System.out.println("prepay_id="+result);
return getPrepayId(result);
}
?
5.工具類
?
?package com.naonao.cmall.utils;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.UUID;
import org.springframework.cache.annotation.Cacheable;
import com.naonao.cmall.utils.http.HttpClient;
public class Sign {
@Cacheable(value="baseCache")
public static String getToken() {
String s = HttpClient.sendGet(
"https://api.weixin.qq.com/cgi-bin/token",
"grant_type=client_credential&appid=" + WeiXinUtils.APP_ID
+ "&secret=" + WeiXinUtils.APP_SECRET);
HashMap<String, Object> json = JsonUtil.stringToTObj(s, HashMap.class);
String token = json.get("access_token").toString();
return token;
}
@Cacheable(value="baseCache")
public static String getTicket() {
String token = Sign.getToken();
String s1 = HttpClient.sendGet(
"https://api.weixin.qq.com/cgi-bin/ticket/getticket",
"access_token=" + token + "&type=jsapi");
HashMap<String, Object> json1 = JsonUtil
.stringToTObj(s1, HashMap.class);
return json1.get("ticket").toString();
}
public static String getNonceStr() {
return create_timestamp();
}
//chatSet SHA-1 or MD5
public static Map<String, String> sign(String url, String chatSet) {
Map<String, String> ret = new HashMap<String, String>();
String nonce_str = create_nonce_str();
String timestamp = create_timestamp();
String string1;
String signature = "";
String jsapi_ticket = getTicket();
// 注意這里參數(shù)名必須全部小寫,且必須有序
string1 = "jsapi_ticket=" + jsapi_ticket + "&noncestr=" + nonce_str
+ "×tamp=" + timestamp + "&url=" + url;
// System.out.println(string1);
try {
MessageDigest crypt = MessageDigest.getInstance(chatSet);
crypt.reset();
crypt.update(string1.getBytes("UTF-8"));
signature = byteToHex(crypt.digest());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
ret.put("url", url);
ret.put("jsapi_ticket", jsapi_ticket);
ret.put("nonceStr", nonce_str);
ret.put("timestamp", timestamp);
ret.put("signature", signature);
for (Map.Entry entry : ret.entrySet()) {
System.out.println(entry.getKey() + ", " + entry.getValue());
}
return ret;
}
private static String byteToHex(final byte[] hash) {
Formatter formatter = new Formatter();
for (byte b : hash) {
formatter.format("%02x", b);
}
String result = formatter.toString();
formatter.close();
return result;
}
private static String create_nonce_str() {
return UUID.randomUUID().toString();
}
private static String create_timestamp() {
return Long.toString(System.currentTimeMillis() / 1000);
}
public static String createSign(String characterEncoding, SortedMap<Object, 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=" + WeiXinUtils.APP_KEY);
String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
return sign;
}
public static String paySign(String characterEncoding, SortedMap<Object, 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.replace(sb.length()-1, sb.length(), "?");
sb.append("key=" + WeiXinUtils.APP_KEY);
//sb.append("params=value");
System.out.println(sb);
String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
return sign;
}
}
package com.naonao.cmall.utils;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.SortedMap;
import javax.servlet.http.HttpServletRequest;
public class Utils {
// MD5加密
public static String getMd5(String plainText) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(plainText.getBytes());
byte b[] = md.digest();
int i;
StringBuffer buf = new StringBuffer("");
for (int offset = 0; offset < b.length; offset++) {
i = b[offset];
if (i < 0)
i += 256;
if (i < 16)
buf.append("0");
buf.append(Integer.toHexString(i));
}
// 32
return buf.toString();
// 16
// return buf.toString().substring(8, 24);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
public static String getRemortIP(HttpServletRequest request) {
if (request.getHeader("x-forwarded-for") == null) {
return request.getRemoteAddr();
}
return request.getHeader("x-forwarded-for");
}
public static String encode(String str) {
try {
return java.net.URLEncoder.encode(str, "UTF-8");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return str;
}
public static String getRequestXml(SortedMap<Object, 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 k = (String) entry.getKey();
String v = (String) entry.getValue();
if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k)
|| "sign".equalsIgnoreCase(k)) {
sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");
} else {
sb.append("<" + k + ">" + v + "</" + k + ">");
}
}
sb.append("</xml>");
return sb.toString();
}
public static String getOutTradeNo(Integer userId, Integer shopId) {
return userId + "c" + shopId + "c" + (new Date()).getTime();
}
/**
* 利用反射實現(xiàn)對象之間屬性復(fù)制
*
* @param from
* @param to
*/
public static void copyProperties(Object from, Object to) throws Exception {
copyPropertiesExclude(from, to, null);
}
/**
* 復(fù)制對象屬性
*
* @param from
* @param to
* @param excludsArray
* 排除屬性列表
* @throws Exception
*/
public static void copyPropertiesExclude(Object from, Object to,
String[] excludsArray) throws Exception {
List<String> excludesList = null;
if (excludsArray != null && excludsArray.length > 0) {
excludesList = Arrays.asList(excludsArray); // 構(gòu)造列表對象
}
Method[] fromMethods = from.getClass().getDeclaredMethods();
Method[] toMethods = to.getClass().getDeclaredMethods();
Method fromMethod = null, toMethod = null;
String fromMethodName = null, toMethodName = null;
for (int i = 0; i < fromMethods.length; i++) {
fromMethod = fromMethods[i];
fromMethodName = fromMethod.getName();
if (!fromMethodName.contains("get"))
continue;
// 排除列表檢測
if (excludesList != null
&& excludesList.contains(fromMethodName.substring(3)
.toLowerCase())) {
continue;
}
toMethodName = "set" + fromMethodName.substring(3);
toMethod = findMethodByName(toMethods, toMethodName);
if (toMethod == null)
continue;
Object value = fromMethod.invoke(from, new Object[0]);
if (value == null)
continue;
// 集合類判空處理
if (value instanceof Collection) {
Collection newValue = (Collection) value;
if (newValue.size() <= 0)
continue;
}
toMethod.invoke(to, new Object[] { value });
}
}
/**
* 對象屬性值復(fù)制,僅復(fù)制指定名稱的屬性值
*
* @param from
* @param to
* @param includsArray
* @throws Exception
*/
public static void copyPropertiesInclude(Object from, Object to,
String[] includsArray) throws Exception {
List<String> includesList = null;
if (includsArray != null && includsArray.length > 0) {
includesList = Arrays.asList(includsArray); // 構(gòu)造列表對象
} else {
return;
}
Method[] fromMethods = from.getClass().getDeclaredMethods();
Method[] toMethods = to.getClass().getDeclaredMethods();
Method fromMethod = null, toMethod = null;
String fromMethodName = null, toMethodName = null;
for (int i = 0; i < fromMethods.length; i++) {
fromMethod = fromMethods[i];
fromMethodName = fromMethod.getName();
if (!fromMethodName.contains("get"))
continue;
// 排除列表檢測
String str = fromMethodName.substring(3);
if (!includesList.contains(str.substring(0, 1).toLowerCase()
+ str.substring(1))) {
continue;
}
toMethodName = "set" + fromMethodName.substring(3);
toMethod = findMethodByName(toMethods, toMethodName);
if (toMethod == null)
continue;
Object value = fromMethod.invoke(from, new Object[0]);
if (value == null)
continue;
// 集合類判空處理
if (value instanceof Collection) {
Collection newValue = (Collection) value;
if (newValue.size() <= 0)
continue;
}
toMethod.invoke(to, new Object[] { value });
}
}
/**
* 從方法數(shù)組中獲取指定名稱的方法
*
* @param methods
* @param name
* @return
*/
public static Method findMethodByName(Method[] methods, String name) {
for (int j = 0; j < methods.length; j++) {
if (methods[j].getName().equals(name))
return methods[j];
}
return null;
}
/**
* map 轉(zhuǎn) Bean
*
* @param map
* @param cls
* @return
*/
public static Object map2Bean(Map map, Class cls) {
Object obj = null;
try {
obj = cls.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
// 取出bean里的所有方法
Method[] methods = cls.getMethods();
for (int i = 0; i < methods.length; i++) {
// 取方法名
String method = methods[i].getName();
// 取出方法的類型
Class[] cc = methods[i].getParameterTypes();
if (cc.length != 1)
continue;
// 如果方法名沒有以set開頭的則退出本次for
if (method.indexOf("set") < 0)
continue;
// 類型
String type = cc[0].getSimpleName();
try {
// 轉(zhuǎn)成小寫
// Object value = method.substring(3).toLowerCase();
Object value = method.substring(3, 4).toLowerCase()
+ method.substring(4);
// 如果map里有該key
if (map.containsKey(value) && map.get(value) != null) {
// 調(diào)用其底層方法
setValue(type, map.get(value), i, methods, obj);
}
} catch (Exception e) {
e.printStackTrace();
}
}
return obj;
}
/**
* 調(diào)用底層方法設(shè)置值
*/
private static void setValue(String type, Object value, int i,
Method[] method, Object bean) {
if (value != null && !value.equals("")) {
try {
if (type.equals("String")) {
// 第一個參數(shù):從中調(diào)用基礎(chǔ)方法的對象 第二個參數(shù):用于方法調(diào)用的參數(shù)
method[i].invoke(bean, new Object[] { value });
} else if (type.equals("int") || type.equals("Integer")) {
method[i].invoke(bean, new Object[] { new Integer(""
+ value) });
} else if (type.equals("double") || type.equals("Double")) {
method[i].invoke(bean,
new Object[] { new Double("" + value) });
} else if (type.equals("float") || type.equals("Float")) {
method[i].invoke(bean,
new Object[] { new Float("" + value) });
} else if (type.equals("long") || type.equals("Long")) {
method[i].invoke(bean,
new Object[] { new Long("" + value) });
} else if (type.equals("boolean") || type.equals("Boolean")) {
method[i].invoke(bean,
new Object[] { Boolean.valueOf("" + value) });
} else if (type.equals("BigDecimal")) {
method[i].invoke(bean, new Object[] { new BigDecimal(""
+ value) });
} else if (type.equals("Date")) {
Date date = null;
if (value.getClass().getName().equals("java.util.Date")) {
date = (Date) value;
} else {
String format = ((String) value).indexOf(":") > 0 ? "yyyy-MM-dd hh:mm:ss"
: "yyyy-MM-dd";
SimpleDateFormat sf = new SimpleDateFormat();
sf.applyPattern(format);
date = sf.parse((String) (value));
}
if (date != null) {
method[i].invoke(bean, new Object[] { date });
}
} else if (type.equals("byte[]")) {
method[i].invoke(bean,
new Object[] { new String(value + "").getBytes() });
}
} catch (Exception e) {
System.out
.println("將linkHashMap 或 HashTable 里的值填充到j(luò)avabean時出錯,請檢查!");
e.printStackTrace();
}
}
}
/** 計算年齡 */
public static String getAge(Date birthDay) throws Exception {
Calendar cal = Calendar.getInstance();
if (cal.before(birthDay)) {
throw new IllegalArgumentException(
"The birthDay is before Now.It's unbelievable!");
}
int yearNow = cal.get(Calendar.YEAR);
int monthNow = cal.get(Calendar.MONTH) + 1;
int dayOfMonthNow = cal.get(Calendar.DAY_OF_MONTH);
cal.setTime(birthDay);
int yearBirth = cal.get(Calendar.YEAR);
int monthBirth = cal.get(Calendar.MONTH);
int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);
int age = yearNow - yearBirth;
if (monthNow <= monthBirth) {
if (monthNow == monthBirth) {
// monthNow==monthBirth
if (dayOfMonthNow < dayOfMonthBirth) {
age--;
}
} else {
// monthNow>monthBirth
age--;
}
}
return age + "";
}
public static String getStringByFloat(Float d1) {
DecimalFormat Formator = new DecimalFormat("###.##");
return Formator.format(d1);
}
}
?
?package com.naonao.cmall.utils.http;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSONObject;
import com.naonao.cmall.utils.MyX509TrustManager;
public class PostRequest {
private static final Logger log = LoggerFactory
.getLogger(PostRequest.class);
public static String GET_URL = "";
public static String POST_URL = "";
public static String readContentFromGet() throws IOException {
String getURL = GET_URL;
URL getUrl = new URL(getURL);
// 根據(jù)拼湊的URL,打開連接,URL.openConnection函數(shù)會根據(jù)URL的類型,
// 返回不同的URLConnection子類的對象,這里URL是一個http,因此實際返回的是HttpURLConnection
HttpURLConnection connection = (HttpURLConnection) getUrl
.openConnection();
// 進(jìn)行連接,但是實際上get request要在下一句的connection.getInputStream()函數(shù)中才會真正發(fā)到
// 服務(wù)器
connection.connect();
// 取得輸入流,并使用Reader讀取
BufferedReader reader = new BufferedReader(new InputStreamReader(
connection.getInputStream(), "utf-8"));// 設(shè)置編碼,否則中文亂碼
String line = "";
String lines = "";
while ((line = reader.readLine()) != null) {
// line = new String(line.getBytes(), "utf-8");
lines += line.trim();
}
reader.close();
// 斷開連接
connection.disconnect();
return lines;
}
public static void contentFromGet() throws IOException {
String getURL = GET_URL;
URL getUrl = new URL(getURL);
// 根據(jù)拼湊的URL,打開連接,URL.openConnection函數(shù)會根據(jù)URL的類型,
// 返回不同的URLConnection子類的對象,這里URL是一個http,因此實際返回的是HttpURLConnection
HttpURLConnection connection = (HttpURLConnection) getUrl
.openConnection();
// 進(jìn)行連接,但是實際上get request要在下一句的connection.getInputStream()函數(shù)中才會真正發(fā)到
// 服務(wù)器
connection.connect();
}
public static String readContentFromPost() throws IOException {
// Post請求的url,與get不同的是不需要帶參數(shù)
URL postUrl = new URL(POST_URL);
// 打開連接
HttpURLConnection connection = (HttpURLConnection) postUrl
.openConnection();
// Output to the connection. Default is
// false, set to true because post
// method must write something to the
// connection
// 設(shè)置是否向connection輸出,因為這個是post請求,參數(shù)要放在
// http正文內(nèi),因此需要設(shè)為true
connection.setDoOutput(true);
// Read from the connection. Default is true.
connection.setDoInput(true);
// Set the post method. Default is GET
connection.setRequestMethod("POST");
// Post cannot use caches
// Post 請求不能使用緩存
connection.setUseCaches(false);
// This method takes effects to
// every instances of this class.
// URLConnection.setFollowRedirects是static函數(shù),作用于所有的URLConnection對象。
// connection.setFollowRedirects(true);
// This methods only
// takes effacts to this
// instance.
// URLConnection.setInstanceFollowRedirects是成員函數(shù),僅作用于當(dāng)前函數(shù)
connection.setInstanceFollowRedirects(true);
// Set the content type to urlencoded,
// because we will write
// some URL-encoded content to the
// connection. Settings above must be set before connect!
// 配置本次連接的Content-type,配置為application/x-www-form-urlencoded的
// 意思是正文是urlencoded編碼過的form參數(shù),下面我們可以看到我們對正文內(nèi)容使用URLEncoder.encode
// 進(jìn)行編碼
connection.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
// 連接,從postUrl.openConnection()至此的配置必須要在connect之前完成,
// 要注意的是connection.getOutputStream會隱含的進(jìn)行connect。
connection.connect();
DataOutputStream out = new DataOutputStream(
connection.getOutputStream());
// The URL-encoded contend
// 正文,正文內(nèi)容其實跟get的URL中'?'后的參數(shù)字符串一致
// String content =
// "key=j0r53nmbbd78x7m1pqml06u2&type=1&toemail=jiucool@gmail.com" +
// "&activatecode=" + URLEncoder.encode("久酷博客", "utf-8");
// DataOutputStream.writeBytes將字符串中的16位的unicode字符以8位的字符形式寫道流里面
// out.writeBytes(content);
out.flush();
out.close(); // flush and close
BufferedReader reader = new BufferedReader(new InputStreamReader(
connection.getInputStream(), "utf-8"));// 設(shè)置編碼,否則中文亂碼
String line = "";
String lines = "";
while ((line = reader.readLine()) != null) {
// line = new String(line.getBytes(), "utf-8");
lines += line.trim();
}
reader.close();
connection.disconnect();
return lines;
}
/**
* 經(jīng)緯度
*
* @param lng
* @param lat
* @return
*/
public static Map<String, String> getAddressByLatlat(String lng, String lat) {
String str = "http://api.map.baidu.com/geocoder?output=json&location="
+ lat + "," + lng + "&key=37492c0ee6f924cb5e934fa08c6b167";
Map<String, String> map = new HashMap<String, String>();
try {
PostRequest.POST_URL = str;
String line = PostRequest.readContentFromPost();
JSONObject jsonObj = JSONObject.parseObject(line);
String result = jsonObj.getString("result");
JSONObject jsonObj2 = JSONObject.parseObject(result);
String cityCode = jsonObj2.getString("cityCode");
String formattedAddress = jsonObj2.getString("formatted_address");
JSONObject jsonObj3 = JSONObject.parseObject(jsonObj2
.getString("addressComponent"));
String city = jsonObj3.getString("city");
map.put("cityCode", cityCode);
map.put("formattedAddress", formattedAddress);
map.put("city", city);
} catch (IOException e) {
e.printStackTrace();
}
return map;
}
/**
* 城市
*
* @param city
* @return
*/
public static Map<String, String> getAddressByCity(String city) {
String str = "http://api.map.baidu.com/geocoder/v2/?ak=E4805d16520de693a3fe707cdc962045&callback=renderOption&output=json&address="
+ city + "&city=" + city;
Map<String, String> map = new HashMap<String, String>();
try {
PostRequest.POST_URL = str;
String line = PostRequest.readContentFromPost();
JSONObject jsonObj = JSONObject.parseObject(line);
String result = jsonObj.getString("result");
JSONObject jsonObj2 = JSONObject.parseObject(result);
String cityCode = jsonObj2.getString("cityCode");
String formattedAddress = jsonObj2.getString("formatted_address");
map.put("cityCode", cityCode);
map.put("formattedAddress", formattedAddress);
map.put("city", city);
} catch (IOException e) {
e.printStackTrace();
}
return map;
}
/**
* 城市
*
* @param city
* @return
*/
public static Map<String, String> getQQMessages(String access_token,
String openid) {
String qqUrl = "https://graph.qq.com/user/get_user_info?oauth_consumer_key=100330589&access_token="
+ access_token + "&openid=" + openid + "&format=json";
Map<String, String> map = new HashMap<String, String>();
try {
PostRequest.GET_URL = qqUrl;
String line = PostRequest.readContentFromGet();
JSONObject jsonObj = JSONObject.parseObject(line);
String nickname = jsonObj.getString("nickname");
String gender = jsonObj.getString("gender");
String url = jsonObj.getString("figureurl_qq_1");
map.put("nickname", nickname);
map.put("gender", gender);
map.put("url", url);
map.put("openid", openid);
} catch (IOException e) {
e.printStackTrace();
}
return map;
}
public static void main(String[] args) {
PostRequest.GET_URL="http://mc-storage.b0.upaiyun.com/song_lib/lrc/20140702/Y2014060133.txt";
String line;
try {
line = PostRequest.readContentFromGet();
System.out.println(line);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 用傳統(tǒng)的URI類進(jìn)行請求
* @param urlStr
*/
public static String post(String urlStr,String xmlInfo) {
String line = "";
try {
URL url = new URL(urlStr);
URLConnection con = url.openConnection();
con.setDoOutput(true);
con.setRequestProperty("Pragma:", "no-cache");
con.setRequestProperty("Cache-Control", "no-cache");
con.setRequestProperty("Content-Type", "text/xml");
OutputStreamWriter out = new OutputStreamWriter(con.getOutputStream());
// System.out.println("xmlInfo=" + xmlInfo);
out.write(new String(xmlInfo.getBytes("UTF-8")));
out.flush();
out.close();
BufferedReader br = new BufferedReader(new InputStreamReader(con
.getInputStream()));
for (line = br.readLine(); line != null; line = br.readLine()) {
line+=line;
}
} catch (Exception e) {
e.printStackTrace();
}
return line;
}
/**
* 發(fā)送https請求
* @param requestUrl 請求地址
* @param requestMethod 請求方式(GET、POST)
* @param outputStr 提交的數(shù)據(jù)
* @return 返回微信服務(wù)器響應(yīng)的信息
*/
public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {
try {
// 創(chuàng)建SSLContext對象,并使用我們指定的信任管理器初始化
TrustManager[] tm = { new MyX509TrustManager() };
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());
// 從上述SSLContext對象中得到SSLSocketFactory對象
SSLSocketFactory ssf = sslContext.getSocketFactory();
URL url = new URL(requestUrl);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(ssf);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
// 設(shè)置請求方式(GET/POST)
conn.setRequestMethod(requestMethod);
conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
// 當(dāng)outputStr不為null時向輸出流寫數(shù)據(jù)
if (null != outputStr) {
OutputStream outputStream = conn.getOutputStream();
// 注意編碼格式
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
// 從輸入流讀取返回內(nèi)容
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) {
log.error("連接超時:{}", ce);
} catch (Exception e) {
log.error("https請求異常:{}", e);
}
return null;
}
/**
* 發(fā)送HttpPost請求
*
* @param strURL
* 服務(wù)地址
* @param params
* json字符串,例如: "{ \"id\":\"12345\" }" ;其中屬性名必須帶雙引號<br/>
* @return 成功:返回json字符串<br/>
*/
public static String postByJson(String strURL, String params) {
System.out.println(strURL);
System.out.println(params);
try {
URL url = new URL(strURL);// 創(chuàng)建連接
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setUseCaches(false);
connection.setInstanceFollowRedirects(true);
connection.setRequestMethod("POST"); // 設(shè)置請求方式
connection.setRequestProperty("Accept", "application/json"); // 設(shè)置接收數(shù)據(jù)的格式
connection.setRequestProperty("Content-Type", "application/json"); // 設(shè)置發(fā)送數(shù)據(jù)的格式
connection.connect();
OutputStreamWriter out = new OutputStreamWriter(
connection.getOutputStream(), "UTF-8"); // utf-8編碼
out.append(params);
out.flush();
out.close();
// 讀取響應(yīng)
int length = (int) connection.getContentLength();// 獲取長度
InputStream is = connection.getInputStream();
if (length != -1) {
byte[] data = new byte[length];
byte[] temp = new byte[512];
int readLen = 0;
int destPos = 0;
while ((readLen = is.read(temp)) > 0) {
System.arraycopy(temp, 0, data, destPos, readLen);
destPos += readLen;
}
String result = new String(data, "UTF-8"); // utf-8編碼
System.out.println(result);
return result;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "error"; // 自定義錯誤信息
}
}
?
?package com.naonao.cmall.utils;
import java.io.IOException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import org.jdom.JDOMException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.naonao.cmall.utils.http.HttpUtil;
import com.naonao.cmall.utils.http.PostRequest;
public class WeiXinUtils {
private static final Logger log = LoggerFactory.getLogger(WeiXinUtils.class);
/** 微信開發(fā)平臺應(yīng)用appid */
public static final String APP_ID = "***";
/**
*
*/
//public static final String noncestr="***";
/** 微信開發(fā)平臺應(yīng)用appsecret */
public static final String APP_SECRET = "***";
/**
* 隨機(jī)字符串
*/
public static final String nonceStr="***";
/** 商戶號 */
public static final String MCH_ID = "***";
// 應(yīng)用對應(yīng)的密鑰
public static final String APP_KEY = "***";
// 微信公眾號api
public static final String REDIRECT_URI = "***"; // 授權(quán)回調(diào)
public static final String PAY_URI = "***";// 支付回調(diào)
public static final String SCOPE = "snsapi_userinfo";
public static String GetOpenIdRequest = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&grant_type=authorization_code";
public static String unifiedOrder = "https://api.mch.weixin.qq.com/pay/unifiedorder";
/**
* weixin地址封裝
*
* @return
*/
public static String getCodeRequest(String url) {
String GetCodeRequest = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect";
String result = null;
GetCodeRequest = GetCodeRequest.replace("APPID", urlEnodeUTF8(APP_ID));
GetCodeRequest = GetCodeRequest.replace("SCOPE", SCOPE);
GetCodeRequest = GetCodeRequest.replace("REDIRECT_URI", urlEnodeUTF8(REDIRECT_URI));
GetCodeRequest = GetCodeRequest.replace("STATE", url);
result = GetCodeRequest;
log.info("================================");
log.info(url);
log.info(GetCodeRequest);
log.info("================================");
return result;
}
/**
* weixin地址封裝
*
* @return
*/
public static String getOpenIdRequest() {
String result = null;
GetOpenIdRequest = GetOpenIdRequest.replace("APPID", urlEnodeUTF8(APP_ID));
GetOpenIdRequest = GetOpenIdRequest.replace("SECRET", urlEnodeUTF8(APP_SECRET));
result = GetOpenIdRequest;
return result;
}
/**
* 鏈接轉(zhuǎn)碼
*
* @param str
* @return
*/
public static String urlEnodeUTF8(String str) {
String result = str;
try {
result = URLEncoder.encode(str, "UTF-8");
} catch (Exception e) {
log.error("WeiXinUtils getCodeRequest urlEnodeUTF8:{}", str);
e.printStackTrace();
}
return result;
}
/**
* 通過code獲取openId
*
* @param codeResult
* @return
*/
public static String getOpenId(String codeResult) {
String openid = "";
try {
String openIdUrl = WeiXinUtils.getOpenIdRequest();
PostRequest.GET_URL = openIdUrl + "&code=" + codeResult;
String s = PostRequest.readContentFromGet();
HashMap<String, Object> json = JsonUtil.stringToTObj(s, HashMap.class);
if (json != null && json.get("openid") != null) {
openid = json.get("openid").toString();
}
} catch (IOException e) {
e.printStackTrace();
}
return openid;
}
/**
* 微信支付
*
* @param opentId
* @param total_fee
* @param userIp
* @param notifyUrl
* @param body
* @param orderNumber
* @return
*/
public static String getPayOrderByWeiXin(String opentId, String total_fee, String userIp, String notifyUrl, String body, String orderNumber) {
SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
parameters.put("appid", APP_ID);
System.out.println("appid:"+APP_ID);
parameters.put("mch_id", MCH_ID);
System.out.println("mch_id:"+MCH_ID);
parameters.put("nonce_str", nonceStr);
System.out.println("nonce_str:"+"HZNAONAOCOM");
parameters.put("body", body);
System.out.println("body:"+body);
parameters.put("out_trade_no", orderNumber);
System.out.println("out_trade_no:"+orderNumber);
parameters.put("total_fee", total_fee.substring(0, total_fee.indexOf(".")));
System.out.println("total_fee="+total_fee.substring(0, total_fee.indexOf(".")));
parameters.put("spbill_create_ip", userIp);
System.out.println("spbill_create_ip="+userIp);
parameters.put("notify_url",notifyUrl );
System.out.println("notify_url="+notifyUrl);
parameters.put("trade_type", "JSAPI");
System.out.println("trade_type=JSAPI");
parameters.put("openid", opentId);
System.out.println("openid="+opentId);
String sign = Sign.createSign("UTF-8", parameters);
System.out.println("sign="+sign);
parameters.put("sign", sign);
String requestXML = Utils.getRequestXml(parameters);
System.out.println("requestXML="+requestXML);
String result = PostRequest.httpsRequest(unifiedOrder, "POST", requestXML);
System.out.println("prepay_id="+result);
return getPrepayId(result);
}
/*
* paySign
*/
public static String getPaySignByWeiXin(String timeStamp, String nonceStr, String _package) {
SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
parameters.put("appId", APP_ID);
System.out.println("appId="+APP_ID);
parameters.put("timeStamp", timeStamp);
System.out.println("timeStamp="+timeStamp);
parameters.put("nonceStr", nonceStr);
System.out.println("nonceStr="+nonceStr);
parameters.put("package", _package);
System.out.println("package="+_package);
parameters.put("signType", "MD5");
System.out.println("signType=MD5");
//parameters.put("key", APP_KEY);
String sign = Sign.paySign("UTF-8", parameters);
System.out.println("sign="+sign);
return sign;
}
private static String getPrepayId(String xml) {
String prepay_id = "";
try {
Map map = XMLUtil.doXMLParse(xml);
prepay_id = map.get("prepay_id").toString();
} catch (JDOMException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return prepay_id;
}
/**
* 微信下載文件
*
* @param name 本地文件名稱
* @param media_id 微信圖片ID
* @return
*/
public static String downloadFile(String name,String media_id) {
String downloadFile="http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID";
String token=Sign.getToken();
downloadFile=downloadFile.replace("ACCESS_TOKEN", token);
downloadFile=downloadFile.replace("MEDIA_ID", media_id);
String path=Config.getMediaImgPath();
Date now = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
path+=dateFormat.format(now)+"/"+name;
try {
HttpUtil.downloadFile(path, downloadFile);
} catch (IOException e) {
e.printStackTrace();
}
return path;
}
}
6.獲取paysSign(簽名的appId中的'I'大寫,不然會報錯,之前我這里卡了好長時間,getPaySignByWeiXin在WeiXinUtils方法里)
String paySign=WeiXinUtils.getPaySignByWeiXin(timeStamp, nonceStr, "prepay_id="+getPrepayId);
?
7.程序的入口
?
?/**
* 微信支付
*/
public ModelAndView WeixinPay(String cmd, JSONObject request,HttpServletRequest httprequest, HttpServletResponse response) {
//"appId": "<%= appId %>", //公眾號名稱,由商戶傳入
//"timeStamp": "<%= timeStamp %>", //時間戳
//"nonceStr": "<%= nonceStr %>", //隨機(jī)串
//"package": "<%= package %>", //擴(kuò)展包
//"signType": "MD5", //微信簽名方式:1.sha1
//"paySign": "<%= paySign %>" //微信簽名
//String accessToken="";
//String ticket="";
String body="";
String num="";
Double sumPrice=0.0;
String userIp =Utils.getRemortIP(httprequest);
//if(userIp==""||userIp==null)
//userIp="127.0.0.1";
String timeStamp= Long.toString(new Date().getTime()/1000);
String nonceStr=WeiXinUtils.nonceStr; //"HZNAONAOCOM";
String openid =request.getString("openid");
String url = request.getString("url");
JSONArray ordernumlist = request.getJSONArray("ordernum");
if(StringUtils.isBlank(openid)||StringUtils.isBlank(url)||ordernumlist==null)
return writeNotParameters(cmd);
if(openid==""||openid==null)
openid="orLhutxu-XEXWPAB-1DewmJ89w8g";
if(url==""||url==null)
url="http://hznaonao.com/c_mall/pay.jsp";//調(diào)用JS接口頁面的完整URL
//訂單號
String[] numlist=new String[100];
for(int i=0;i<ordernumlist.size();i++){
Object obj=ordernumlist.get(i);
//JSONObject obj = ordernumlist.getJSONObject(i);
//String ordernum=obj.getString("ordernum");
numlist[i]=obj.toString();
num=num+obj;
}
for(int j=0;j<numlist.length;j++){
if(numlist[j]==null)
break;
TOrder order=orderService.findOrderByNumber(numlist[j]);
List<TOrderGoods> ordergoods=orderGoodsService.findOrderGoodsByNumber(numlist[j]);
System.out.println(Double.parseDouble(order.getSumPrice()));
sumPrice=sumPrice+Double.parseDouble(order.getSumPrice());
for(int i=0;i<ordergoods.size();i++){
body=body+","+ordergoods.get(i).getGoodsName();
}
}
String getPrepayId = WeiXinUtils.getPayOrderByWeiXin(openid,String.valueOf(sumPrice*100),userIp,url,body,num+timeStamp);
System.out.println(getPrepayId);
String paySign=WeiXinUtils.getPaySignByWeiXin(timeStamp, nonceStr, "prepay_id="+getPrepayId);
System.out.println(paySign);
WeiXinVO v =new WeiXinVO();
v.setAppId(WeiXinUtils.APP_ID);
v.setTimeStamp(timeStamp);
v.setNonceStr(nonceStr);
v.set_package("prepay_id="+getPrepayId);
v.setSignType("MD5");
v.setPaySign(paySign);
v.setUrl(url);
System.out.println("appId="+WeiXinUtils.APP_ID);
System.out.println("timeStamp="+timeStamp);
System.out.println("nonceStr="+nonceStr);
System.out.println("package=prepay_id="+getPrepayId);
System.out.println("signType=MD5");
System.out.println("paySign="+paySign);
return writeJson(cmd, SUCCESS_CODE, "查詢成功", v);
}
?
?
8.注意paySign簽名的timeStamp、nonceStr與最后發(fā)送給微信的timeStamp、nonceStr要一致,MD5加密的sign要轉(zhuǎn)化成大寫。
?
9.調(diào)起微信支付,把a(bǔ)ppId,timeStamp,nonceStr,package,signType,paySign返回給微信,就OK了,另外回調(diào)頁面下次再貼代碼。
總結(jié)
以上是生活随笔為你收集整理的Java开发微信支付流程及容易入坑的点的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AJAX请求5步法
- 下一篇: 揭秘:QQ号码能准确测出QQ主人年龄问题