1. 程式人生 > >SpringBoot和微信二維碼相關的部分

SpringBoot和微信二維碼相關的部分

package soke.home.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.security.KeyStore;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.dom4j.QName;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import com.alibaba.fastjson.JSONObject;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;
import com.typesafe.config.ConfigFactory;

import soke.common.util.GetPostUtil;
import soke.home.classes.domain.model.CpClass;
import soke.home.classes.domain.model.CpClassMember;
import soke.home.family.domain.model.CpFamily;
import soke.home.message.domain.model.CpMsg;
import soke.home.message.domain.model.CpMsgDnd;
import soke.home.message.domain.model.CpMsgInbox;
import soke.home.message.domain.model.Message;
import soke.home.message.domain.model.MessageManagerPool;
import soke.home.org.domain.model.OrgMember;
import soke.home.org.domain.model.Organization;
import soke.home.user.domain.model.User;
import soke.home.user.enums.JFTRole;
import soke.home.wx.annotation.XStreamCDATA;
import soke.home.wx.constants.WeiXinConstants;
import soke.home.wx.thread.HomeVisitThread;
import soke.memory.redis.RedisDb;

@SuppressWarnings("deprecation")
@Component
/**
 * 
 * @author 15293
 *
 */
public class WeixinUtil {
	static Logger logger = LoggerFactory.getLogger(WeixinUtil.class);

	/*-------------------------WX---------------------------*/

	/** appId 微信的正式環境 */
	public static String appID = ConfigFactory.load().getString("weixin.appId");
	public static String appsecret = ConfigFactory.load().getString("weixin.appsecret");
	/** 商品號 */
	public static String mch_id = ConfigFactory.load().getString("weixin.mchId");
	/** 付款回撥地址 */
	public static String notify_url = ConfigFactory.load().getString("weixin.notifyUrl");
	/** 微信公眾號Key */
	public static String key = ConfigFactory.load().getString("weixin.key");
	/** 微信公眾號校驗的欄位 */
	public static String token = ConfigFactory.load().getString("weixin.token");
	/** 專案路徑 **/
	public static String applyaddress = ConfigFactory.load().getString("weixin.applyaddress");
	/** 傳送紅包的證書路徑 **/
	public static String redPaperPath = ConfigFactory.load().getString("wexin.redPaperPath");

	/**
	 * 獲取微信的access_token(redis裡面獲取不到就自己去取)
	 * 
	 * @return String(null)
	 * 
	 **/
	public static String getAccessToken() {
		String accessToken = null;
		if (RedisDb.exists(WeiXinConstants.ACCESSTOKEN_IN_REDIS)) {
			accessToken = RedisDb.getString("access_token");
		}

		String aString = GetPostUtil.sendGet("https://api.weixin.qq.com/cgi-bin/token",
				"grant_type=client_credential&appid=" + appID + "&secret=" + appsecret);
		JSONObject jsonObject = JSONObject.parseObject(aString);

		if (jsonObject.get("access_token") != null) {
			accessToken = (String) jsonObject.get("access_token");
			RedisDb.setAccessToken("access_token", accessToken, WeiXinConstants.EXPIRETIME);
		} else {
			logger.error("access_token的獲取有問題" + jsonObject);
		}

		return accessToken;
	}

