From cd8f73819900dd41e1a92b0393e67da57684f9a3 Mon Sep 17 00:00:00 2001
From: cuilei <ray_tsu1@163.com>
Date: 星期三, 02 七月 2025 19:27:01 +0800
Subject: [PATCH] 企业微信模板卡片消息回调接口、模板卡片消息参数实体封装

---
 lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/utils/AesException.java                 |   59 +++
 lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/vo/TemplateCard.java                    |   20 +
 lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/utils/SHA1.java                         |   61 +++
 lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/utils/Sample.java                       |  136 ++++++++
 lxzn-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java                                               |    2 
 lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/utils/PKCS7Encoder.java                 |   67 +++
 lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/MessageAPI.java                         |   26 +
 lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/controller/WeComCallbackController.java |  136 ++++++++
 lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/utils/XMLParse.java                     |  104 ++++++
 lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/vo/TemplateCardEntity.java              |   94 +++++
 lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/utils/ByteGroup.java                    |   26 +
 lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/utils/WXBizMsgCrypt.java                |  289 +++++++++++++++++
 12 files changed, 1,020 insertions(+), 0 deletions(-)

diff --git a/lxzn-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java b/lxzn-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java
index 982587e..307b51d 100644
--- a/lxzn-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java
+++ b/lxzn-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java
@@ -163,6 +163,8 @@
 
         //娴嬭瘯妯″潡鎺掗櫎
         filterChainDefinitionMap.put("/test/seata/**", "anon");
+        //浼佷笟寰俊娑堟伅鍥炶皟鎺ュ彛
+        filterChainDefinitionMap.put("/qywx/message/callback/**", "anon");
 
 
         // 娣诲姞鑷繁鐨勮繃婊ゅ櫒骞朵笖鍙栧悕涓簀wt
