diff --git a/pom.xml b/pom.xml
index 19050fc..3612ec3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -18,6 +18,7 @@
1.8
+ 3.8.0
@@ -216,8 +217,27 @@
1.4.8
+
+ com.github.binarywang
+ weixin-java-open
+ ${weixin-java-open.version}
+
-
+
+ redis.clients
+ jedis
+ 2.9.0
+
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+ true
+
+
+ com.thoughtworks.xstream
+ xstream
+ 1.4.10
+
diff --git a/src/main/java/com/bsd/say/config/RedisProperies.java b/src/main/java/com/bsd/say/config/RedisProperies.java
new file mode 100644
index 0000000..9238d5b
--- /dev/null
+++ b/src/main/java/com/bsd/say/config/RedisProperies.java
@@ -0,0 +1,124 @@
+package com.bsd.say.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import redis.clients.jedis.JedisPoolConfig;
+import redis.clients.jedis.Protocol;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLSocketFactory;
+
+/**
+ * @author 007
+ */
+@ConfigurationProperties(prefix = "wechat.redis")
+public class RedisProperies extends JedisPoolConfig {
+ private String host = "111.229.204.101";
+ private int port = 63790;
+ private String password = "1qaz2wsx";
+ private int database = 4;
+ private int connectionTimeout = Protocol.DEFAULT_TIMEOUT;
+ private int soTimeout = Protocol.DEFAULT_TIMEOUT;
+ private String clientName;
+ private boolean ssl;
+ private SSLSocketFactory sslSocketFactory;
+ private SSLParameters sslParameters;
+ private HostnameVerifier hostnameVerifier;
+
+ public boolean isSsl() {
+ return ssl;
+ }
+
+ public void setSsl(boolean ssl) {
+ this.ssl = ssl;
+ }
+
+ public SSLSocketFactory getSslSocketFactory() {
+ return sslSocketFactory;
+ }
+
+ public void setSslSocketFactory(SSLSocketFactory sslSocketFactory) {
+ this.sslSocketFactory = sslSocketFactory;
+ }
+
+ public SSLParameters getSslParameters() {
+ return sslParameters;
+ }
+
+ public void setSslParameters(SSLParameters sslParameters) {
+ this.sslParameters = sslParameters;
+ }
+
+ public HostnameVerifier getHostnameVerifier() {
+ return hostnameVerifier;
+ }
+
+ public void setHostnameVerifier(HostnameVerifier hostnameVerifier) {
+ this.hostnameVerifier = hostnameVerifier;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public void setHost(String host) {
+ if (host == null || "".equals(host)) {
+ host = Protocol.DEFAULT_HOST;
+ }
+ this.host = host;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ if ("".equals(password)) {
+ password = null;
+ }
+ this.password = password;
+ }
+
+ public int getDatabase() {
+ return database;
+ }
+
+ public void setDatabase(int database) {
+ this.database = database;
+ }
+
+ public String getClientName() {
+ return clientName;
+ }
+
+ public void setClientName(String clientName) {
+ if ("".equals(clientName)) {
+ clientName = null;
+ }
+ this.clientName = clientName;
+ }
+
+ public int getConnectionTimeout() {
+ return connectionTimeout;
+ }
+
+ public void setConnectionTimeout(int connectionTimeout) {
+ this.connectionTimeout = connectionTimeout;
+ }
+
+ public int getSoTimeout() {
+ return soTimeout;
+ }
+
+ public void setSoTimeout(int soTimeout) {
+ this.soTimeout = soTimeout;
+ }
+}
diff --git a/src/main/java/com/bsd/say/controller/WechatController.java b/src/main/java/com/bsd/say/controller/WechatController.java
index 78a93bb..ae34c25 100644
--- a/src/main/java/com/bsd/say/controller/WechatController.java
+++ b/src/main/java/com/bsd/say/controller/WechatController.java
@@ -1,18 +1,28 @@
package com.bsd.say.controller;
+import com.bsd.say.config.RedisProperies;
+import com.bsd.say.service.WxOpenServiceDemo;
+import com.bsd.say.service.impl.WeixinService;
import com.bsd.say.util.LogUtils;
-import com.bsd.say.util.MessageUtil;
import com.bsd.say.util.Xml2MapUtil;
import com.bsd.say.util.wechat.AesException;
import com.bsd.say.util.wechat.WXBizMsgCrypt;
+import com.sun.org.apache.bcel.internal.generic.NEW;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.open.bean.message.WxOpenXmlMessage;
import org.apache.commons.collections.MapUtils;
+import org.apache.commons.lang3.StringUtils;
import org.dom4j.DocumentException;
import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
+import redis.clients.jedis.Jedis;
+import redis.clients.jedis.JedisPool;
+
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -39,94 +49,43 @@ public class WechatController {
private String componentAppId;
@Resource
private RedisTemplate redisTemplate;
+ @Autowired
+ private WxOpenServiceDemo wxOpenService;
Logger logger = LogUtils.getBussinessLogger();
-
+ @Autowired
+ private WeixinService weixinService;
/**
* 接收component_verify_ticket 或 authorized事件
*/
- @PostMapping(value = "/getComponentVerifyTicket")
- @ResponseBody
- public void getComponentVerifyTicket(HttpServletRequest request, HttpServletResponse response) throws Exception {
-
- String nonce = request.getParameter("nonce");
- String timestamp = request.getParameter("timestamp");
- String signature = request.getParameter("signature");
- String msgSignature = request.getParameter("msg_signature");
-// String postData = request.getParameter("postData");
- logger.info("nonce: " + nonce);
- logger.info("timestamp: " + timestamp);
- logger.info("signature: " + signature);
- logger.info("msgSignature: " + msgSignature);
-
-
-
-
-// Map map= MessageUtil.parseXml(request);
-
-// System.out.println(map.toString());
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- StringBuilder sb = new StringBuilder();
- BufferedReader in = request.getReader();
- String line;
- while ((line = in.readLine()) != null) {
- sb.append(line);
+ @RequestMapping("/getComponentVerifyTicket")
+ public Object receiveTicket(@RequestBody(required = false) String requestBody, @RequestParam("timestamp") String timestamp,
+ @RequestParam("nonce") String nonce, @RequestParam("signature") String signature,
+ @RequestParam(name = "encrypt_type", required = false) String encType,
+ @RequestParam(name = "msg_signature", required = false) String msgSignature) {
+ this.logger.info(
+ "\n接收微信请求:[signature=[{}], encType=[{}], msgSignature=[{}],"
+ + " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
+ signature, encType, msgSignature, timestamp, nonce, requestBody);
+
+ if (!StringUtils.equalsIgnoreCase("aes", encType)
+ || !wxOpenService.getWxOpenComponentService().checkSignature(timestamp, nonce, signature)) {
+ throw new IllegalArgumentException("非法请求,可能属于伪造的请求!");
}
- String postData = sb.toString();
- logger.info("postData: " + postData);
- try {
- //这个类是微信官网提供的解密类,需要用到消息校验Token 消息加密Key和服务平台appid
- WXBizMsgCrypt pc = new WXBizMsgCrypt(componentToken,
- aesKey, componentAppId);
- DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
- dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
- dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
- dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
- dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
- dbf.setXIncludeAware(false);
- dbf.setExpandEntityReferences(false);
- DocumentBuilder db = dbf.newDocumentBuilder();
- StringReader sr = new StringReader(postData);
- InputSource is = new InputSource(sr);
- org.w3c.dom.Document document = db.parse(is);
-
- org.w3c.dom.Element root = document.getDocumentElement();
- NodeList nodelist1 = root.getElementsByTagName("Encrypt");
- String encrypt = nodelist1.item(0).getTextContent();
- String format = "";
- String fromXML = String.format(format, encrypt);
- String xml = pc.decryptMsg(msgSignature, timestamp, nonce, fromXML);
- Map result = Xml2MapUtil.xml2map(xml);// 将xml转为map
-
- String componentVerifyTicket = MapUtils.getString(result, "ComponentVerifyTicket");
+ // aes加密的消息
+ WxOpenXmlMessage inMessage = WxOpenXmlMessage.fromEncryptedXml(requestBody,
+ wxOpenService.getWxOpenConfigStorage(), timestamp, nonce, msgSignature);
+ this.logger.debug("\n消息解密后内容为:\n{} ", inMessage.toString());
+ try {
+ String out = wxOpenService.getWxOpenComponentService().route(inMessage);
+ this.logger.debug("\n组装回复信息:{}", out);
+ } catch (WxErrorException e) {
+ this.logger.error("receive_ticket", e);
+ }
- logger.info("----verify ticket--" + componentVerifyTicket);
- // 存储平台授权票据,保存ticket
- String TICKET = componentVerifyTicket;
- redisTemplate.opsForValue().set("component_verify_ticket", TICKET);
- } catch (Exception e) {
-// log.error(e.getMessage(), e);
- e.printStackTrace();
- }
-// WeChatUtils.responseReplyMessage(response, "success");
- output(response, "success");
+ return "success";
}
/**
@@ -146,43 +105,7 @@ public class WechatController {
}
}
- // /**
-// * 处理授权事件的推送
-// *
-// * @param request
-// * @throws IOException
-// * @throws AesException
-// * @throws DocumentException
-// */
-// public void processAuthorizeEvent(HttpServletRequest request) throws IOException, DocumentException, AesException {
-// String nonce = request.getParameter("nonce");
-// String timestamp = request.getParameter("timestamp");
-// String signature = request.getParameter("signature");
-// String msgSignature = request.getParameter("msg_signature");
-//
-// if (!StringUtils.isNotBlank(msgSignature))
-// return;// 微信推送给第三方开放平台的消息一定是加过密的,无消息加密无法解密消息
-// boolean isValid = checkSignature(COMPONENT_TOKEN, signature, timestamp, nonce);
-// if (isValid) {
-// StringBuilder sb = new StringBuilder();
-// BufferedReader in = request.getReader();
-// String line;
-// while ((line = in.readLine()) != null) {
-// sb.append(line);
-// }
-// String xml = sb.toString();
-//// LogUtil.info("第三方平台全网发布-----------------------原始 Xml="+xml);
-// String encodingAesKey = COMPONENT_ENCODINGAESKEY;// 第三方平台组件加密密钥
-// String appId = getAuthorizerAppidFromXml(xml);// 此时加密的xml数据中ToUserName是非加密的,解析xml获取即可
-// //LogUtil.info("第三方平台全网发布-------------appid----------getAuthorizerAppidFromXml(xml)-----------appId="+appId);
-// WXBizMsgCrypt pc = new WXBizMsgCrypt(COMPONENT_TOKEN, encodingAesKey, COMPONENT_APPID);
-// xml = pc.decryptMsg(msgSignature, timestamp, nonce, xml);
-//// LogUtil.info("第三方平台全网发布-----------------------解密后 Xml="+xml);
-// processAuthorizationEvent(xml);
-// }
-// }
-//
-//
+
@RequestMapping(value = "/{appid}/callback", method = {RequestMethod.GET, RequestMethod.POST})
public void callBackEvent(HttpServletRequest request, HttpServletResponse response) throws IOException, DocumentException, AesException {
@@ -209,117 +132,28 @@ public class WechatController {
//// LogUtil.info("全网发布接入检测消息反馈开始---------------APPID="+ APPID +"------------------------toUserName="+toUserName);
// checkWeixinAllNetworkCheck(request,response,xml);
}
-//
-//
-// public void checkWeixinAllNetworkCheck(HttpServletRequest request, HttpServletResponse response,String xml) throws DocumentException, IOException, AesException{
-// String nonce = request.getParameter("nonce");
-// String timestamp = request.getParameter("timestamp");
-// String msgSignature = request.getParameter("msg_signature");
-//
-// WXBizMsgCrypt pc = new WXBizMsgCrypt(componentToken, aesKey, componentAppId);
-// xml = pc.decryptMsg(msgSignature, timestamp, nonce, xml);
-//
-// Document doc = DocumentHelper.parseText(xml);
-// Element rootElt = doc.getRootElement();
-// String msgType = rootElt.elementText("MsgType");
-// String toUserName = rootElt.elementText("ToUserName");
-// String fromUserName = rootElt.elementText("FromUserName");
-//
-//// LogUtil.info("---全网发布接入检测--step.1-----------msgType="+msgType+"-----------------toUserName="+toUserName+"-----------------fromUserName="+fromUserName);
-//// LogUtil.info("---全网发布接入检测--step.2-----------xml="+xml);
-// if("event".equals(msgType)){
-//// LogUtil.info("---全网发布接入检测--step.3-----------事件消息--------");
-// String event = rootElt.elementText("Event");
-// replyEventMessage(request,response,event,toUserName,fromUserName);
-// }else if("text".equals(msgType)){
-//// LogUtil.info("---全网发布接入检测--step.3-----------文本消息--------");
-// String content = rootElt.elementText("Content");
-// processTextMessage(request,response,content,toUserName,fromUserName);
-// }
-// }
-//
-// public void replyEventMessage(HttpServletRequest request, HttpServletResponse response, String event, String toUserName, String fromUserName) throws DocumentException, IOException {
-// String content = event + "from_callback";
-//// LogUtil.info("---全网发布接入检测------step.4-------事件回复消息 content="+content + " toUserName="+toUserName+" fromUserName="+fromUserName);
-// replyTextMessage(request,response,content,toUserName,fromUserName);
-// }
-//
-//
-// /**
-// * 回复微信服务器"文本消息"
-// * @param request
-// * @param response
-// * @param content
-// * @param toUserName
-// * @param fromUserName
-// * @throws DocumentException
-// * @throws IOException
-// */
-// public void replyTextMessage(HttpServletRequest request, HttpServletResponse response, String content, String toUserName, String fromUserName) throws DocumentException, IOException {
-// Long createTime = Calendar.getInstance().getTimeInMillis() / 1000;
-// StringBuffer sb = new StringBuffer();
-// sb.append("");
-// sb.append("");
-// sb.append("");
-// sb.append(""+createTime+"");
-// sb.append("");
-// sb.append("");
-// sb.append("");
-// String replyMsg = sb.toString();
-//
-// String returnvaleue = "";
-// try {
-// WXBizMsgCrypt pc = new WXBizMsgCrypt(componentToken, aesKey, componentAppId);
-// returnvaleue = pc.encryptMsg(replyMsg, createTime.toString(), "easemob");
-//// logger.info("------------------加密后的返回内容 returnvaleue: "+returnvaleue);
-// } catch (AesException e) {
-// e.printStackTrace();
-// }
-// output(response, returnvaleue);
-// }
-//
-// public void processTextMessage(HttpServletRequest request, HttpServletResponse response,String content,String toUserName, String fromUserName) throws IOException, DocumentException{
-// if("TESTCOMPONENT_MSG_TYPE_TEXT".equals(content)){
-// String returnContent = content+"_callback";
-// replyTextMessage(request,response,returnContent,toUserName,fromUserName);
-// }else if(StringUtils.startsWithIgnoreCase(content, "QUERY_AUTH_CODE")){
-// output(response, "");
-// //接下来客服API再回复一次消息
-// replyApiTextMessage(request,response,content.split(":")[1],fromUserName);
-// }
-// }
-//
-// public void replyApiTextMessage(HttpServletRequest request, HttpServletResponse response, String auth_code, String fromUserName) throws DocumentException, IOException {
-// String authorization_code = auth_code;
-// // 得到微信授权成功的消息后,应该立刻进行处理!!相关信息只会在首次授权的时候推送过来
-// logger.info("------step.1----使用客服消息接口回复粉丝----逻辑开始-------------------------");
-// try {
-// ApiComponentToken apiComponentToken = new ApiComponentToken();
-// apiComponentToken.setComponent_appid(COMPONENT_APPID);
-// apiComponentToken.setComponent_appsecret(COMPONENT_APPSECRET);
-// WeixinOpenAccountEntity entity = getWeixinOpenAccount(APPID);
-// apiComponentToken.setComponent_verify_ticket(entity.getTicket());
-// String component_access_token = JwThirdAPI.getAccessToken(apiComponentToken);
-//
-// logger.info("------step.2----使用客服消息接口回复粉丝------- component_access_token = "+component_access_token + "---------authorization_code = "+authorization_code);
-// net.sf.json.JSONObject authorizationInfoJson = JwThirdAPI.getApiQueryAuthInfo(COMPONENT_APPID, authorization_code, component_access_token);
-// logger.info("------step.3----使用客服消息接口回复粉丝-------------- 获取authorizationInfoJson = "+authorizationInfoJson);
-// net.sf.json.JSONObject infoJson = authorizationInfoJson.getJSONObject("authorization_info");
-// String authorizer_access_token = infoJson.getString("authorizer_access_token");
-//
-//
-// Map obj = new HashMap();
-// Map msgMap = new HashMap();
-// String msg = auth_code + "_from_api";
-// msgMap.put("content", msg);
-//
-// obj.put("touser", fromUserName);
-// obj.put("msgtype", "text");
-// obj.put("text", msgMap);
-// JwThirdAPI.sendMessage(obj, authorizer_access_token);
-// } catch (WexinReqException e) {
-// e.printStackTrace();
-// }
-//
-// }
+
+ @RequestMapping("test")
+ public void test(){
+ JedisPool pool = new JedisPool();
+ RedisProperies redisProperies = new RedisProperies();
+ if (pool == null) {
+ synchronized (WxOpenServiceDemo.class) {
+ if (pool == null) {
+ pool = new JedisPool(redisProperies, redisProperies.getHost(),
+ redisProperies.getPort(), redisProperies.getConnectionTimeout(),
+ redisProperies.getSoTimeout(), redisProperies.getPassword(),
+ redisProperies.getDatabase(), redisProperies.getClientName(),
+ redisProperies.isSsl(), redisProperies.getSslSocketFactory(),
+ redisProperies.getSslParameters(), redisProperies.getHostnameVerifier());
+ }
+ }
+ }
+ Jedis jedis = null;
+ RedisProperies properies = new RedisProperies();
+
+ jedis = pool.getResource();
+ System.out.println(jedis.get("wechat_component_verify_ticket:wx474350bcaea2d745"));
+ }
+
}
diff --git a/src/main/java/com/bsd/say/service/WxOpenServiceDemo.java b/src/main/java/com/bsd/say/service/WxOpenServiceDemo.java
new file mode 100644
index 0000000..b41800a
--- /dev/null
+++ b/src/main/java/com/bsd/say/service/WxOpenServiceDemo.java
@@ -0,0 +1,69 @@
+package com.bsd.say.service;
+
+import com.bsd.say.config.RedisProperies;
+import me.chanjar.weixin.open.api.impl.WxOpenInRedisConfigStorage;
+import me.chanjar.weixin.open.api.impl.WxOpenMessageRouter;
+import me.chanjar.weixin.open.api.impl.WxOpenServiceImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.stereotype.Service;
+import redis.clients.jedis.JedisPool;
+
+import javax.annotation.PostConstruct;
+
+/**
+ * @author 007
+ */
+@Service
+public class WxOpenServiceDemo extends WxOpenServiceImpl {
+ @Value("${wechat.aesKey}")
+ private String aesKey;
+ @Value("${wechat.componentToken}")
+ private String componentToken;
+ @Value("${wechat.appId}")
+ private String appId;
+ @Value("${wechat.componentAppId}")
+ private String componentAppId;
+ @Value("${wechat.componentAppSecret}")
+ private String componentAppSecret;
+ private Logger logger = LoggerFactory.getLogger(getClass());
+ private static JedisPool pool;
+ private WxOpenMessageRouter wxOpenMessageRouter;
+ @PostConstruct
+ public void init() {
+ WxOpenInRedisConfigStorage inRedisConfigStorage = new WxOpenInRedisConfigStorage(getJedisPool());
+ inRedisConfigStorage.setComponentAppId(componentAppId);
+ inRedisConfigStorage.setComponentAppSecret(componentAppSecret);
+ inRedisConfigStorage.setComponentToken(componentToken);
+ inRedisConfigStorage.setComponentAesKey(aesKey);
+ setWxOpenConfigStorage(inRedisConfigStorage);
+ wxOpenMessageRouter = new WxOpenMessageRouter(this);
+ wxOpenMessageRouter.rule().handler((wxMpXmlMessage, map, wxMpService, wxSessionManager) -> {
+ logger.info("\n接收到 {} 公众号请求消息,内容:{}", wxMpService.getWxMpConfigStorage().getAppId(), wxMpXmlMessage);
+ return null;
+ }).next();
+ }
+ public WxOpenMessageRouter getWxOpenMessageRouter(){
+ return wxOpenMessageRouter;
+ }
+
+ private JedisPool getJedisPool() {
+ RedisProperies redisProperies = new RedisProperies();
+ if (pool == null) {
+ synchronized (WxOpenServiceDemo.class) {
+ if (pool == null) {
+ pool = new JedisPool(redisProperies, redisProperies.getHost(),
+ redisProperies.getPort(), redisProperies.getConnectionTimeout(),
+ redisProperies.getSoTimeout(), redisProperies.getPassword(),
+ redisProperies.getDatabase(), redisProperies.getClientName(),
+ redisProperies.isSsl(), redisProperies.getSslSocketFactory(),
+ redisProperies.getSslParameters(), redisProperies.getHostnameVerifier());
+ }
+ }
+ }
+ return pool;
+ }
+}