	/**
	 * 獲取生成臨時二維碼需要的ticket
	 * 
	 * 1.設定了過期時間為2592000---即30天 2.如果報40001(access_token無效)的錯誤
	 * 就移除Redis裡面的access_token重新生成
	 * 
	 * @param l:傳入的帶引數的二維碼裡面存的引數值
	 * 
	 * @return String(null)
	 *
	 */
	public static String getTicket(long l) {
		String accessToken = getAccessToken();
		JSONObject jsonObject = JSONObject.parseObject(
				"{\"expire_seconds\":2592000,\"action_name\": \"QR_SCENE\", \"action_info\": {\"scene\": {\"scene_id\":"
						+ l + "}}}");
		String aString2 = GetPostUtil
				.post("https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + accessToken, jsonObject);
		JSONObject jsonObject2 = JSONObject.parseObject(aString2);

		// 當出現access_token出現40001異常的時候 從redis裡面移除
		String errcode = (String) jsonObject2.get("errcode");
		if (errcode != null && errcode.equals("40001")) {
			RedisDb.delString("access_token");
			accessToken = getAccessToken();
			GetPostUtil.post("https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + accessToken, jsonObject);
		}

		String ticket = (String) jsonObject2.get("ticket");
		return ticket;
	}

	/**
	 * 解析微信發來的請求或者XML為鍵值對,方便取值(因為有request和xml2種情況 ,所以合併成一個介面,傳入2個引數 )
	 * 
	 * @param request:requset請求
	 * @param xml:String的xml語句
	 * 
	 * @return HashMap<Sring,String>
	 * 
	 * @throws IOException
	 * @throws DocumentException
	 * 
	 */
	public static Map<String, String> parseXml(HttpServletRequest request, String xml)
			throws IOException, DocumentException {
		// 將解析結果儲存在HashMap中
		Map<String, String> map = new HashMap<String, String>();
		InputStream inputStream = null;
		Document document = null;

		if (request != null) {
			inputStream = request.getInputStream();
			SAXReader reader = new SAXReader();
			document = reader.read(inputStream);
		}

		if (xml != null) {
			document = DocumentHelper.parseText(xml);
		}

		Element rootElement = document.getRootElement();
		ele2map(map, rootElement);
		if (inputStream != null) {
			inputStream.close();
			inputStream = null;
		}
		return map;
	}

	/**
	 * 解析xml檔案
	 */
	static void ele2map(Map<String, String> map, Element ele) {
		// 獲得當前節點的子節點
		List<Element> elements = ele.elements();
		if (elements.size() == 0) {
			// 沒有子節點說明當前節點是葉子節點,直接取值即可
			if (ele.getText() != null) {
				map.put(ele.getName(), ele.getText());
			}
		} else if (elements.size() == 1) {
			// 只有一個子節點說明不用考慮list的情況,直接繼續遞迴即可
			Map<String, String> tempMap = new HashMap<String, String>();
			ele2map(map, elements.get(0));
			if (tempMap.get(ele.getName()) != null) {
				map.put(ele.getName(), tempMap.get(ele.getName()));
			}
		} else {
			// 多個子節點的話就得考慮list的情況了,比如多個子節點有節點名稱相同的
			// 構造一個map用來去重
			Map<String, String> tempMap = new HashMap<String, String>();
			for (Element element : elements) {
				tempMap.put(element.getName(), null);
			}
			Set<String> keySet = tempMap.keySet();
			for (String string : keySet) {
				Namespace namespace = elements.get(0).getNamespace();
				List<Element> elements2 = ele.elements(new QName(string, namespace));
				// 如果同名的數目大於1則表示要構建list 現在假設不可能重名
				if (elements2.size() > 1) {

				} else {
					// 同名的數量不大於1則直接遞迴去
					ele2map(map, elements2.get(0));
				}
			}
		}
	}

	/**
	 * 根據access和OpenId獲取使用者基本資訊
	 * 
	 * @param openid
	 * 
	 * @return JsonObject(null)
	 */
	public static JSONObject getUserInfoFromWX(String openid) {
		if (openid == null) {
			return null;
		}

		String url = "https://api.weixin.qq.com/cgi-bin/user/info";
		String accessToken = getAccessToken();
		String info = GetPostUtil.sendGet(url, "access_token=" + accessToken + "&openid=" + openid + "&lang=zh_CN");
		JSONObject jsonObject = JSONObject.parseObject(info);
		return jsonObject;
	}

	/**
	 * 把object轉換成xml物件
	 * 
	 * @param object
	 * 
	 * @return String
	 */
	public static String objectToXml(Object object) {
		XStream xstream = createXstream();
		xstream.alias("xml", object.getClass());
		return xstream.toXML(object);
	}

	/**
	 * 利用Xstream來把Object轉換成xml檔案(匿名內部類)
	 * 
	 * @return
	 */
	public static XStream createXstream() {
		return new XStream(new XppDriver() {

			@Override
			public HierarchicalStreamWriter createWriter(Writer out) {
				return new PrettyPrintWriter(out) {
					boolean cdata = false;
					Class<?> targetClass = null;

					@Override
					public void startNode(String name, @SuppressWarnings("rawtypes") Class clazz) {
						super.startNode(name, clazz);
						// 業務處理,對於用XStreamCDATA標記的Field,需要加上CDATA標籤
						if (!"xml".equals(name)) {
							cdata = needCDATA(targetClass, name);
						} else {
							targetClass = clazz;
						}
					}

					@Override
					protected void writeText(QuickWriter writer, String text) {
						if (cdata) {
							writer.write("<![CDATA[");
							writer.write(text);
							writer.write("]]>");
						} else {
							writer.write(text);
						}
					}
				};
			}
		});
	}

	/**
	 * 迴圈往上面遍歷,看域上面是否有註解
	 * 
	 * @param targetClass
	 * @param fieldAlias
	 * @return
	 */
	private static boolean needCDATA(Class<?> targetClass, String fieldAlias) {
		boolean cdata = false;
		cdata = existsCDATA(targetClass, fieldAlias);
		if (cdata) {
			return cdata;
		}
		Class<?> superClass = targetClass.getSuperclass();
		while (!superClass.equals(Object.class)) {
			cdata = existsCDATA(superClass, fieldAlias);
			if (cdata) {
				return cdata;
			}
			superClass = superClass.getClass().getSuperclass();
		}
		return false;
	}

	private static boolean existsCDATA(Class<?> clazz, String fieldAlias) {
		// 特例新增
		if ("MediaId".equals(fieldAlias)) {
			return true;
		}

		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			if (field.getAnnotation(XStreamCDATA.class) != null) {
				XStreamAlias xStreamAlias = field.getAnnotation(XStreamAlias.class);
				if (null != xStreamAlias) {
					if (fieldAlias.equals(xStreamAlias.value())) {
						return true;
					}
				} else {
					// 如果傳入的xml節點的名稱和@xstreamAlias的相等也返回true
					if (fieldAlias.equals(field.getName())) {
						return true;
					}
				}
			}
		}
		return false;
	}

	/**
	 * 判斷是否是QQ表情
	 * 
	 * @param content
	 * @return
	 */
	public static boolean isQqFace(String content) {
		boolean result = false;

		// 判斷QQ表情的正則表示式
		String qqfaceRegex = "/::\\)|/::~|/::B|/::\\||/:8-\\)|/::<|/::$|/::X|/::Z|/::'\\(|/::-\\||/::@|"
				+ "/::P|/::D|/::O|/::\\(|/::\\+|/:--b|/::Q|/::T|/:,@P|/:,@-D|/::d|/:,@o|/::g|/:\\|-\\)|"
				+ "/::!|/::L|/::>|/::,@|/:,@f|/::-S|/:\\?|/:,@x|/:,@@|/::8|/:,@!|/:!!!|/:xx|/:bye|/:wipe|"
				+ "/:dig|/:handclap|/:&-\\(|/:B-\\)|/:<@|/:@>|/::-O|/:>-\\||/:P-\\(|/::'\\||/:X-\\)|/::\\*|"
				+ "/:@x|/:8\\*|/:pd|/:<W>|/:beer|/:basketb|/:oo|/:coffee|/:eat|/:pig|/:rose|/:fade|/:showlove|"
				+ "/:heart|/:break|/:cake|/:li|/:bome|/:kn|/:footb|/:ladybug|/:shit|/:moon|/:sun|/:gift|/:hug|"
				+ "/:strong|/:weak|/:share|/:v|/:@\\)|/:jj|/:@@|/:bad|/:lvu|/:no|/:ok|/:love|/:<L>|/:jump|/:shake|"
				+ "/:<O>|/:circle|/:kotow|/:turn|/:skip|/:oY|/:#-0|/:hiphot|/:kiss|/:<&|/:&>"
				+ "|\\[Smart\\]|\\[Hey\\]|\\[Facepalm\\]|\\[Smirk\\]|\\[Concerned\\]|\\[Yeah!\\]|\\[Packet\\]|\\[Chick\\]";
		Pattern p = Pattern.compile(qqfaceRegex);
		Matcher m = p.matcher(content);
		if (m.matches()) {
			result = true;
		}
		return result;
	}

	
	/**
	 * 調起Js
	 * 
	 * @return
	 */
	public static String getJsSdkConfigTicket() {
		String ticket = null;
		if (RedisDb.exists("jsapi_ticket")) {
			ticket = RedisDb.getString("jsapi_ticket");
		}

		if (ticket != null) {
			System.err.println("jsapi_ticket是從Redis裡面取得,值為:");
			return ticket;
		}

		String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket";
		String accessToken = getAccessToken();
		String info = GetPostUtil.sendGet(url, "access_token=" + accessToken + "&type=jsapi");
		JSONObject jsonObject = JSONObject.parseObject(info);
		System.err.print("獲取JsApiTicket的值:ticket是手動獲取的:" + jsonObject);
		ticket = jsonObject.getString("ticket");
		RedisDb.setAccessToken("jsapi_ticket", ticket, WeiXinConstants.EXPIRETIME);
		return ticket;
	}

	/**
	 * 生成內部訂單號
	 */
	public static String createOutTradeNo(Integer uid) {
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
		String date = LocalDateTime.now().format(formatter);
		Random random = new Random();
		String uuid = uid + "";
		int rannum = (int) (random.nextDouble() * (99999 - 10000 + 1)) + 10000;
		if (uid == null) {
			uuid = "00";
		} else if (uid < 10) {
			uuid = "0" + uid;
		}
		return date + uuid + rannum;
	}

	
	/**
	 * 因為微信授權的特殊性 同一code只能獲取一次資訊 所以用redis來處理一下;
	 * 
	 * @param code
	 *            微信網頁授權碼
	 * 
	 * @param openId
	 *            openId
	 */
	public static String opreateOpenId(String code, String openId) {
		if (code == null) {
			logger.info("WeixinUtil的opreateOpenId傳入的code為null");
			return null;
		}

		if (openId != null) {
			RedisDb.setString(code, openId);
			return null;
		} else {
			openId = RedisDb.getString(code);
			return openId;
		}

	}

	/**
	 * @param mchId
	 *            ----商戶Id
	 * 
	 * @param xml
	 *            ----包含簽名的xml檔案
	 * 
	 * @param url
	 *            ----需要post資料的url地址
	 * 
	 * @return String
	 * 
	 */
	public static String WxRedPaperSend(String mchId, String xml, String url) {
		try {
			KeyStore keyStore = KeyStore.getInstance("PKCS12");
			FileInputStream instream = new FileInputStream(new File(redPaperPath));
			try {
				keyStore.load(instream, mchId.toCharArray());
			} finally {
				instream.close();
			}

			// Trust own CA and all self-signed certs
			SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mchId.toCharArray()).build();
			// Allow TLSv1 protocol only
			SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" },
					null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
			CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
			StringBuffer result = new StringBuffer();
			try {
				HttpPost httpPost = new HttpPost(url);
				// 構造HttpClient的HttpPost請求
				httpPost.addHeader("Connection", "keep-alive");
				httpPost.addHeader("Accept", "*/*");
				httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
				httpPost.addHeader("Host", "api.mch.weixin.qq.com");
				httpPost.addHeader("X-Requested-With", "XMLHttpRequest");
				httpPost.addHeader("Cache-Control", "max-age=0");
				httpPost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
				httpPost.setEntity(new StringEntity(xml, "UTF-8"));
				CloseableHttpResponse response = httpclient.execute(httpPost);

				try {
					HttpEntity entity = response.getEntity();
					System.out.println(response.getStatusLine());
					if (entity != null) {
						System.out.println("Response content length: " + entity.getContentLength());
						BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));
						String text;
						while ((text = bufferedReader.readLine()) != null) {
							result.append(text);
							result.append("\n");
						}
					}
					EntityUtils.consume(entity);
				} finally {
					response.close();
				}
			} finally {
				httpclient.close();
			}