diff --git a/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/MessageAPI.java b/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/MessageAPI.java
new file mode 100644
index 0000000..3cda9bf
--- /dev/null
+++ b/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/MessageAPI.java
@@ -0,0 +1,26 @@
+package org.jeecg.modules.qywx.message;
+
+import com.alibaba.fastjson.JSONObject;
+import com.jeecg.qywx.api.core.util.HttpUtil;
+import org.jeecg.modules.qywx.message.vo.TemplateCard;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MessageAPI {
+    private static final Logger logger = LoggerFactory.getLogger(MessageAPI.class);
+    //鍙戦�佹秷鎭紙post锛�
+    static String message_send_url="https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=ACCESS_TOKEN";
+
+    public static JSONObject sendTemplateCardMessage(TemplateCard templateCard, String accessToken) {
+        logger.info("[MessageAPI] sendTemplateCardMessage params:accessToken:{},templateCard:{}", new Object[]{accessToken, templateCard});
+        // 鎷艰鍙戦�佷俊鎭殑url
+        String url = message_send_url.replace("ACCESS_TOKEN", accessToken);
+        // 灏嗕俊鎭璞¤浆鎹㈡垚json瀛楃涓�
+        String params = JSONObject.toJSONString(templateCard);
+        logger.info("[MessageAPI] sendTemplateCardMessage params:jsonText:{}", new Object[]{params});
+        // 璋冪敤鎺ュ彛鍙戦�佷俊鎭�
+        JSONObject jsonObject = HttpUtil.sendPost(url, params);
+        logger.info("[MessageAPI] sendTemplateCardMessage response:{}", new Object[]{jsonObject.toJSONString()});
+        return jsonObject;
+    }
+}
diff --git a/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/controller/WeComCallbackController.java b/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/controller/WeComCallbackController.java
new file mode 100644
index 0000000..ad84126
--- /dev/null
+++ b/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/controller/WeComCallbackController.java
@@ -0,0 +1,136 @@
+package org.jeecg.modules.qywx.message.controller;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.jeecg.modules.qywx.message.utils.WXBizMsgCrypt;
+import org.springframework.web.bind.annotation.*;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import java.io.StringReader;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+
+/**
+ * 浼佷笟寰俊娑堟伅鍥炶皟鎺ュ彛锛堟敮鎸� URL 楠岃瘉 + 娑堟伅鎺ユ敹锛�
+ */
+@RestController
+@RequestMapping("/qywx/message/callback")
+@Slf4j
+public class WeComCallbackController {
+
+    // 鏇挎崲涓轰綘鐨勫簲鐢ㄩ厤缃�
+    private static final String TOKEN = "bPGpQimYTtjAfAj2uTE4fb";
+    private static final String AES_KEY = "hkbscaEtxWAydMIoWe8EW4drpHXaYroQPKBMoKCs2bf"; // EncodingAESKey
+    private static final String CORP_ID = "ww5999b2643c95fa75"; // 浼佷笟 ID 鎴� AppId
+
+    private static WXBizMsgCrypt wxBizMsgCrypt;
+
+    static {
+        try {
+            wxBizMsgCrypt = new WXBizMsgCrypt(TOKEN, AES_KEY, CORP_ID);
+        } catch (Exception e) {
+            throw new RuntimeException("鍒濆鍖� WXBizMsgCrypt 澶辫触锛岃妫�鏌� Token/AESKey/AppId 鏄惁姝g‘", e);
+        }
+    }
+
+    /**
+     * GET 璇锋眰锛氱敤浜� URL 楠岃瘉锛圱oken 鏍¢獙锛�
+     */
+    @GetMapping(produces = "text/plain;charset=utf-8")
+    public String verifyUrl(
+            @RequestParam("msg_signature") String msgSignature,
+            @RequestParam("timestamp") String timestamp,
+            @RequestParam("nonce") String nonce,
+            @RequestParam("echostr") String echostr) {
+        try {
+            log.info("鏀跺埌浼佷笟寰俊 URL 楠岃瘉璇锋眰锛歮sg_signature={}, timestamp={}, nonce={}, echostr={}", msgSignature, timestamp, nonce, echostr);
+
+            // 璋冪敤瀹樻柟 SDK 楠岃瘉骞惰В瀵�
+            String decryptedEchoStr = wxBizMsgCrypt.VerifyURL(msgSignature, timestamp, nonce, echostr);
+            log.info("瑙e瘑鍚庣殑 echostr: {}", decryptedEchoStr);
+
+            // 杩斿洖瑙e瘑鍚庣殑鍐呭锛堜紒涓氬井淇¤姹傚繀椤诲師鏍疯繑鍥烇級
+            return decryptedEchoStr;
+        } catch (Exception e) {
+            log.error("URL 楠岃瘉澶辫触", e);
+            return "fail";
+        }
+    }
+
+    /**
+     * POST 璇锋眰锛氭帴鏀朵紒涓氬井淇℃帹閫佺殑娑堟伅
+     */
+    @PostMapping(produces = "text/xml;charset=utf-8")
+    public String handleWeComCallback(@RequestBody String xmlData,
+                                      @RequestParam("msg_signature") String msgSignature,
+                                      @RequestParam("timestamp") String timestamp,
+                                      @RequestParam("nonce") String nonce) {
+        try {
+            log.info("鏀跺埌浼佷笟寰俊娑堟伅鎺ㄩ�侊細msg_signature={}, timestamp={}, nonce={}", msgSignature, timestamp, nonce);
+            log.info("鍘熷 XML 鏁版嵁: {}", xmlData);
+
+            // Step 1: 瑙e瘑娑堟伅
+            String plainXml = wxBizMsgCrypt.DecryptMsg(msgSignature, timestamp, nonce, xmlData);
+            log.info("瑙e瘑鍚庣殑鏄庢枃娑堟伅: {}", plainXml);
+
+            // Step 2: 瑙f瀽 XML 骞跺鐞嗕笟鍔¢�昏緫
+            Map<String, String> msgMap = parseXmlToMap(plainXml);
+            String eventType = msgMap.get("Event");
+            String content = msgMap.get("Content");
+
+            log.info("浜嬩欢绫诲瀷: {}, 娑堟伅鍐呭: {}", eventType, content);
+
+            // Step 3: 涓氬姟澶勭悊锛堢ず渚嬶細鍥炲 success锛�
+            String responseXml = "<xml><returncode>0</returncode><returndata>success</returndata></xml>";
+            return responseXml;
+        } catch (Exception e) {
+            log.error("澶勭悊浼佷笟寰俊娑堟伅澶辫触", e);
+            return "<xml><returncode>1</returncode><returndata>fail</returndata></xml>";
+        }
+    }
+
+    /**
+     * 灏� XML 杞负 Map
+     */
+    private Map<String, String> parseXmlToMap(String xml) throws Exception {
+        Map<String, String> map = new HashMap<>();
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+        DocumentBuilder builder = factory.newDocumentBuilder();
+        StringReader reader = new StringReader(xml);
+        InputSource source = new InputSource(reader);
+        Document doc = builder.parse(source);
+        Element root = doc.getDocumentElement();
+        NodeList list = root.getChildNodes();
+
+        for (int i = 0; i < list.getLength(); i++) {
+            if (list.item(i).getNodeType() == Document.ELEMENT_NODE) {
+                Element element = (Element) list.item(i);
+                map.put(element.getNodeName(), element.getTextContent());
+            }
+        }
+        return map;
+    }
+
+    //public static void main(String[] args) throws UnsupportedEncodingException {
+    //    String msg_signature = "eae930cbae5d988ed29f8aac6cf221016f81669e";
+    //    String timestamp = "1751356163";
+    //    String nonce = "16ljuxd4gd8";
+    //    String echostr = "Ax30h%2BharWss%2FeNNQl8x4KdzggrpmLFH8i%2F0mHqVGbcKcq1NeascovZV%2B08ooq5o0ng8RJ2WPyo69A8oGhKpxA%3D%3D";
+    //
+    //    String decode = URLDecoder.decode(echostr, "UTF-8");
+    //    //System.out.println(decode);
+    //    WeComCallbackController weComCallbackController = new WeComCallbackController();
+    //    String decryptedEchoStr = weComCallbackController.verifyUrl(msg_signature, timestamp, nonce, decode);
+    //    System.out.println(decryptedEchoStr);
+    //}
+}
diff --git a/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/utils/AesException.java b/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/utils/AesException.java
new file mode 100644
index 0000000..9b1ecce
--- /dev/null
+++ b/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/utils/AesException.java
@@ -0,0 +1,59 @@
+package org.jeecg.modules.qywx.message.utils;
+
+@SuppressWarnings("serial")
+public class AesException extends Exception {
+
+	public final static int OK = 0;
+	public final static int ValidateSignatureError = -40001;
+	public final static int ParseXmlError = -40002;
+	public final static int ComputeSignatureError = -40003;
+	public final static int IllegalAesKey = -40004;
+	public final static int ValidateCorpidError = -40005;
+	public final static int EncryptAESError = -40006;
+	public final static int DecryptAESError = -40007;
+	public final static int IllegalBuffer = -40008;
+	//public final static int EncodeBase64Error = -40009;
+	//public final static int DecodeBase64Error = -40010;
+	//public final static int GenReturnXmlError = -40011;
+
+	private int code;
+
+	private static String getMessage(int code) {
+		switch (code) {
+		case ValidateSignatureError:
+			return "绛惧悕楠岃瘉閿欒";
+		case ParseXmlError:
+			return "xml瑙f瀽澶辫触";
+		case ComputeSignatureError:
+			return "sha鍔犲瘑鐢熸垚绛惧悕澶辫触";
+		case IllegalAesKey:
+			return "SymmetricKey闈炴硶";
+		case ValidateCorpidError:
+			return "corpid鏍¢獙澶辫触";
+		case EncryptAESError:
+			return "aes鍔犲瘑澶辫触";
+		case DecryptAESError:
+			return "aes瑙e瘑澶辫触";
+		case IllegalBuffer:
+			return "瑙e瘑鍚庡緱鍒扮殑buffer闈炴硶";
+//		case EncodeBase64Error:
+//			return "base64鍔犲瘑閿欒";
+//		case DecodeBase64Error:
+//			return "base64瑙e瘑閿欒";
+//		case GenReturnXmlError:
+//			return "xml鐢熸垚澶辫触";
+		default:
+			return null; // cannot be
+		}
+	}
+
+	public int getCode() {
+		return code;
+	}
+
+	AesException(int code) {
+		super(getMessage(code));
+		this.code = code;
+	}
+
+}
diff --git a/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/utils/ByteGroup.java b/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/utils/ByteGroup.java
new file mode 100644
index 0000000..96d94ab
--- /dev/null
+++ b/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/utils/ByteGroup.java
@@ -0,0 +1,26 @@
+package org.jeecg.modules.qywx.message.utils;
+
+import java.util.ArrayList;
+
+class ByteGroup {
+	ArrayList<Byte> byteContainer = new ArrayList<Byte>();
+
+	public byte[] toBytes() {
+		byte[] bytes = new byte[byteContainer.size()];
+		for (int i = 0; i < byteContainer.size(); i++) {
+			bytes[i] = byteContainer.get(i);
+		}
+		return bytes;
+	}
+
+	public ByteGroup addBytes(byte[] bytes) {
+		for (byte b : bytes) {
+			byteContainer.add(b);
+		}
+		return this;
+	}
+
+	public int size() {
+		return byteContainer.size();
+	}
+}
diff --git a/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/utils/PKCS7Encoder.java b/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/utils/PKCS7Encoder.java
new file mode 100644
index 0000000..2bda687
--- /dev/null
+++ b/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/utils/PKCS7Encoder.java
@@ -0,0 +1,67 @@
+/**
+ * 瀵逛紒涓氬井淇″彂閫佺粰浼佷笟鍚庡彴鐨勬秷鎭姞瑙e瘑绀轰緥浠g爜.
+ * 
+ * @copyright Copyright (c) 1998-2014 Tencent Inc.
+ */
+
+// ------------------------------------------------------------------------
+
+package org.jeecg.modules.qywx.message.utils;
+
+import java.nio.charset.Charset;
+import java.util.Arrays;
+
+/**
+ * 鎻愪緵鍩轰簬PKCS7绠楁硶鐨勫姞瑙e瘑鎺ュ彛.
+ */
+class PKCS7Encoder {
+	static Charset CHARSET = Charset.forName("utf-8");
+	static int BLOCK_SIZE = 32;
+
+	/**
+	 * 鑾峰緱瀵规槑鏂囪繘琛岃ˉ浣嶅~鍏呯殑瀛楄妭.
+	 * 
+	 * @param count 闇�瑕佽繘琛屽~鍏呰ˉ浣嶆搷浣滅殑鏄庢枃瀛楄妭涓暟
+	 * @return 琛ラ綈鐢ㄧ殑瀛楄妭鏁扮粍
+	 */
+	static byte[] encode(int count) {
+		// 璁$畻闇�瑕佸~鍏呯殑浣嶆暟
+		int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);
+		if (amountToPad == 0) {
+			amountToPad = BLOCK_SIZE;
+		}
+		// 鑾峰緱琛ヤ綅鎵�鐢ㄧ殑瀛楃
+		char padChr = chr(amountToPad);
+		String tmp = new String();
+		for (int index = 0; index < amountToPad; index++) {
+			tmp += padChr;
+		}
+		return tmp.getBytes(CHARSET);
+	}
+
+	/**
+	 * 鍒犻櫎瑙e瘑鍚庢槑鏂囩殑琛ヤ綅瀛楃
+	 * 
+	 * @param decrypted 瑙e瘑鍚庣殑鏄庢枃
+	 * @return 鍒犻櫎琛ヤ綅瀛楃鍚庣殑鏄庢枃
+	 */
+	static byte[] decode(byte[] decrypted) {
+		int pad = (int) decrypted[decrypted.length - 1];
+		if (pad < 1 || pad > 32) {
+			pad = 0;
+		}
+		return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);
+	}
+
+	/**
+	 * 灏嗘暟瀛楄浆鍖栨垚ASCII鐮佸搴旂殑瀛楃锛岀敤浜庡鏄庢枃杩涜琛ョ爜
+	 * 
+	 * @param a 闇�瑕佽浆鍖栫殑鏁板瓧
+	 * @return 杞寲寰楀埌鐨勫瓧绗�
+	 */
+	static char chr(int a) {
+		byte target = (byte) (a & 0xFF);
+		return (char) target;
+	}
+
+}
diff --git a/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/utils/SHA1.java b/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/utils/SHA1.java
new file mode 100644
index 0000000..30f04f2
--- /dev/null
+++ b/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/utils/SHA1.java
@@ -0,0 +1,61 @@
+/**
+ * 瀵逛紒涓氬井淇″彂閫佺粰浼佷笟鍚庡彴鐨勬秷鎭姞瑙e瘑绀轰緥浠g爜.
+ * 
+ * @copyright Copyright (c) 1998-2014 Tencent Inc.
+ */
+
+// ------------------------------------------------------------------------
+
+package org.jeecg.modules.qywx.message.utils;
+
+import java.security.MessageDigest;
+import java.util.Arrays;
+
+/**
+ * SHA1 class
+ *
+ * 璁$畻娑堟伅绛惧悕鎺ュ彛.
+ */
+class SHA1 {
+
+	/**
+	 * 鐢⊿HA1绠楁硶鐢熸垚瀹夊叏绛惧悕
+	 * @param token 绁ㄦ嵁
+	 * @param timestamp 鏃堕棿鎴�
+	 * @param nonce 闅忔満瀛楃涓�
+	 * @param encrypt 瀵嗘枃
+	 * @return 瀹夊叏绛惧悕
+	 * @throws AesException 
+	 */
+	public static String getSHA1(String token, String timestamp, String nonce, String encrypt) throws AesException
+			  {
+		try {
+			String[] array = new String[] { token, timestamp, nonce, encrypt };
+			StringBuffer sb = new StringBuffer();
+			// 瀛楃涓叉帓搴�
+			Arrays.sort(array);
+			for (int i = 0; i < 4; i++) {
+				sb.append(array[i]);
+			}
+			String str = sb.toString();
+			// SHA1绛惧悕鐢熸垚
+			MessageDigest md = MessageDigest.getInstance("SHA-1");
+			md.update(str.getBytes());
+			byte[] digest = md.digest();
+
+			StringBuffer hexstr = new StringBuffer();
+			String shaHex = "";
+			for (int i = 0; i < digest.length; i++) {
+				shaHex = Integer.toHexString(digest[i] & 0xFF);
+				if (shaHex.length() < 2) {
+					hexstr.append(0);
+				}
+				hexstr.append(shaHex);
+			}
+			return hexstr.toString();
+		} catch (Exception e) {
+			e.printStackTrace();
+			throw new AesException(AesException.ComputeSignatureError);
+		}
+	}
+}
diff --git a/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/utils/Sample.java b/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/utils/Sample.java
new file mode 100644
index 0000000..41b870a
--- /dev/null
+++ b/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/utils/Sample.java
@@ -0,0 +1,136 @@
+package org.jeecg.modules.qywx.message.utils;
+
+import java.io.StringReader;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+public class Sample {
+
+	public static void main(String[] args) throws Exception {
+		String sToken = "QDG6eK";
+		String sCorpID = "wx5823bf96d3bd56c7";
+		String sEncodingAESKey = "jWmYm7qr5nMoAUwZRjGtBxmz3KA1tkAj3ykkR6q2B2C";
+
+		WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(sToken, sEncodingAESKey, sCorpID);
+		/*
+		------------浣跨敤绀轰緥涓�锛氶獙璇佸洖璋僓RL---------------
+		*浼佷笟寮�鍚洖璋冩ā寮忔椂锛屼紒涓氬井淇′細鍚戦獙璇乽rl鍙戦�佷竴涓猤et璇锋眰 
+		鍋囪鐐瑰嚮楠岃瘉鏃讹紝浼佷笟鏀跺埌绫讳技璇锋眰锛�
+		* GET /cgi-bin/wxpush?msg_signature=5c45ff5e21c57e6ad56bac8758b79b1d9ac89fd3&timestamp=1409659589&nonce=263014780&echostr=P9nAzCzyDtyTWESHep1vC5X9xho%2FqYX3Zpb4yKa9SKld1DsH3Iyt3tP3zNdtp%2B4RPcs8TgAE7OaBO%2BFZXvnaqQ%3D%3D 
+		* HTTP/1.1 Host: qy.weixin.qq.com
+
+		鎺ユ敹鍒拌璇锋眰鏃讹紝浼佷笟搴�		1.瑙f瀽鍑篏et璇锋眰鐨勫弬鏁帮紝鍖呮嫭娑堟伅浣撶鍚�(msg_signature)锛屾椂闂存埑(timestamp)锛岄殢鏈烘暟瀛椾覆(nonce)浠ュ強浼佷笟寰俊鎺ㄩ�佽繃鏉ョ殑闅忔満鍔犲瘑瀛楃涓�(echostr),
+		杩欎竴姝ユ敞鎰忎綔URL瑙g爜銆�
+		2.楠岃瘉娑堟伅浣撶鍚嶇殑姝g‘鎬� 
+		3. 瑙e瘑鍑篹chostr鍘熸枃锛屽皢鍘熸枃褰撲綔Get璇锋眰鐨剅esponse锛岃繑鍥炵粰浼佷笟寰俊
+		绗�2锛�3姝ュ彲浠ョ敤浼佷笟寰俊鎻愪緵鐨勫簱鍑芥暟VerifyURL鏉ュ疄鐜般��
+
+		*/
+		// 瑙f瀽鍑簎rl涓婄殑鍙傛暟鍊煎涓嬶細
+		// String sVerifyMsgSig = HttpUtils.ParseUrl("msg_signature");
+		String sVerifyMsgSig = "5c45ff5e21c57e6ad56bac8758b79b1d9ac89fd3";
+		// String sVerifyTimeStamp = HttpUtils.ParseUrl("timestamp");
+		String sVerifyTimeStamp = "1409659589";
+		// String sVerifyNonce = HttpUtils.ParseUrl("nonce");
+		String sVerifyNonce = "263014780";
+		// String sVerifyEchoStr = HttpUtils.ParseUrl("echostr");
+		String sVerifyEchoStr = "P9nAzCzyDtyTWESHep1vC5X9xho/qYX3Zpb4yKa9SKld1DsH3Iyt3tP3zNdtp+4RPcs8TgAE7OaBO+FZXvnaqQ==";
+		String sEchoStr; //闇�瑕佽繑鍥炵殑鏄庢枃
+		try {
+			sEchoStr = wxcpt.VerifyURL(sVerifyMsgSig, sVerifyTimeStamp,
+					sVerifyNonce, sVerifyEchoStr);
+			System.out.println("verifyurl echostr: " + sEchoStr);
+			// 楠岃瘉URL鎴愬姛锛屽皢sEchoStr杩斿洖
+			// HttpUtils.SetResponse(sEchoStr);
+		} catch (Exception e) {
+			//楠岃瘉URL澶辫触锛岄敊璇師鍥犺鏌ョ湅寮傚父
+			e.printStackTrace();
+		}
+
+		/*
+		------------浣跨敤绀轰緥浜岋細瀵圭敤鎴峰洖澶嶇殑娑堟伅瑙e瘑---------------
+		鐢ㄦ埛鍥炲娑堟伅鎴栬�呯偣鍑讳簨浠跺搷搴旀椂锛屼紒涓氫細鏀跺埌鍥炶皟娑堟伅锛屾娑堟伅鏄粡杩囦紒涓氬井淇″姞瀵嗕箣鍚庣殑瀵嗘枃浠ost褰㈠紡鍙戦�佺粰浼佷笟锛屽瘑鏂囨牸寮忚鍙傝�冨畼鏂规枃妗�
+		鍋囪浼佷笟鏀跺埌浼佷笟寰俊鐨勫洖璋冩秷鎭涓嬶細
+		POST /cgi-bin/wxpush? msg_signature=477715d11cdb4164915debcba66cb864d751f3e6&timestamp=1409659813&nonce=1372623149 HTTP/1.1
+		Host: qy.weixin.qq.com
+		Content-Length: 613
+		<xml>		<ToUserName><![CDATA[wx5823bf96d3bd56c7]]></ToUserName><Encrypt><![CDATA[RypEvHKD8QQKFhvQ6QleEB4J58tiPdvo+rtK1I9qca6aM/wvqnLSV5zEPeusUiX5L5X/0lWfrf0QADHHhGd3QczcdCUpj911L3vg3W/sYYvuJTs3TUUkSUXxaccAS0qhxchrRYt66wiSpGLYL42aM6A8dTT+6k4aSknmPj48kzJs8qLjvd4Xgpue06DOdnLxAUHzM6+kDZ+HMZfJYuR+LtwGc2hgf5gsijff0ekUNXZiqATP7PF5mZxZ3Izoun1s4zG4LUMnvw2r+KqCKIw+3IQH03v+BCA9nMELNqbSf6tiWSrXJB3LAVGUcallcrw8V2t9EL4EhzJWrQUax5wLVMNS0+rUPA3k22Ncx4XXZS9o0MBH27Bo6BpNelZpS+/uh9KsNlY6bHCmJU9p8g7m3fVKn28H3KDYA5Pl/T8Z1ptDAVe0lXdQ2YoyyH2uyPIGHBZZIs2pDBS8R07+qN+E7Q==]]></Encrypt>
+		<AgentID><![CDATA[218]]></AgentID>
+		</xml>
+
+		浼佷笟鏀跺埌post璇锋眰涔嬪悗搴旇		1.瑙f瀽鍑簎rl涓婄殑鍙傛暟锛屽寘鎷秷鎭綋绛惧悕(msg_signature)锛屾椂闂存埑(timestamp)浠ュ強闅忔満鏁板瓧涓�(nonce)
+		2.楠岃瘉娑堟伅浣撶鍚嶇殑姝g‘鎬с��
+		3.灏唒ost璇锋眰鐨勬暟鎹繘琛寈ml瑙f瀽锛屽苟灏�<Encrypt>鏍囩鐨勫唴瀹硅繘琛岃В瀵嗭紝瑙e瘑鍑烘潵鐨勬槑鏂囧嵆鏄敤鎴峰洖澶嶆秷鎭殑鏄庢枃锛屾槑鏂囨牸寮忚鍙傝�冨畼鏂规枃妗�
+		绗�2锛�3姝ュ彲浠ョ敤浼佷笟寰俊鎻愪緵鐨勫簱鍑芥暟DecryptMsg鏉ュ疄鐜般��
+		*/
+		// String sReqMsgSig = HttpUtils.ParseUrl("msg_signature");
+		String sReqMsgSig = "477715d11cdb4164915debcba66cb864d751f3e6";
+		// String sReqTimeStamp = HttpUtils.ParseUrl("timestamp");
+		String sReqTimeStamp = "1409659813";
+		// String sReqNonce = HttpUtils.ParseUrl("nonce");
+		String sReqNonce = "1372623149";
+		// post璇锋眰鐨勫瘑鏂囨暟鎹�
+		// sReqData = HttpUtils.PostData();
+		String sReqData = "<xml><ToUserName><![CDATA[wx5823bf96d3bd56c7]]></ToUserName><Encrypt><![CDATA[RypEvHKD8QQKFhvQ6QleEB4J58tiPdvo+rtK1I9qca6aM/wvqnLSV5zEPeusUiX5L5X/0lWfrf0QADHHhGd3QczcdCUpj911L3vg3W/sYYvuJTs3TUUkSUXxaccAS0qhxchrRYt66wiSpGLYL42aM6A8dTT+6k4aSknmPj48kzJs8qLjvd4Xgpue06DOdnLxAUHzM6+kDZ+HMZfJYuR+LtwGc2hgf5gsijff0ekUNXZiqATP7PF5mZxZ3Izoun1s4zG4LUMnvw2r+KqCKIw+3IQH03v+BCA9nMELNqbSf6tiWSrXJB3LAVGUcallcrw8V2t9EL4EhzJWrQUax5wLVMNS0+rUPA3k22Ncx4XXZS9o0MBH27Bo6BpNelZpS+/uh9KsNlY6bHCmJU9p8g7m3fVKn28H3KDYA5Pl/T8Z1ptDAVe0lXdQ2YoyyH2uyPIGHBZZIs2pDBS8R07+qN+E7Q==]]></Encrypt><AgentID><![CDATA[218]]></AgentID></xml>";
+
+		try {
+			String sMsg = wxcpt.DecryptMsg(sReqMsgSig, sReqTimeStamp, sReqNonce, sReqData);
+			System.out.println("after decrypt msg: " + sMsg);
+			// TODO: 瑙f瀽鍑烘槑鏂噚ml鏍囩鐨勫唴瀹硅繘琛屽鐞�
+			// For example:
+			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+			DocumentBuilder db = dbf.newDocumentBuilder();
+			StringReader sr = new StringReader(sMsg);
+			InputSource is = new InputSource(sr);
+			Document document = db.parse(is);
+
+			Element root = document.getDocumentElement();
+			NodeList nodelist1 = root.getElementsByTagName("Content");
+			String Content = nodelist1.item(0).getTextContent();
+			System.out.println("Content锛�" + Content);
+			
+		} catch (Exception e) {
+			// TODO
+			// 瑙e瘑澶辫触锛屽け璐ュ師鍥犺鏌ョ湅寮傚父
+			e.printStackTrace();
+		}
+
+	/*
+		------------浣跨敤绀轰緥涓夛細浼佷笟鍥炲鐢ㄦ埛娑堟伅鐨勫姞瀵�---------------
+		浼佷笟琚姩鍥炲鐢ㄦ埛鐨勬秷鎭篃闇�瑕佽繘琛屽姞瀵嗭紝骞朵笖鎷兼帴鎴愬瘑鏂囨牸寮忕殑xml涓层��
+		鍋囪浼佷笟闇�瑕佸洖澶嶇敤鎴风殑鏄庢枃濡備笅锛�
+		<xml>
+		<ToUserName><![CDATA[mycreate]]></ToUserName>
+		<FromUserName><![CDATA[wx5823bf96d3bd56c7]]></FromUserName>
+		<CreateTime>1348831860</CreateTime>
+		<MsgType><![CDATA[text]]></MsgType>
+		<Content><![CDATA[this is a test]]></Content>
+		<MsgId>1234567890123456</MsgId>
+		<AgentID>128</AgentID>
+		</xml>
+
+		涓轰簡灏嗘娈垫槑鏂囧洖澶嶇粰鐢ㄦ埛锛屼紒涓氬簲锛�			1.鑷繁鐢熸垚鏃堕棿鏃堕棿鎴�(timestamp),闅忔満鏁板瓧涓�(nonce)浠ヤ究鐢熸垚娑堟伅浣撶鍚嶏紝涔熷彲浠ョ洿鎺ョ敤浠庝紒涓氬井淇$殑post url涓婅В鏋愬嚭鐨勫搴斿�笺��
+		2.灏嗘槑鏂囧姞瀵嗗緱鍒板瘑鏂囥��	3.鐢ㄥ瘑鏂囷紝姝ラ1鐢熸垚鐨則imestamp,nonce鍜屼紒涓氬湪浼佷笟寰俊璁惧畾鐨則oken鐢熸垚娑堟伅浣撶鍚嶃��			4.灏嗗瘑鏂囷紝娑堟伅浣撶鍚嶏紝鏃堕棿鎴筹紝闅忔満鏁板瓧涓叉嫾鎺ユ垚xml鏍煎紡鐨勫瓧绗︿覆锛屽彂閫佺粰浼佷笟銆�
+		浠ヤ笂2锛�3锛�4姝ュ彲浠ョ敤浼佷笟寰俊鎻愪緵鐨勫簱鍑芥暟EncryptMsg鏉ュ疄鐜般��
+		*/
+		String sRespData = "<xml><ToUserName><![CDATA[mycreate]]></ToUserName><FromUserName><![CDATA[wx5823bf96d3bd56c7]]></FromUserName><CreateTime>1348831860</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[this is a test]]></Content><MsgId>1234567890123456</MsgId><AgentID>128</AgentID></xml>";
+		try{
+			String sEncryptMsg = wxcpt.EncryptMsg(sRespData, sReqTimeStamp, sReqNonce);
+			System.out.println("after encrypt sEncrytMsg: " + sEncryptMsg);
+			// 鍔犲瘑鎴愬姛
+			// TODO:
+			// HttpUtils.SetResponse(sEncryptMsg);
+		}
+		catch(Exception e)
+		{
+			e.printStackTrace();
+			// 鍔犲瘑澶辫触
+		}
+
+	}
+}
diff --git a/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/utils/WXBizMsgCrypt.java b/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/utils/WXBizMsgCrypt.java
new file mode 100644
index 0000000..cded1d1
--- /dev/null
+++ b/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/utils/WXBizMsgCrypt.java
@@ -0,0 +1,289 @@
+/**
+ * 瀵逛紒涓氬井淇″彂閫佺粰浼佷笟鍚庡彴鐨勬秷鎭姞瑙e瘑绀轰緥浠g爜.
+ * 
+ * @copyright Copyright (c) 1998-2014 Tencent Inc.
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * 閽堝org.apache.commons.codec.binary.Base64锛�
+ * 闇�瑕佸鍏ユ灦鍖卌ommons-codec-1.9锛堟垨commons-codec-1.8绛夊叾浠栫増鏈級
+ * 瀹樻柟涓嬭浇鍦板潃锛歨ttp://commons.apache.org/proper/commons-codec/download_codec.cgi
+ */
+package org.jeecg.modules.qywx.message.utils;
+
+import org.apache.commons.codec.binary.Base64;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.Random;
+
+/**
+ * 鎻愪緵鎺ユ敹鍜屾帹閫佺粰浼佷笟寰俊娑堟伅鐨勫姞瑙e瘑鎺ュ彛(UTF8缂栫爜鐨勫瓧绗︿覆).
+ * <ol>
+ * 	<li>绗笁鏂瑰洖澶嶅姞瀵嗘秷鎭粰浼佷笟寰俊</li>
+ * 	<li>绗笁鏂规敹鍒颁紒涓氬井淇″彂閫佺殑娑堟伅锛岄獙璇佹秷鎭殑瀹夊叏鎬э紝骞跺娑堟伅杩涜瑙e瘑銆�</li>
+ * </ol>
+ * 璇存槑锛氬紓甯竕ava.security.InvalidKeyException:illegal Key Size鐨勮В鍐虫柟妗�
+ * <ol>
+ * 	<li>鍦ㄥ畼鏂圭綉绔欎笅杞絁CE鏃犻檺鍒舵潈闄愮瓥鐣ユ枃浠讹紙JDK7鐨勪笅杞藉湴鍧�锛�
+ *      http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html</li>
+ * 	<li>涓嬭浇鍚庤В鍘嬶紝鍙互鐪嬪埌local_policy.jar鍜孶S_export_policy.jar浠ュ強readme.txt</li>
+ * 	<li>濡傛灉瀹夎浜咼RE锛屽皢涓や釜jar鏂囦欢鏀惧埌%JRE_HOME%\lib\security鐩綍涓嬭鐩栧師鏉ョ殑鏂囦欢</li>
+ * 	<li>濡傛灉瀹夎浜咼DK锛屽皢涓や釜jar鏂囦欢鏀惧埌%JDK_HOME%\jre\lib\security鐩綍涓嬭鐩栧師鏉ユ枃浠�</li>
+ * </ol>
+ */
+public class WXBizMsgCrypt {
+	static Charset CHARSET = Charset.forName("utf-8");
+	Base64 base64 = new Base64();
+	byte[] aesKey;
+	String token;
+	String receiveid;
+
+	/**
+	 * 鏋勯�犲嚱鏁�
+	 * @param token 浼佷笟寰俊鍚庡彴锛屽紑鍙戣�呰缃殑token
+	 * @param encodingAesKey 浼佷笟寰俊鍚庡彴锛屽紑鍙戣�呰缃殑EncodingAESKey
+	 * @param receiveid, 涓嶅悓鍦烘櫙鍚箟涓嶅悓锛岃瑙佹枃妗�
+	 * 
+	 * @throws AesException 鎵ц澶辫触锛岃鏌ョ湅璇ュ紓甯哥殑閿欒鐮佸拰鍏蜂綋鐨勯敊璇俊鎭�
+	 */
+	public WXBizMsgCrypt(String token, String encodingAesKey, String receiveid) throws AesException {
+		if (encodingAesKey.length() != 43) {
+			throw new AesException(AesException.IllegalAesKey);
+		}
+
+		this.token = token;
+		this.receiveid = receiveid;
+		aesKey = Base64.decodeBase64(encodingAesKey + "=");
+	}
+
+	// 鐢熸垚4涓瓧鑺傜殑缃戠粶瀛楄妭搴�
+	byte[] getNetworkBytesOrder(int sourceNumber) {
+		byte[] orderBytes = new byte[4];
+		orderBytes[3] = (byte) (sourceNumber & 0xFF);
+		orderBytes[2] = (byte) (sourceNumber >> 8 & 0xFF);
+		orderBytes[1] = (byte) (sourceNumber >> 16 & 0xFF);
+		orderBytes[0] = (byte) (sourceNumber >> 24 & 0xFF);
+		return orderBytes;
+	}
+
+	// 杩樺師4涓瓧鑺傜殑缃戠粶瀛楄妭搴�
+	int recoverNetworkBytesOrder(byte[] orderBytes) {
+		int sourceNumber = 0;
+		for (int i = 0; i < 4; i++) {
+			sourceNumber <<= 8;
+			sourceNumber |= orderBytes[i] & 0xff;
+		}
+		return sourceNumber;
+	}
+
+	// 闅忔満鐢熸垚16浣嶅瓧绗︿覆
+	String getRandomStr() {
+		String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+		Random random = new Random();
+		StringBuffer sb = new StringBuffer();
+		for (int i = 0; i < 16; i++) {
+			int number = random.nextInt(base.length());
+			sb.append(base.charAt(number));
+		}
+		return sb.toString();
+	}
+
+	/**
+	 * 瀵规槑鏂囪繘琛屽姞瀵�.
+	 * 
+	 * @param text 闇�瑕佸姞瀵嗙殑鏄庢枃
+	 * @return 鍔犲瘑鍚巄ase64缂栫爜鐨勫瓧绗︿覆
+	 * @throws AesException aes鍔犲瘑澶辫触
+	 */
+	String encrypt(String randomStr, String text) throws AesException {
+		ByteGroup byteCollector = new ByteGroup();
+		byte[] randomStrBytes = randomStr.getBytes(CHARSET);
+		byte[] textBytes = text.getBytes(CHARSET);
+		byte[] networkBytesOrder = getNetworkBytesOrder(textBytes.length);
+		byte[] receiveidBytes = receiveid.getBytes(CHARSET);
+
+		// randomStr + networkBytesOrder + text + receiveid
+		byteCollector.addBytes(randomStrBytes);
+		byteCollector.addBytes(networkBytesOrder);
+		byteCollector.addBytes(textBytes);
+		byteCollector.addBytes(receiveidBytes);
+
+		// ... + pad: 浣跨敤鑷畾涔夌殑濉厖鏂瑰紡瀵规槑鏂囪繘琛岃ˉ浣嶅~鍏�
+		byte[] padBytes = PKCS7Encoder.encode(byteCollector.size());
+		byteCollector.addBytes(padBytes);
+
+		// 鑾峰緱鏈�缁堢殑瀛楄妭娴�, 鏈姞瀵�
+		byte[] unencrypted = byteCollector.toBytes();
+
+		try {
+			// 璁剧疆鍔犲瘑妯″紡涓篈ES鐨凜BC妯″紡
+			Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
+			SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
+			IvParameterSpec iv = new IvParameterSpec(aesKey, 0, 16);
+			cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
+
+			// 鍔犲瘑
+			byte[] encrypted = cipher.doFinal(unencrypted);
+
+			// 浣跨敤BASE64瀵瑰姞瀵嗗悗鐨勫瓧绗︿覆杩涜缂栫爜
+			String base64Encrypted = base64.encodeToString(encrypted);
+
+			return base64Encrypted;
+		} catch (Exception e) {
+			e.printStackTrace();
+			throw new AesException(AesException.EncryptAESError);
+		}
+	}
+
+	/**
+	 * 瀵瑰瘑鏂囪繘琛岃В瀵�.
+	 * 
+	 * @param text 闇�瑕佽В瀵嗙殑瀵嗘枃
+	 * @return 瑙e瘑寰楀埌鐨勬槑鏂�
+	 * @throws AesException aes瑙e瘑澶辫触
+	 */
+	String decrypt(String text) throws AesException {
+		byte[] original;
+		try {
+			// 璁剧疆瑙e瘑妯″紡涓篈ES鐨凜BC妯″紡
+			Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
+			SecretKeySpec key_spec = new SecretKeySpec(aesKey, "AES");
+			IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16));
+			//IvParameterSpec iv = new IvParameterSpec(new byte[16]); // 鍥哄畾 IV
+			cipher.init(Cipher.DECRYPT_MODE, key_spec, iv);
+
+			// 浣跨敤BASE64瀵瑰瘑鏂囪繘琛岃В鐮�
+			byte[] encrypted = Base64.decodeBase64(text);
+
+			// 瑙e瘑
+			original = cipher.doFinal(encrypted);
+		} catch (Exception e) {
+			e.printStackTrace();
+			throw new AesException(AesException.DecryptAESError);
+		}
+
+		String xmlContent, from_receiveid;
+		try {
+			// 鍘婚櫎琛ヤ綅瀛楃
+			byte[] bytes = PKCS7Encoder.decode(original);
+
+			// 鍒嗙16浣嶉殢鏈哄瓧绗︿覆,缃戠粶瀛楄妭搴忓拰receiveid
+			byte[] networkOrder = Arrays.copyOfRange(bytes, 16, 20);
+
+			int xmlLength = recoverNetworkBytesOrder(networkOrder);
+
+			xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET);
+			from_receiveid = new String(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length),
+					CHARSET);
+		} catch (Exception e) {
+			e.printStackTrace();
+			throw new AesException(AesException.IllegalBuffer);
+		}
+
+		// receiveid涓嶇浉鍚岀殑鎯呭喌
+		if (!from_receiveid.equals(receiveid)) {
+			throw new AesException(AesException.ValidateCorpidError);
+		}
+		return xmlContent;
+
+	}
+
+	/**
+	 * 灏嗕紒涓氬井淇″洖澶嶇敤鎴风殑娑堟伅鍔犲瘑鎵撳寘.
+	 * <ol>
+	 * 	<li>瀵硅鍙戦�佺殑娑堟伅杩涜AES-CBC鍔犲瘑</li>
+	 * 	<li>鐢熸垚瀹夊叏绛惧悕</li>
+	 * 	<li>灏嗘秷鎭瘑鏂囧拰瀹夊叏绛惧悕鎵撳寘鎴恱ml鏍煎紡</li>
+	 * </ol>
+	 * 
+	 * @param replyMsg 浼佷笟寰俊寰呭洖澶嶇敤鎴风殑娑堟伅锛寈ml鏍煎紡鐨勫瓧绗︿覆
+	 * @param timeStamp 鏃堕棿鎴筹紝鍙互鑷繁鐢熸垚锛屼篃鍙互鐢║RL鍙傛暟鐨則imestamp
+	 * @param nonce 闅忔満涓诧紝鍙互鑷繁鐢熸垚锛屼篃鍙互鐢║RL鍙傛暟鐨刵once
+	 * 
+	 * @return 鍔犲瘑鍚庣殑鍙互鐩存帴鍥炲鐢ㄦ埛鐨勫瘑鏂囷紝鍖呮嫭msg_signature, timestamp, nonce, encrypt鐨剎ml鏍煎紡鐨勫瓧绗︿覆
+	 * @throws AesException 鎵ц澶辫触锛岃鏌ョ湅璇ュ紓甯哥殑閿欒鐮佸拰鍏蜂綋鐨勯敊璇俊鎭�
+	 */
+	public String EncryptMsg(String replyMsg, String timeStamp, String nonce) throws AesException {
+		// 鍔犲瘑
+		String encrypt = encrypt(getRandomStr(), replyMsg);
+
+		// 鐢熸垚瀹夊叏绛惧悕
+		if (timeStamp == "") {
+			timeStamp = Long.toString(System.currentTimeMillis());
+		}
+
+		String signature = SHA1.getSHA1(token, timeStamp, nonce, encrypt);
+
+		// System.out.println("鍙戦�佺粰骞冲彴鐨勭鍚嶆槸: " + signature[1].toString());
+		// 鐢熸垚鍙戦�佺殑xml
+		String result = XMLParse.generate(encrypt, signature, timeStamp, nonce);
+		return result;
+	}
+
+	/**
+	 * 妫�楠屾秷鎭殑鐪熷疄鎬э紝骞朵笖鑾峰彇瑙e瘑鍚庣殑鏄庢枃.
+	 * <ol>
+	 * 	<li>鍒╃敤鏀跺埌鐨勫瘑鏂囩敓鎴愬畨鍏ㄧ鍚嶏紝杩涜绛惧悕楠岃瘉</li>
+	 * 	<li>鑻ラ獙璇侀�氳繃锛屽垯鎻愬彇xml涓殑鍔犲瘑娑堟伅</li>
+	 * 	<li>瀵规秷鎭繘琛岃В瀵�</li>
+	 * </ol>
+	 * 
+	 * @param msgSignature 绛惧悕涓诧紝瀵瑰簲URL鍙傛暟鐨刴sg_signature
+	 * @param timeStamp 鏃堕棿鎴筹紝瀵瑰簲URL鍙傛暟鐨則imestamp
+	 * @param nonce 闅忔満涓诧紝瀵瑰簲URL鍙傛暟鐨刵once
+	 * @param postData 瀵嗘枃锛屽搴擯OST璇锋眰鐨勬暟鎹�
+	 * 
+	 * @return 瑙e瘑鍚庣殑鍘熸枃
+	 * @throws AesException 鎵ц澶辫触锛岃鏌ョ湅璇ュ紓甯哥殑閿欒鐮佸拰鍏蜂綋鐨勯敊璇俊鎭�
+	 */
+	public String DecryptMsg(String msgSignature, String timeStamp, String nonce, String postData)
+			throws AesException {
+
+		// 瀵嗛挜锛屽叕浼楄处鍙风殑app secret
+		// 鎻愬彇瀵嗘枃
+		Object[] encrypt = XMLParse.extract(postData);
+
+		// 楠岃瘉瀹夊叏绛惧悕
+		String signature = SHA1.getSHA1(token, timeStamp, nonce, encrypt[1].toString());
+
+		// 鍜孶RL涓殑绛惧悕姣旇緝鏄惁鐩哥瓑
+		// System.out.println("绗笁鏂规敹鍒癠RL涓殑绛惧悕锛�" + msg_sign);
+		// System.out.println("绗笁鏂规牎楠岀鍚嶏細" + signature);
+		if (!signature.equals(msgSignature)) {
+			throw new AesException(AesException.ValidateSignatureError);
+		}
+
+		// 瑙e瘑
+		String result = decrypt(encrypt[1].toString());
+		return result;
+	}
+
+	/**
+	 * 楠岃瘉URL
+	 * @param msgSignature 绛惧悕涓诧紝瀵瑰簲URL鍙傛暟鐨刴sg_signature
+	 * @param timeStamp 鏃堕棿鎴筹紝瀵瑰簲URL鍙傛暟鐨則imestamp
+	 * @param nonce 闅忔満涓诧紝瀵瑰簲URL鍙傛暟鐨刵once
+	 * @param echoStr 闅忔満涓诧紝瀵瑰簲URL鍙傛暟鐨別chostr
+	 * 
+	 * @return 瑙e瘑涔嬪悗鐨別chostr
+	 * @throws AesException 鎵ц澶辫触锛岃鏌ョ湅璇ュ紓甯哥殑閿欒鐮佸拰鍏蜂綋鐨勯敊璇俊鎭�
+	 */
+	public String VerifyURL(String msgSignature, String timeStamp, String nonce, String echoStr)
+			throws AesException {
+		String signature = SHA1.getSHA1(token, timeStamp, nonce, echoStr);
+
+		if (!signature.equals(msgSignature)) {
+			throw new AesException(AesException.ValidateSignatureError);
+		}
+
+		String result = decrypt(echoStr);
+		return result;
+	}
+
+}
\ No newline at end of file
diff --git a/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/utils/XMLParse.java b/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/utils/XMLParse.java
new file mode 100644
index 0000000..89ed6a4
--- /dev/null
+++ b/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/utils/XMLParse.java
@@ -0,0 +1,104 @@
+/**
+ * 瀵逛紒涓氬井淇″彂閫佺粰浼佷笟鍚庡彴鐨勬秷鎭姞瑙e瘑绀轰緥浠g爜.
+ * 
+ * @copyright Copyright (c) 1998-2014 Tencent Inc.
+ */
+
+// ------------------------------------------------------------------------
+
+package org.jeecg.modules.qywx.message.utils;
+
+import java.io.StringReader;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+/**
+ * XMLParse class
+ *
+ * 鎻愪緵鎻愬彇娑堟伅鏍煎紡涓殑瀵嗘枃鍙婄敓鎴愬洖澶嶆秷鎭牸寮忕殑鎺ュ彛.
+ */
+class XMLParse {
+
+	/**
+	 * 鎻愬彇鍑簒ml鏁版嵁鍖呬腑鐨勫姞瀵嗘秷鎭�
+	 * @param xmltext 寰呮彁鍙栫殑xml瀛楃涓�
+	 * @return 鎻愬彇鍑虹殑鍔犲瘑娑堟伅瀛楃涓�
+	 * @throws AesException 
+	 */
+	public static Object[] extract(String xmltext) throws AesException     {
+		Object[] result = new Object[3];
+		try {
+			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+			
+			String FEATURE = null;
+			// This is the PRIMARY defense. If DTDs (doctypes) are disallowed, almost all XML entity attacks are prevented
+			// Xerces 2 only - http://xerces.apache.org/xerces2-j/features.html#disallow-doctype-decl
+			FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
+			dbf.setFeature(FEATURE, true);
+			
+			// If you can't completely disable DTDs, then at least do the following:
+			// Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-general-entities
+			// Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-general-entities
+			// JDK7+ - http://xml.org/sax/features/external-general-entities 
+			FEATURE = "http://xml.org/sax/features/external-general-entities";
+			dbf.setFeature(FEATURE, false);
+			
+			// Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-parameter-entities
+			// Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-parameter-entities
+			// JDK7+ - http://xml.org/sax/features/external-parameter-entities 
+			FEATURE = "http://xml.org/sax/features/external-parameter-entities";
+			dbf.setFeature(FEATURE, false);
+			
+			// Disable external DTDs as well
+			FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
+			dbf.setFeature(FEATURE, false);
+			
+			// and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks"
+			dbf.setXIncludeAware(false);
+			dbf.setExpandEntityReferences(false);
+			
+			// And, per Timothy Morgan: "If for some reason support for inline DOCTYPEs are a requirement, then 
+			// ensure the entity settings are disabled (as shown above) and beware that SSRF attacks
+			// (http://cwe.mitre.org/data/definitions/918.html) and denial 
+			// of service attacks (such as billion laughs or decompression bombs via "jar:") are a risk."
+			
+			// remaining parser logic
+			DocumentBuilder db = dbf.newDocumentBuilder();
+			StringReader sr = new StringReader(xmltext);
+			InputSource is = new InputSource(sr);
+			Document document = db.parse(is);
+
+			Element root = document.getDocumentElement();
+			NodeList nodelist1 = root.getElementsByTagName("Encrypt");
+			result[0] = 0;
+			result[1] = nodelist1.item(0).getTextContent();
+			return result;
+		} catch (Exception e) {
+			e.printStackTrace();
+			throw new AesException(AesException.ParseXmlError);
+		}
+	}
+
+	/**
+	 * 鐢熸垚xml娑堟伅
+	 * @param encrypt 鍔犲瘑鍚庣殑娑堟伅瀵嗘枃
+	 * @param signature 瀹夊叏绛惧悕
+	 * @param timestamp 鏃堕棿鎴�
+	 * @param nonce 闅忔満瀛楃涓�
+	 * @return 鐢熸垚鐨剎ml瀛楃涓�
+	 */
+	public static String generate(String encrypt, String signature, String timestamp, String nonce) {
+
+		String format = "<xml>\n" + "<Encrypt><![CDATA[%1$s]]></Encrypt>\n"
+				+ "<MsgSignature><![CDATA[%2$s]]></MsgSignature>\n"
+				+ "<TimeStamp>%3$s</TimeStamp>\n" + "<Nonce><![CDATA[%4$s]]></Nonce>\n" + "</xml>";
+		return String.format(format, encrypt, signature, timestamp, nonce);
+
+	}
+}
diff --git a/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/vo/TemplateCard.java b/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/vo/TemplateCard.java
new file mode 100644
index 0000000..cf7772c
--- /dev/null
+++ b/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/vo/TemplateCard.java
@@ -0,0 +1,20 @@
+package org.jeecg.modules.qywx.message.vo;
+
+import lombok.Data;
+
+/**
+ * 浼佷笟寰俊妯℃澘鍗$墖娑堟伅锛堟枃鏈�氱煡鍨嬶級
+ */
+@Data
+public class TemplateCard {
+    private String touser;//鎴愬憳ID鍒楄〃锛堟秷鎭帴鏀惰�咃紝澶氫釜鎺ユ敹鑰呯敤鈥榺鈥欏垎闅旓紝鏈�澶氭敮鎸�1000涓級銆傜壒娈婃儏鍐碉細鎸囧畾涓篅all锛屽垯鍚戝叧娉ㄨ浼佷笟搴旂敤鐨勫叏閮ㄦ垚鍛樺彂閫�
+    private String toparty;//閮ㄩ棬ID鍒楄〃锛屽涓帴鏀惰�呯敤鈥榺鈥欏垎闅旓紝鏈�澶氭敮鎸�100涓�傚綋touser涓篅all鏃跺拷鐣ユ湰鍙�
+    private String totag;//鏍囩ID鍒楄〃锛屽涓帴鏀惰�呯敤鈥榺鈥欏垎闅旓紝鏈�澶氭敮鎸�100涓�傚綋touser涓篅all鏃跺拷鐣ユ湰鍙傛暟
+    private int agentid;//浼佷笟搴旂敤鐨刬d锛屾暣鍨嬨�傚彲鍦ㄥ簲鐢ㄧ殑璁剧疆椤甸潰鏌ョ湅
+    private TemplateCardEntity template_card;//娑堟伅瀹炰綋
+    private String enable_id_trans;// 鍚�	琛ㄧず鏄惁寮�鍚痠d杞瘧锛�0琛ㄧず鍚︼紝1琛ㄧず鏄紝榛樿0
+    private String enable_duplicate_check;// 鍚�	琛ㄧず鏄惁寮�鍚噸澶嶆秷鎭鏌ワ紝0琛ㄧず鍚︼紝1琛ㄧず鏄紝榛樿0
+    private String duplicate_check_interval;// 鍚�	琛ㄧず鏄惁閲嶅娑堟伅妫�鏌ョ殑鏃堕棿闂撮殧锛岄粯璁�1800s锛屾渶澶т笉瓒呰繃4灏忔椂
+    private String msgtype = "template_card";//娑堟伅绫诲瀷锛屾鏃跺浐瀹氫负锛歵emplate_card
+
+}
diff --git a/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/vo/TemplateCardEntity.java b/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/vo/TemplateCardEntity.java
new file mode 100644
index 0000000..8fdf7b5
--- /dev/null
+++ b/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/qywx/message/vo/TemplateCardEntity.java
@@ -0,0 +1,94 @@
+package org.jeecg.modules.qywx.message.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 妯℃澘鍗$墖娑堟伅瀹炰綋
+ */
+@Data
+public class TemplateCardEntity {
+    private Source source;//鍚�	鍗$墖鏉ユ簮鏍峰紡淇℃伅锛屼笉闇�瑕佹潵婧愭牱寮忓彲涓嶅~鍐�
+    private ActionMenu action_menu;//鍚�	鍗$墖鍙充笂瑙掓洿澶氭搷浣滄寜閽�
+    private String task_id;//鍚�	浠诲姟id锛屽悓涓�涓簲鐢ㄤ换鍔d涓嶈兘閲嶅锛屽彧鑳界敱鏁板瓧銆佸瓧姣嶅拰鈥淿-@鈥濈粍鎴愶紝鏈�闀�128瀛楄妭锛屽~浜哸ction_menu瀛楁鐨勮瘽鏈瓧娈靛繀濉�
+    private MainTitle main_title;
+    private QuoteArea quote_area;//鍚�	寮曠敤鏂囩尞鏍峰紡
+    private EmphasisContent emphasis_content;
+    private String sub_title_text;//浜岀骇鏅�氭枃鏈紝寤鸿涓嶈秴杩�160涓瓧锛岋紙鏀寔id杞瘧锛�
+    private List<HorizontalContent> horizontal_content_list;
+    private List<Jump> jump_list;//鍚�	璺宠浆鎸囧紩鏍峰紡鐨勫垪琛紝璇ュ瓧娈靛彲涓虹┖鏁扮粍锛屼絾鏈夋暟鎹殑璇濋渶纭瀵瑰簲瀛楁鏄惁蹇呭~锛屽垪琛ㄩ暱搴︿笉瓒呰繃3
+    private CardAction card_action;//鏄�	鏁翠綋鍗$墖鐨勭偣鍑昏烦杞簨浠讹紝text_notice蹇呭~鏈瓧娈�
+    //鍥炬枃灞曠ず鍨嬪崱绁ㄧ嫭鏈夌殑鍙傛暟
+    private CardImage card_image;
+    private String card_type = "text_notice";// 妯℃澘鍗$墖绫诲瀷锛屾枃鏈�氱煡鍨嬪崱鐗囧~鍐� "text_notice"
+
+    @Data
+    public static class Source {
+        private String icon_url;//鍚�	鏉ユ簮鍥剧墖鐨剈rl锛屾潵婧愬浘鐗囩殑灏哄寤鸿涓�72*72
+        private String desc;//鍚�	鏉ユ簮鍥剧墖鐨勬弿杩帮紝寤鸿涓嶈秴杩�20涓瓧锛岋紙鏀寔id杞瘧锛�
+        private String desc_color;//鍚�	鏉ユ簮鏂囧瓧鐨勯鑹诧紝鐩墠鏀寔锛�0(榛樿) 鐏拌壊锛�1 榛戣壊锛�2 绾㈣壊锛�3 缁胯壊
+    }
+
+    @Data
+    public static class ActionMenu {
+        private String desc;//鍚�	鏇村鎿嶄綔鐣岄潰鐨勬弿杩�
+        private List<ActionList> action_list;//鏄�	鎿嶄綔鍒楄〃锛屽垪琛ㄩ暱搴﹀彇鍊艰寖鍥翠负 [1, 3]
+
+        @Data
+        @AllArgsConstructor
+        public static class ActionList {
+            private String key;//鏄�	鎿嶄綔key鍊硷紝鐢ㄦ埛鐐瑰嚮鍚庯紝浼氫骇鐢熷洖璋冧簨浠跺皢鏈弬鏁颁綔涓篍ventKey杩斿洖锛屽洖璋冧簨浠朵細甯︿笂璇ey鍊硷紝鏈�闀挎敮鎸�1024瀛楄妭锛屼笉鍙噸澶�
+            private String text;//鏄�	鎿嶄綔鐨勬弿杩版枃妗�
+        }
+    }
+
+    @Data
+    public static class MainTitle {
+        private String title;//鍚�	涓�绾ф爣棰橈紝寤鸿涓嶈秴杩�36涓瓧锛屾枃鏈�氱煡鍨嬪崱鐗囨湰瀛楁闈炲繀濉紝浣嗕笉鍙湰瀛楁鍜宻ub_title_text閮戒笉濉紝锛堟敮鎸乮d杞瘧锛�
+        private String desc;//鍚�	鏍囬杈呭姪淇℃伅锛屽缓璁笉瓒呰繃44涓瓧锛岋紙鏀寔id杞瘧锛�
+    }
+
+    @Data
+    private class QuoteArea {
+        private int type;//鍚�	寮曠敤鏂囩尞鏍峰紡鍖哄煙鐐瑰嚮浜嬩欢锛�0鎴栦笉濉唬琛ㄦ病鏈夌偣鍑讳簨浠讹紝1 浠h〃璺宠浆url锛�2 浠h〃璺宠浆灏忕▼搴�
+        private String url;//鍚�	鐐瑰嚮璺宠浆鐨剈rl锛宷uote_area.type鏄�1鏃跺繀濉�
+        private String title;//鍚�	寮曠敤鏂囩尞鏍峰紡鐨勬爣棰�
+        private String quote_text;//鍚�	寮曠敤鏂囩尞鏍峰紡鐨勫紩鐢ㄦ枃妗�
+    }
+
+    @Data
+    private class EmphasisContent {
+        private String title;//鍚�	鍏抽敭鏁版嵁鏍峰紡鐨勬暟鎹唴瀹癸紝寤鸿涓嶈秴杩�14涓瓧
+        private String desc;//鍚�	鍏抽敭鏁版嵁鏍峰紡鐨勬暟鎹弿杩板唴瀹癸紝寤鸿涓嶈秴杩�22涓瓧
+    }
+
+    @Data
+    public static class HorizontalContent {
+        private String keyname;//鏄�	浜岀骇鏍囬锛屽缓璁笉瓒呰繃5涓瓧
+        private String value;//鍚�	浜岀骇鏂囨湰锛屽鏋渉orizontal_content_list.type鏄�2锛岃瀛楁浠h〃鏂囦欢鍚嶇О锛堣鍖呭惈鏂囦欢绫诲瀷锛夛紝寤鸿涓嶈秴杩�30涓瓧锛岋紙鏀寔id杞瘧锛�
+    }
+
+    @Data
+    @AllArgsConstructor
+    public static class Jump {
+        private int type;//鍚�	璺宠浆閾炬帴绫诲瀷锛�0鎴栦笉濉唬琛ㄤ笉鏄摼鎺ワ紝1 浠h〃璺宠浆url锛�2 浠h〃璺宠浆灏忕▼搴�
+        private String title;//鏄�	璺宠浆閾炬帴鏍峰紡鐨勬枃妗堝唴瀹癸紝寤鸿涓嶈秴杩�18涓瓧
+        private String url;//鍚�	璺宠浆閾炬帴鐨剈rl锛宩ump_list.type鏄�1鏃跺繀濉�
+    }
+
+    @Data
+    public static class CardAction {
+        private int type;//鏄�	璺宠浆浜嬩欢绫诲瀷锛�1 浠h〃璺宠浆url锛�2 浠h〃鎵撳紑灏忕▼搴忋�倀ext_notice鍗$墖妯$増涓瀛楁鍙栧�艰寖鍥翠负[1,2]
+        private String url;//鍚�	璺宠浆浜嬩欢鐨剈rl锛宑ard_action.type鏄�1鏃跺繀濉�
+        private String appid;//鍚�	璺宠浆浜嬩欢鐨勫皬绋嬪簭鐨刟ppid锛屽繀椤绘槸涓庡綋鍓嶅簲鐢ㄥ叧鑱旂殑灏忕▼搴忥紝card_action.type鏄�2鏃跺繀濉�
+        private String pagepath;//鍚�	璺宠浆浜嬩欢鐨勫皬绋嬪簭鐨刾agepath锛宑ard_action.type鏄�2鏃堕�夊~
+    }
+
+    @Data
+    public static class CardImage {
+        private String url;//鏄�	鍥剧墖鐨剈rl
+        private String aspect_ratio;//鍚�	鍥剧墖鐨勫楂樻瘮锛屽楂樻瘮瑕佸皬浜�2.25锛屽ぇ浜�1.3锛屼笉濉鍙傛暟榛樿1.3
+    }
+}

--
Gitblit v1.9.3