Java开发微信支付流程及容易入坑的点

本人琢磨微信支付好几天了,终于完成了,下面是开发微信支付的流程:

1.先要有认证后的微信服务号,然后申请开通微信支付功能,通过之后,腾讯会跟你发一封邮件,如下图:

 2.配置好微信支付的支付授权目录(配置错误,支付时微信会返回:http://ki.hdh.com/kjjk/jh未注册错误)


3.我们要参照微信传的参数,如下图:


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

		// 注意这里参数名必须全部小写,且必须有序
		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();
	}

	/**
	 * 利用反射实现对象之间属性复制
	 * 
	 * @param from
	 * @param to
	 */
	public static void copyProperties(Object from, Object to) throws Exception {
		copyPropertiesExclude(from, to, null);
	}

	/**
	 * 复制对象属性
	 * 
	 * @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); // 构造列表对象
		}
		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 });
		}
	}

	/**
	 * 对象属性值复制,仅复制指定名称的属性值
	 * 
	 * @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); // 构造列表对象
		} 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 });
		}
	}

	/**
	 * 从方法数组中获取指定名称的方法
	 * 
	 * @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 转 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 {
				// 转成小写
				// 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) {
					// 调用其底层方法
					setValue(type, map.get(value), i, methods, obj);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return obj;
	}

	/**
	 * 调用底层方法设置值
	 */
	private static void setValue(String type, Object value, int i,
			Method[] method, Object bean) {
		if (value != null && !value.equals("")) {
			try {
				if (type.equals("String")) {
					// 第一个参数:从中调用基础方法的对象 第二个参数:用于方法调用的参数
					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 里的值填充到javabean时出错,请检查!");
				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);
		// 根据拼凑的URL,打开连接,URL.openConnection函数会根据URL的类型,
		// 返回不同的URLConnection子类的对象,这里URL是一个http,因此实际返回的是HttpURLConnection
		HttpURLConnection connection = (HttpURLConnection) getUrl
				.openConnection();
		// 进行连接,但是实际上get request要在下一句的connection.getInputStream()函数中才会真正发到
		// 服务器
		connection.connect();
		// 取得输入流,并使用Reader读取
		BufferedReader reader = new BufferedReader(new InputStreamReader(
				connection.getInputStream(), "utf-8"));// 设置编码,否则中文乱码
		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);
		// 根据拼凑的URL,打开连接,URL.openConnection函数会根据URL的类型,
		// 返回不同的URLConnection子类的对象,这里URL是一个http,因此实际返回的是HttpURLConnection
		HttpURLConnection connection = (HttpURLConnection) getUrl
				.openConnection();
		// 进行连接,但是实际上get request要在下一句的connection.getInputStream()函数中才会真正发到
		// 服务器
		connection.connect();
	}

	public static String readContentFromPost() throws IOException {
		// Post请求的url,与get不同的是不需要带参数
		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
		// 设置是否向connection输出,因为这个是post请求,参数要放在
		// http正文内,因此需要设为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函数,作用于所有的URLConnection对象。
		// connection.setFollowRedirects(true);

		// This methods only
		// takes effacts to this
		// instance.
		// URLConnection.setInstanceFollowRedirects是成员函数,仅作用于当前函数
		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参数,下面我们可以看到我们对正文内容使用URLEncoder.encode
		// 进行编码
		connection.setRequestProperty("Content-Type",
				"application/x-www-form-urlencoded");
		// 连接,从postUrl.openConnection()至此的配置必须要在connect之前完成,
		// 要注意的是connection.getOutputStream会隐含的进行connect。
		connection.connect();
		DataOutputStream out = new DataOutputStream(
				connection.getOutputStream());
		// The URL-encoded contend
		// 正文,正文内容其实跟get的URL中'?'后的参数字符串一致
		// 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"));// 设置编码,否则中文乱码
		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;
	}

	/**
	 * 经纬度
	 * 
	 * @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();
		}
	}
	
    
    /** 
     * 用传统的URI类进行请求 
     * @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;
    }  
    
    /**
     * 发送https请求
     * @param requestUrl 请求地址
     * @param requestMethod 请求方式(GET、POST)
     * @param outputStr 提交的数据
     * @return 返回微信服务器响应的信息
     */
    public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {
        try {
            // 创建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);
            // 设置请求方式(GET/POST)
            conn.setRequestMethod(requestMethod);
            conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
            // 当outputStr不为null时向输出流写数据
            if (null != outputStr) {
                OutputStream outputStream = conn.getOutputStream();
                // 注意编码格式
                outputStream.write(outputStr.getBytes("UTF-8"));
                outputStream.close();
            }
            // 从输入流读取返回内容
            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;
    }
    
    /** 
     * 发送HttpPost请求 
     *  
     * @param strURL 
     *            服务地址 
     * @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);// 创建连接  
            HttpURLConnection connection = (HttpURLConnection) url  
                    .openConnection();  
            connection.setDoOutput(true);  
            connection.setDoInput(true);  
            connection.setUseCaches(false);  
            connection.setInstanceFollowRedirects(true);  
            connection.setRequestMethod("POST"); // 设置请求方式  
            connection.setRequestProperty("Accept", "application/json"); // 设置接收数据的格式  
            connection.setRequestProperty("Content-Type", "application/json"); // 设置发送数据的格式  
            connection.connect();  
            OutputStreamWriter out = new OutputStreamWriter(  
                    connection.getOutputStream(), "UTF-8"); // utf-8编码  
            out.append(params);  
            out.flush();  
            out.close();  
            // 读取响应  
            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);
	
	/** 微信开发平台应用appid */
	public static final String APP_ID = "***";
	
	/**
	 * 
	 */
	//public static final String noncestr="***";
	/** 微信开发平台应用appsecret */
	public static final String APP_SECRET = "***";
	/**
	 * 随机字符串
	 */
	public static final String nonceStr="***";
	
	/** 商户号 */
	public static final String MCH_ID = "***";
	
	// 应用对应的密钥
	public static final String APP_KEY = "***";
	
	// 微信公众号api
	public static final String REDIRECT_URI = "***"; // 授权回调
	public static final String PAY_URI = "***";// 支付回调
	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;
	}

	/**
	 * 链接转码
	 * 
	 * @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 %>", //随机串
        //"package": "<%= package %>", //扩展包
        //"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";//调用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与最后发送给微信的timeStamp、nonceStr要一致,MD5加密的sign要转化成大写。

9.调起微信支付,把appId,timeStamp,nonceStr,package,signType,paySign返回给微信,就OK了,另外回调页面下次再贴代码。

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值