			return result.toString();
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("傳送現金紅包的封裝接口出錯:" + e.getMessage());
			return null;
		}

	}

}

相關推薦

SpringBoot相關部分

package soke.home.util; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.Inp

關於viewport引起的識別區域偏移的問題討論與解決

ges 瀏覽器內核 不同 清晰 css 工作量 分辨 轉換成 如果 一、問題概述 在開發一個含有二維碼的微信頁面時,我遇到了這樣一個問題:使用iPhone第一次進入該頁面時,二維碼可以長按識別,但第二次進入時長按無法識別到二維碼。安卓機都能識別。 二、我進行了以下嘗試:

公眾平臺開發(121) 海報

關鍵字:微信公眾平臺 二維碼 海報作者:方倍工作室原文: http://www.cnblogs.com/txw1958/p/weixin-poster.html    本文介紹微信公眾平臺下二維碼海報的開發過程。 一、微信二維碼海報介紹 微信二維碼海報是指在

通過程式設計做特別效果的個性 (思路)

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Android 基於google Zxing實現 條形碼掃描,仿掃描效果

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

你的是唯一的嗎 【的祕密】

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

上傳檔案

轉載自:https://blog.csdn.net/peng_wei_kang/article/details/80279923 作者:peng_wei_kang     在業務系統中常常遇到檔案上傳比較麻煩等問題,首先拍照後要將照片拷貝到電

的製作

 1.匯入pom中的jar包 <!-- https://mvnrepository.com/artifact/com.google.zxing/core --> <dependency> <groupId>com

TP5.0 web付款,包括查詢是否支付成功。

首先呢,需要公司去註冊微信平臺上的東西,拿到資質,拿到配置資訊才可以進行測試。 我們程式猿這裡直接從程式碼開始,不管前面亂七八糟的程式。 下載好文件後把文件放在 exends 目錄下 ![這裡我改名為 wechatpay](https://img-blog.csdnimg.cn/20

如何在CSDN個人主頁新增公眾號或者個人

對於CSDN,在這裡,如果有自己的能力,你想推廣你個人。我想,你將你的微信二維碼或者你的微信公眾號的二維碼放在這裡,至少我是這樣想的 那麼我在我的CSDN的部落格主頁面中,我們就添加了我的微信公眾號的二維碼: 具體實現的步驟: 1、 找到個人主頁裡的“管理部落格”

多個收款,加人,進群,這樣做簡單方便又安全!

我有幾個微訊號,可以同時收款嗎? 我業務長期推廣,有幾個微訊號,想做成一個微信二維碼加人可以嗎? 我這邊做活動,想把很多微信群二維碼,做成一個可以嗎? 其實沒那麼麻煩,一個介面就能搞定!重點給大家講解一下! 支付活碼:微信收款用 微信活碼:微信加人用 群活碼:

node.js獲取並儲存到伺服器

const body = {path: 'pages/index',} const opts = { url: `https://api.weixin.qq.com/wxa/getwxa

C#獲取顯示到wpf

微信的api開放的二維碼是一個連結地址,而我們要將這個二維碼顯示到客戶端。方式很多,今天我們講其中一種。 /// <summary> /// 獲取圖片路徑 /// </summary> /// <param name="h

java生成帶圖片的

廢話不多說。 import java.awt.Color; import java.awt.Graphics2D; import java.awt.Image; import java.awt.geom.AffineTransform; import java.awt.

java生成自己的

根據上一篇得到的資料,我們可以生成自己的微信二維碼: import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.io.OutputStream; i

解析內的資訊

這兩天對微信二維碼比較感興趣,所以就花了點時間學習了一下,下面我將先介紹一下如何解析微信二維碼內的資訊。 直接上程式碼: import java.awt.image.BufferedImage; import java.io.File; import java.io.IOExcep

Android 基於google Zxing實現、條形碼掃描,仿掃描效果(現在正做個掃描App、收藏)

瞭解二維碼這個東西還是從微信中,當時微信推出二維碼掃描功能,自己感覺挺新穎的,從一張圖片中掃一下竟然能直接加好友,不可思議啊,那時候還不瞭解二維碼,呵呵,然後做專案的時候,老闆說要加上二維碼掃描功能,然後自己的屁顛屁顛的去百度,google啥的,發現很多朋友都

Java 支付

本文程式碼並非原創,是根據網上一篇部落格修改而成,留作備忘。 微信支付有2種模式,第一種模式略微複雜,本文采用第二種模式; 微信掃碼模式二 業務流程說明: (1)商戶後臺系統根據使用者選購的商品生成訂單。 (2)使用者確認

解決mui-app分享

var Intent = null, File = null, Uri = null, main = null; var shares = null; var shareImageUrl = ''; mui.plusReady(function() {

海報推廣示例

這倆天根據客戶 需求  微信商城 能生成自己的二維碼 並且 需先關注公眾號,掃碼的使用者顯示出自己的上級研究兩天,發現微信二維碼介面能實現這個功能 ! 思路:1.生成微信永久二位碼 具體看微信公眾文件     http://mp.weixin.qq.com/wiki/18/