🔥 删除无效代码

This commit is contained in:
ronger 2022-08-25 10:14:36 +08:00
parent 546a46fa6b
commit 0ec8b17c8a
40 changed files with 5 additions and 2110 deletions

View File

@ -3,14 +3,12 @@ package com.rymcu.forest.config;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.session.mgt.eis.MemorySessionDAO;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.EnvironmentAware;
@ -116,62 +114,12 @@ public class ShiroConfig implements EnvironmentAware {
@Bean
public SessionManager sessionManager() {
BaseSessionManager sessionManager = new BaseSessionManager();
sessionManager.setSessionDAO(redisSessionDAO());
sessionManager.setSessionDAO(new MemorySessionDAO());
sessionManager.setSessionIdUrlRewritingEnabled(false);
sessionManager.setGlobalSessionTimeout(21600000L);
return sessionManager;
}
/**
* 配置shiro redisManager
* <p>
* 使用的是shiro-redis开源插件
*
* @return
*/
public RedisManager redisManager() {
StringBuffer host = new StringBuffer(env.getProperty("spring.redis.host"));
host.append(":").append(env.getProperty("spring.redis.port"));
// 设置redis配置信息
RedisManager redisManager = new RedisManager();
redisManager.setHost(host.toString());
redisManager.setPassword(env.getProperty("spring.redis.password"));
return redisManager;
}
/**
* cacheManager 缓存 redis实现
* <p>
* 使用的是shiro-redis开源插件
*
* @return
*/
@Bean
public RedisCacheManager cacheManager() {
RedisCacheManager redisCacheManager = new RedisCacheManager();
redisCacheManager.setRedisManager(redisManager());
return redisCacheManager;
}
/**
* RedisSessionDAO shiro sessionDao层的实现 通过redis
* <p>
* 使用的是shiro-redis开源插件
*/
@Bean
public RedisSessionDAO redisSessionDAO() {
RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
redisSessionDAO.setRedisManager(redisManager());
redisSessionDAO.setExpire(21600);
return redisSessionDAO;
}
/**
* 开启shiro aop注解支持.
* 使用代理方式;所以需要开启代码支持;

View File

@ -1,11 +1,11 @@
package com.rymcu.forest.handler;
import com.alibaba.fastjson.JSON;
import com.rymcu.forest.core.constant.NotificationConstant;
import com.rymcu.forest.handler.event.ArticleDeleteEvent;
import com.rymcu.forest.handler.event.ArticleEvent;
import com.rymcu.forest.lucene.service.LuceneService;
import com.rymcu.forest.util.NotificationUtils;
import com.rymcu.forest.wx.mp.utils.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
@ -29,7 +29,7 @@ public class ArticleHandler {
@Async
public void processArticlePostEvent(ArticleEvent articleEvent) throws InterruptedException {
Thread.sleep(1000);
log.info(String.format("执行文章发布相关事件:[%s]", JsonUtils.toJson(articleEvent)));
log.info(String.format("执行文章发布相关事件:[%s]", JSON.toJSONString(articleEvent)));
// 发送系统通知
if (articleEvent.getNotification()) {
NotificationUtils.sendAnnouncement(articleEvent.getIdArticle(), NotificationConstant.Article, articleEvent.getArticleTitle());
@ -59,7 +59,7 @@ public class ArticleHandler {
@Async
public void processArticleDeleteEvent(ArticleDeleteEvent articleDeleteEvent) throws InterruptedException {
Thread.sleep(1000);
log.info(String.format("执行文章删除相关事件:[%s]", JsonUtils.toJson(articleDeleteEvent)));
log.info(String.format("执行文章删除相关事件:[%s]", JSON.toJSONString(articleDeleteEvent)));
luceneService.deleteArticle(articleDeleteEvent.getIdArticle());
log.info("执行完成文章删除相关事件...id={}", articleDeleteEvent.getIdArticle());
}

View File

@ -1,14 +0,0 @@
package com.rymcu.forest.service;
import com.rymcu.forest.core.service.Service;
import com.rymcu.forest.entity.WxUser;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
/**
* @author ronger
*/
public interface WxUserService extends Service<WxUser> {
WxUser saveUser(WxMpUser wxMpUser, String appId);
}

View File

@ -3,16 +3,12 @@ package com.rymcu.forest.service.impl;
import com.rymcu.forest.core.service.AbstractService;
import com.rymcu.forest.dto.ArticleTagDTO;
import com.rymcu.forest.dto.LabelModel;
import com.rymcu.forest.dto.baidu.TagNlpDTO;
import com.rymcu.forest.entity.Article;
import com.rymcu.forest.entity.Tag;
import com.rymcu.forest.entity.User;
import com.rymcu.forest.mapper.ArticleMapper;
import com.rymcu.forest.mapper.TagMapper;
import com.rymcu.forest.service.TagService;
import com.rymcu.forest.util.BaiDuAipUtils;
import com.rymcu.forest.util.CacheUtils;
import com.rymcu.forest.util.UserUtils;
import com.rymcu.forest.util.XssUtils;
import com.rymcu.forest.web.api.common.UploadController;
import com.rymcu.forest.web.api.exception.BaseApiException;
@ -97,16 +93,6 @@ public class TagServiceImpl extends AbstractService<Tag> implements TagService {
return 1;
} else {
if (StringUtils.isNotBlank(articleContentHtml)) {
List<TagNlpDTO> list = BaiDuAipUtils.getKeywords(article.getArticleTitle(), articleContentHtml);
if (list.size() > 0) {
StringBuffer tags = new StringBuffer();
for (TagNlpDTO tagNlpDTO : list) {
tags.append(tagNlpDTO.getTag()).append(",");
}
article.setArticleTags(tags.toString());
} else {
article.setArticleTags("待分类");
}
saveTagArticle(article, articleContentHtml, userId);
}
}

View File

@ -1,55 +0,0 @@
package com.rymcu.forest.service.impl;
import com.rymcu.forest.core.service.AbstractService;
import com.rymcu.forest.entity.WxUser;
import com.rymcu.forest.mapper.WxUserMapper;
import com.rymcu.forest.service.WxUserService;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
* @author ronger
*/
@Service
public class WxUserServiceImpl extends AbstractService<WxUser> implements WxUserService {
@Resource
private WxUserMapper wxUserMapper;
@Override
public WxUser saveUser(WxMpUser wxMpUser, String appId) {
WxUser searchWxUser = new WxUser();
if (StringUtils.isBlank(wxMpUser.getUnionId())) {
searchWxUser.setUnionId(wxMpUser.getUnionId());
} else {
searchWxUser.setAppId(appId);
searchWxUser.setOpenId(searchWxUser.getOpenId());
}
List<WxUser> wxUsers = wxUserMapper.select(searchWxUser);
WxUser wxUser;
if (wxUsers.isEmpty()) {
wxUser = new WxUser();
wxUser.setAppId(appId);
wxUser = copyWxUser(wxMpUser,wxUser);
wxUserMapper.insertSelective(wxUser);
} else {
wxUser = wxUsers.get(0);
wxUser = copyWxUser(wxMpUser,wxUser);
wxUserMapper.updateByPrimaryKeySelective(wxUser);
}
return wxUser;
}
private WxUser copyWxUser(WxMpUser wxMpUser, WxUser wxUser) {
wxUser.setSubscribe(wxMpUser.getSubscribe());
wxUser.setSubscribeTime(wxMpUser.getSubscribeTime());
wxUser.setUnionId(wxMpUser.getUnionId());
wxUser.setOpenId(wxMpUser.getOpenId());
wxUser.setLanguage(wxMpUser.getLanguage());
return wxUser;
}
}

View File

@ -1,197 +0,0 @@
package com.rymcu.forest.util;
import com.alibaba.fastjson.JSON;
import com.baidu.aip.nlp.AipNlp;
import com.rymcu.forest.dto.baidu.TagNlpDTO;
import org.apache.commons.lang.StringUtils;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.List;
/**
* @author ronger
*/
public class BaiDuAipUtils {
public static final String APP_ID = "18094949";
public static final String API_KEY = "3h3BOgejXI1En5aq1iGHeWrF";
public static final String SECRET_KEY = "8guDNvxWF1wu8ogpVxLHlRY5FeOBE8z7";
public static final Integer MAX_CONTENT_LENGTH = 3000;
public static void main(String[] args) {
String title = "51单片机第4章--跑马灯实验";
System.out.println(title.length());
String content = "<h2>4.1 进制转换基础知识</h2>\n" +
"<p>进制实际是一个非常简单易懂的概念,对于初学者来说也很容易上手。我们接触最多的就是十进制了,它的特点为逢十进一,包含 0123456789 共十个元素。在生活中我们用到的基本都是十进制了,所以大家对它已经非常熟悉并能应用自如,但是在计算机(包括单片机)世界里,所有都是以二进制为基础的。二进制的特点为逢二进一,包含 0,1 共两个元素。计算机中的数据都是以二进制存储的,这就是我们所说的 01 世界。通常我们讲的 32 位或 64 位操作系统这里的位指的就是二进制位数。因为我们实际多用十进制,那么我们在和计算机系统沟通过程中,十进制与二进制之间的转换就变得很重要了。进制之间的转换如下表所示。<br />\n" +
"<img src=\"https://static.rymcu.com/article/1584363905093.png\" alt=\"表4-1进制转换.png\" /><br />\n" +
"二进制转换十进制公式如下:<br />\n" +
"<img src=\"https://static.rymcu.com/article/1584363941039.png\" alt=\"进制转换公式.png\" /><br />\n" +
"其中n 表示二进制的位数。<br />\n" +
"下面我们举个例子来更加直观的说明这个公式:<br />\n" +
"例如1101这是一个 4 位的二进制数,计算如下,<br />\n" +
"<img src=\"https://static.rymcu.com/article/1584363961871.png\" alt=\"进制转换公式1.png\" /><br />\n" +
"大家可以利用这个公式计算的结果和上表进行一一对照。<br />\n" +
"十六进制也是我们常用的进制,它的特点为逢十六进一,包括 0123456789ABCDEF 共十六个元素。实际上十六进制是二进制的一种特殊形式,十六进制的 1 位等价于二进制的 4 位,在 C 语言编程中我们常用十六进制来表示二进制数。在实际应用中我们常常该数字之前加一个前缀来表示他的进制“0b”表示二进制“0x”表示十六进制。下面我们举例说明<br />\n" +
"0b10010010 = 0x92<br />\n" +
"上面一个八位的二进制数转换为一个两位的十六进制数。二进制的前 4 位等于十六进制的第 1 位:<br />\n" +
"0b1001 = 0x9<br />\n" +
"二进制数的后 4 位等于十六进制的第 2 位:<br />\n" +
"0b0010 = 0x2<br />\n" +
"在计算机中,我们通常所说的二进制的 1 位也叫 1bit8 位表示 1 个字节,也叫 1Byte。根据二进制与十六机制的关系一个 2 位的十六进制数则可表示 1 个字节。在运用的过程中牢记 0~15 的十进制与二进制、十六进制之间的转换关系对于程序的编写有很大的好处。</p>\n" +
"<h2>4.2 闪烁 LED 小灯</h2>\n" +
"<p>怎么让 LED 小灯闪烁?我们最先想到的办法当然是先让 LED 小灯点亮,延时一段时间,熄灭 LED 小灯,再延时一段时间,一直循环上面的步骤就能实现 LED 小灯的闪烁了。根据第 3 章的知识我们知道点亮 LED 的语句为“led0 = 0;”,熄灭 LED 的语句为“led0 = 1;”。按照第 3 章介绍我们重新建立一个 LED 小灯闪烁的工程。程序代码设计如下:</p>\n" +
"<pre><code class=\"language-C++\">#include&lt;reg52.h&gt; //寄存器声明头文件 \n" +
"sbit led0 = P1^0; // 位声明将P1.0管脚声明为led0 \n" +
" \n" +
"void main() //程序主函数入口每个C语言程序有且只有一个 \n" +
"{ \n" +
" int i; //变量声明 \n" +
" while(1) //循环 \n" +
" { \n" +
" led0 = 0; //赋值管脚P1.0为低电平点亮LED小灯 \n" +
" for(i=0;i&lt;5000;i++);//延时一段时间 \n" +
" led0 = 1;//熄灭LED小灯 \n" +
" for(i=0;i&lt;5000;i++);//再延时一段时间 \n" +
" } \n" +
"} \n" +
"</code></pre>\n" +
"<h2>4.3\t跑马灯设计</h2>\n" +
"<p>在我们的开发板上设计了 8 个依次排列的 LED 小灯,让小灯依次点亮和熄灭实现跑马灯的效果是我们这一节的主要内容。</p>\n" +
"<h3>4.3.1 硬件设计</h3>\n" +
"<p>8 个 LED 小灯的硬件电路设计原理图如下图所示:<br />\n" +
"<img src=\"https://static.rymcu.com/article/1584364202185.png\" alt=\"图4-1-8位跑马灯设计原理图.png\" /><br />\n" +
"如上图所示8 个 LED 小灯 LED0-LED7 的正极和电源 VCC 之间均串联了一个 1K 的限流电阻。LED7-LED0 的负极与 74HC573 锁存器的 Q0-Q7 一一相连接。锁存器 74HC573 的功能我们这里不详细介绍,把它的 D0-D7 与 Q0-Q7 之间看作是电气上一一联通的。由图所示,锁存器的 D0-D7 和单片机的 P1.7-P1.0 是一一连接的。因此LED 小灯 LED7-LED0 的负极与单片机的 P1.7~P1.0 管脚一一相连,在单片机程序中通过控制 P1.7-P1.0 管脚的高低电平便可控制 8 个 LED 小灯的亮灭。<br />\n" +
"该实验要实现的功能为:首先点亮 LED0然后延迟一段时间熄灭 LED0熄灭 LED0 点亮 LED1延迟一段时间熄灭 LED1 点亮 LED2延迟一段时间一直到熄灭 LED6 点亮 LED7依照上面的步骤一直循环下去便实现了一个简单的跑马灯的效果。</p>\n" +
"<h3>4.3.2 软件设计</h3>\n" +
"<p>前面我们试验中都是只对 P1.0 这个管脚进行赋值,来控制 LED 小灯 led0 的亮灭。实际在编写程序的过程中我们可以对 P1 寄存器进行直接赋值来同时控制 8 个 LED 小灯。<br />\n" +
"<img src=\"https://static.rymcu.com/article/1584364354304.png\" alt=\"表4-2-P1寄存器对照表.png\" /><br />\n" +
"如上表所示P1 寄存器是一个 8 位的寄存器,最高位到最低位依次对应的 P1.7 管脚到 P1.0 管脚。点亮某个 LED 小灯的二进制,十六进制赋值如上表所示。例如 P1 = 0xFE;表示点亮 led0,P1=0x7F;则表示点亮 led7。在软件代码设计时我们想到的第一个方法为依次点亮小灯并延时代码如下所示。</p>\n" +
"<pre><code class=\"language-C++\">#include&lt;reg52.h&gt; //加载头文件\n" +
"int i;\n" +
"\n" +
"void main()//主函数入口\n" +
"{\n" +
"\tP1 = 0xFE; //点亮LED0\n" +
"\tfor(i=0;i&lt;5000;i++);//延时一段时间\n" +
"\tP1 = 0xFD; //点亮LED1\n" +
"\tfor(i=0;i&lt;5000;i++);//延时一段时间\n" +
"\tP1 = 0xFB; //点亮LED2\n" +
"\tfor(i=0;i&lt;5000;i++);//延时一段时间\n" +
"\tP1 = 0xF7; //点亮LED3\n" +
"\tfor(i=0;i&lt;5000;i++);//延时一段时间\n" +
"\tP1 = 0xEF; //点亮LED4\n" +
"\tfor(i=0;i&lt;5000;i++);//延时一段时间\n" +
"\tP1 = 0xDF; //点亮LED5\n" +
"\tfor(i=0;i&lt;5000;i++);//延时一段时间\n" +
"\tP1 = 0xBF; //点亮LED6\n" +
"\tfor(i=0;i&lt;5000;i++);//延时一段时间\n" +
"\tP1 = 0x7F; //点亮LED7\n" +
"\tfor(i=0;i&lt;5000;i++);//延时一段时间\n" +
"} \n" +
"</code></pre>\n" +
"<p>我们对代码进行一下小的改进,这个方法这里称之为“左移取反”法,这个方法在很多的应用中都能用到,非常实用。代码如下图所示。</p>\n" +
"<pre><code class=\"language-C++\">#include&lt;reg52.h&gt; //加载头文件\n" +
"int i;\n" +
"int flag=0;\n" +
" \n" +
"void main()//主函数入口\n" +
"{ \n" +
" P0 = 0xff;\n" +
"\twhile(1)\n" +
"\t{\n" +
"\t\tP1 = ~(0x01&lt;&lt;flag);//P1的值等于1左移flag位后取反点亮第flag位LED小灯亮\n" +
"\t\tfor(i=0;i&lt;25000;i++);//延时一段时间\n" +
"\n" +
"\t\tif(flag&gt;=8)\t //flag大于7时置零从零开始\n" +
"\t\t{\n" +
"\t\t\tflag=0;\n" +
"\t\t}\n" +
"\t\telse\n" +
"\t\t{\n" +
"\t\t\tflag++;\t //flag累加\n" +
"\t\t}\n" +
"\t}\n" +
"}\n" +
"</code></pre>\n" +
"<p>我们对上面代码进行分析flag 是一个从 0 到 7 依次循环的数P1 等于 1 向左移 flag 位再取反。当 flag 等于 2 时0b0000,0001 左移 2 位等于 0b0000,0100,再取反等于 0b1111,1011=0xFB,并赋值给 P1点亮了小灯 led2。同理当 flag 等于 6 时0b0000,0001 左移 6 位等于 0b0100,0000,再取反等于 0b1011,1111=0xBF 并赋值给 P1点亮了小灯 led6。flag 为其他值时,大家可以进行一一分析。</p>\n" +
"<h3>4.3.3 下载验证</h3>\n" +
"<p>将程序通过 STC-isp 软件下载到单片机,观察 8 个 LED 小灯效果与设想的效果是否一致至此本章的内容讲解完毕内容包括进制转换的基础知识、LED 小灯闪速程序以及跑马灯的两种程序。大家在动手操作的过程中多多下载到单片机中观察现象,加深印象。</p>\n";
System.out.println(getKeywords(title, content));
System.out.println(getNewsSummary(title, content, 200));
}
public static List<TagNlpDTO> getKeywords(String title, String content) {
if (StringUtils.isBlank(content)) {
return null;
}
// api 限制内容不能超过 3000
if (content.length() > MAX_CONTENT_LENGTH) {
content = content.substring(0, MAX_CONTENT_LENGTH);
}
// 初始化一个AipNlp
AipNlp client = new AipNlp(APP_ID, API_KEY, SECRET_KEY);
// 可选设置网络连接参数
client.setConnectionTimeoutInMillis(2000);
client.setSocketTimeoutInMillis(60000);
// 传入可选参数调用接口
HashMap<String, Object> options = new HashMap<String, Object>(1);
// 新闻摘要接口
JSONObject res = client.keyword(title, Html2TextUtil.getContent(content), options);
List<TagNlpDTO> list = JSON.parseArray(res.get("items").toString(), TagNlpDTO.class);
return list;
}
public static String getTopic(String title, String content) {
if (StringUtils.isBlank(content)) {
return "";
}
// api 限制内容不能超过 3000
if (content.length() > MAX_CONTENT_LENGTH) {
content = content.substring(0, MAX_CONTENT_LENGTH);
}
// 初始化一个AipNlp
AipNlp client = new AipNlp(APP_ID, API_KEY, SECRET_KEY);
// 可选设置网络连接参数
client.setConnectionTimeoutInMillis(2000);
client.setSocketTimeoutInMillis(60000);
// 传入可选参数调用接口
HashMap<String, Object> options = new HashMap<String, Object>(1);
// 新闻摘要接口
JSONObject res = client.topic(title, Html2TextUtil.getContent(content), options);
return res.toString(2);
}
public static String getNewsSummary(String title, String content, int maxSummaryLen) {
if (StringUtils.isBlank(content)) {
return "";
}
// api 限制内容不能超过 3000
if (content.length() > MAX_CONTENT_LENGTH) {
content = content.substring(0, MAX_CONTENT_LENGTH);
}
// 初始化一个AipNlp
AipNlp client = new AipNlp(APP_ID, API_KEY, SECRET_KEY);
// 可选设置网络连接参数
client.setConnectionTimeoutInMillis(2000);
client.setSocketTimeoutInMillis(60000);
// 传入可选参数调用接口
HashMap<String, Object> options = new HashMap<String, Object>(1);
options.put("title", title);
// 新闻摘要接口
JSONObject res = client.newsSummary(Html2TextUtil.getContent(content), maxSummaryLen, options);
return res.getString("summary");
}
}

View File

@ -1,149 +0,0 @@
package com.rymcu.forest.wx.miniapp.config;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage;
import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage;
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
import cn.binarywang.wx.miniapp.message.WxMaMessageHandler;
import cn.binarywang.wx.miniapp.message.WxMaMessageRouter;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
@Slf4j
@Configuration
@EnableConfigurationProperties(WxMaProperties.class)
public class WxMaConfiguration {
private final WxMaProperties properties;
private static final Map<String, WxMaMessageRouter> routers = Maps.newHashMap();
private static Map<String, WxMaService> maServices;
@Autowired
public WxMaConfiguration(WxMaProperties properties) {
this.properties = properties;
}
public static WxMaService getMaService(String appid) {
WxMaService wxService = maServices.get(appid);
if (wxService == null) {
throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置,请核实!", appid));
}
return wxService;
}
public static WxMaMessageRouter getRouter(String appid) {
return routers.get(appid);
}
@PostConstruct
public void init() {
List<WxMaProperties.Config> configs = this.properties.getConfigs();
if (configs == null) {
throw new RuntimeException("大哥拜托先看下项目首页的说明readme文件添加下相关配置注意别配错了");
}
maServices = configs.stream()
.map(a -> {
WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
// WxMaDefaultConfigImpl config = new WxMaRedisConfigImpl(new JedisPool());
// 使用上面的配置时需要同时引入jedis-lock的依赖否则会报类无法找到的异常
config.setAppid(a.getAppId());
config.setSecret(a.getSecret());
config.setToken(a.getToken());
config.setAesKey(a.getAesKey());
config.setMsgDataFormat(a.getMsgDataFormat());
WxMaService service = new WxMaServiceImpl();
service.setWxMaConfig(config);
routers.put(a.getAppId(), this.newRouter(service));
return service;
}).collect(Collectors.toMap(s -> s.getWxMaConfig().getAppid(), a -> a));
}
private WxMaMessageRouter newRouter(WxMaService service) {
final WxMaMessageRouter router = new WxMaMessageRouter(service);
router
.rule().handler(logHandler).next()
.rule().async(false).content("订阅消息").handler(subscribeMsgHandler).end()
.rule().async(false).content("文本").handler(textHandler).end()
.rule().async(false).content("图片").handler(picHandler).end()
.rule().async(false).content("二维码").handler(qrcodeHandler).end();
return router;
}
private final WxMaMessageHandler subscribeMsgHandler = (wxMessage, context, service, sessionManager) -> {
service.getMsgService().sendSubscribeMsg(WxMaSubscribeMessage.builder()
.templateId("此处更换为自己的模板id")
.data(Lists.newArrayList(
new WxMaSubscribeMessage.MsgData("keyword1", "339208499")))
.toUser(wxMessage.getFromUser())
.build());
return null;
};
private final WxMaMessageHandler logHandler = (wxMessage, context, service, sessionManager) -> {
log.info("收到消息:" + wxMessage.toString());
service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("收到信息为:" + wxMessage.toJson())
.toUser(wxMessage.getFromUser()).build());
return null;
};
private final WxMaMessageHandler textHandler = (wxMessage, context, service, sessionManager) -> {
service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("回复文本消息")
.toUser(wxMessage.getFromUser()).build());
return null;
};
private final WxMaMessageHandler picHandler = (wxMessage, context, service, sessionManager) -> {
try {
WxMediaUploadResult uploadResult = service.getMediaService()
.uploadMedia("image", "png",
ClassLoader.getSystemResourceAsStream("tmp.png"));
service.getMsgService().sendKefuMsg(
WxMaKefuMessage
.newImageBuilder()
.mediaId(uploadResult.getMediaId())
.toUser(wxMessage.getFromUser())
.build());
} catch (WxErrorException e) {
e.printStackTrace();
}
return null;
};
private final WxMaMessageHandler qrcodeHandler = (wxMessage, context, service, sessionManager) -> {
try {
final File file = service.getQrcodeService().createQrcode("123", 430);
WxMediaUploadResult uploadResult = service.getMediaService().uploadMedia("image", file);
service.getMsgService().sendKefuMsg(
WxMaKefuMessage
.newImageBuilder()
.mediaId(uploadResult.getMediaId())
.toUser(wxMessage.getFromUser())
.build());
} catch (WxErrorException e) {
e.printStackTrace();
}
return null;
};
}

View File

@ -1,45 +0,0 @@
package com.rymcu.forest.wx.miniapp.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.List;
/**
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
@Data
@ConfigurationProperties(prefix = "wx.miniapp")
public class WxMaProperties {
private List<Config> configs;
@Data
public static class Config {
/**
* 设置微信小程序的appid
*/
private String appId;
/**
* 设置微信小程序的Secret
*/
private String secret;
/**
* 设置微信小程序消息服务器配置的token
*/
private String token;
/**
* 设置微信小程序消息服务器配置的EncodingAESKey
*/
private String aesKey;
/**
* 消息格式XML或者JSON
*/
private String msgDataFormat;
}
}

View File

@ -1,80 +0,0 @@
package com.rymcu.forest.wx.miniapp.controller;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.constant.WxMaConstants;
import com.google.common.collect.Lists;
import com.google.common.io.Files;
import com.rymcu.forest.wx.miniapp.config.WxMaConfiguration;
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.common.error.WxErrorException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
/**
* <pre>
* 小程序临时素材接口
* Created by BinaryWang on 2017/6/16.
* </pre>
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
@RestController
@RequestMapping("/wx/media/{appId}")
public class WxMaMediaController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 上传临时素材
*
* @return 素材的media_id列表实际上如果有的话只会有一个
*/
@PostMapping("/upload")
public List<String> uploadMedia(@PathVariable String appId, HttpServletRequest request) throws WxErrorException {
final WxMaService wxService = WxMaConfiguration.getMaService(appId);
CommonsMultipartResolver resolver = new CommonsMultipartResolver(request.getSession().getServletContext());
if (!resolver.isMultipart(request)) {
return Lists.newArrayList();
}
MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
Iterator<String> it = multiRequest.getFileNames();
List<String> result = Lists.newArrayList();
while (it.hasNext()) {
try {
MultipartFile file = multiRequest.getFile(it.next());
File newFile = new File(Files.createTempDir(), file.getOriginalFilename());
this.logger.info("filePath is " + newFile.toString());
file.transferTo(newFile);
WxMediaUploadResult uploadResult = wxService.getMediaService().uploadMedia(WxMaConstants.KefuMsgType.IMAGE, newFile);
this.logger.info("media_id " + uploadResult.getMediaId());
result.add(uploadResult.getMediaId());
} catch (IOException e) {
this.logger.error(e.getMessage(), e);
}
}
return result;
}
/**
* 下载临时素材
*/
@GetMapping("/download/{mediaId}")
public File getMedia(@PathVariable String appId, @PathVariable String mediaId) throws WxErrorException {
final WxMaService wxService = WxMaConfiguration.getMaService(appId);
return wxService.getMediaService().getMedia(mediaId);
}
}

View File

@ -1,93 +0,0 @@
package com.rymcu.forest.wx.miniapp.controller;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import com.rymcu.forest.wx.miniapp.config.WxMaConfiguration;
import com.rymcu.forest.wx.miniapp.utils.JsonUtils;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 微信小程序用户接口
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
@RestController
@RequestMapping("/wx/user/{appId}")
public class WxMaUserController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 登陆接口
*/
@GetMapping("/login")
public String login(@PathVariable String appId, String code) {
if (StringUtils.isBlank(code)) {
return "empty jscode";
}
final WxMaService wxService = WxMaConfiguration.getMaService(appId);
try {
WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(code);
this.logger.info(session.getSessionKey());
this.logger.info(session.getOpenid());
//TODO 可以增加自己的逻辑关联业务相关数据
return JsonUtils.toJson(session);
} catch (WxErrorException e) {
this.logger.error(e.getMessage(), e);
return e.toString();
}
}
/**
* <pre>
* 获取用户信息接口
* </pre>
*/
@GetMapping("/info")
public String info(@PathVariable String appId, String sessionKey,
String signature, String rawData, String encryptedData, String iv) {
final WxMaService wxService = WxMaConfiguration.getMaService(appId);
// 用户信息校验
if (!wxService.getUserService().checkUserInfo(sessionKey, rawData, signature)) {
return "user check failed";
}
// 解密用户信息
WxMaUserInfo userInfo = wxService.getUserService().getUserInfo(sessionKey, encryptedData, iv);
return JsonUtils.toJson(userInfo);
}
/**
* <pre>
* 获取用户绑定手机号信息
* </pre>
*/
@GetMapping("/phone")
public String phone(@PathVariable String appId, String sessionKey, String signature,
String rawData, String encryptedData, String iv) {
final WxMaService wxService = WxMaConfiguration.getMaService(appId);
// 用户信息校验
if (!wxService.getUserService().checkUserInfo(sessionKey, rawData, signature)) {
return "user check failed";
}
// 解密
WxMaPhoneNumberInfo phoneNoInfo = wxService.getUserService().getPhoneNoInfo(sessionKey, encryptedData, iv);
return JsonUtils.toJson(phoneNoInfo);
}
}

View File

@ -1,28 +0,0 @@
package com.rymcu.forest.wx.miniapp.utils;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
/**
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
public class JsonUtils {
private static final ObjectMapper JSON = new ObjectMapper();
static {
JSON.setSerializationInclusion(Include.NON_NULL);
JSON.configure(SerializationFeature.INDENT_OUTPUT, Boolean.TRUE);
}
public static String toJson(Object obj) {
try {
return JSON.writeValueAsString(obj);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
}

View File

@ -1,17 +0,0 @@
package com.rymcu.forest.wx.mp.builder;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Binary Wang(https://github.com/binarywang)
*/
public abstract class AbstractBuilder {
protected final Logger logger = LoggerFactory.getLogger(getClass());
public abstract WxMpXmlOutMessage build(String content,
WxMpXmlMessage wxMessage, WxMpService service);
}

View File

@ -1,24 +0,0 @@
package com.rymcu.forest.wx.mp.builder;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutImageMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
/**
* @author Binary Wang(https://github.com/binarywang)
*/
public class ImageBuilder extends AbstractBuilder {
@Override
public WxMpXmlOutMessage build(String content, WxMpXmlMessage wxMessage,
WxMpService service) {
WxMpXmlOutImageMessage m = WxMpXmlOutMessage.IMAGE().mediaId(content)
.fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser())
.build();
return m;
}
}

View File

@ -1,22 +0,0 @@
package com.rymcu.forest.wx.mp.builder;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutTextMessage;
/**
* @author Binary Wang(https://github.com/binarywang)
*/
public class TextBuilder extends AbstractBuilder {
@Override
public WxMpXmlOutMessage build(String content, WxMpXmlMessage wxMessage,
WxMpService service) {
WxMpXmlOutTextMessage m = WxMpXmlOutMessage.TEXT().content(content)
.fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser())
.build();
return m;
}
}

View File

@ -1,111 +0,0 @@
package com.rymcu.forest.wx.mp.config;
import com.rymcu.forest.wx.mp.handler.*;
import lombok.AllArgsConstructor;
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
import java.util.stream.Collectors;
import static me.chanjar.weixin.common.api.WxConsts.EventType;
import static me.chanjar.weixin.common.api.WxConsts.EventType.SUBSCRIBE;
import static me.chanjar.weixin.common.api.WxConsts.EventType.UNSUBSCRIBE;
import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType;
import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType.EVENT;
import static me.chanjar.weixin.mp.constant.WxMpEventConstants.CustomerService.*;
import static me.chanjar.weixin.mp.constant.WxMpEventConstants.POI_CHECK_NOTIFY;
/**
* wechat mp configuration
*
* @author Binary Wang(https://github.com/binarywang)
*/
@AllArgsConstructor
@Configuration
@EnableConfigurationProperties(WxMpProperties.class)
public class WxMpConfiguration {
private final LogHandler logHandler;
private final NullHandler nullHandler;
private final KfSessionHandler kfSessionHandler;
private final StoreCheckNotifyHandler storeCheckNotifyHandler;
private final LocationHandler locationHandler;
private final MenuHandler menuHandler;
private final MsgHandler msgHandler;
private final UnsubscribeHandler unsubscribeHandler;
private final SubscribeHandler subscribeHandler;
private final ScanHandler scanHandler;
private final WxMpProperties properties;
@Bean
public WxMpService wxMpService() {
// 代码里 getConfigs()处报错的同学请注意仔细阅读项目说明你的IDE需要引入lombok插件
final List<WxMpProperties.MpConfig> configs = this.properties.getConfigs();
if (configs == null) {
throw new RuntimeException("大哥拜托先看下项目首页的说明readme文件添加下相关配置注意别配错了");
}
WxMpService service = new WxMpServiceImpl();
service.setMultiConfigStorages(configs
.stream().map(a -> {
WxMpDefaultConfigImpl configStorage = new WxMpDefaultConfigImpl();
configStorage.setAppId(a.getAppId());
configStorage.setSecret(a.getSecret());
configStorage.setToken(a.getToken());
configStorage.setAesKey(a.getAesKey());
return configStorage;
}).collect(Collectors.toMap(WxMpDefaultConfigImpl::getAppId, a -> a, (o, n) -> o)));
return service;
}
@Bean
public WxMpMessageRouter messageRouter(WxMpService wxMpService) {
final WxMpMessageRouter newRouter = new WxMpMessageRouter(wxMpService);
// 记录所有事件的日志 异步执行
newRouter.rule().handler(this.logHandler).next();
// 接收客服会话管理事件
newRouter.rule().async(false).msgType(EVENT).event(KF_CREATE_SESSION)
.handler(this.kfSessionHandler).end();
newRouter.rule().async(false).msgType(EVENT).event(KF_CLOSE_SESSION)
.handler(this.kfSessionHandler).end();
newRouter.rule().async(false).msgType(EVENT).event(KF_SWITCH_SESSION)
.handler(this.kfSessionHandler).end();
// 门店审核事件
newRouter.rule().async(false).msgType(EVENT).event(POI_CHECK_NOTIFY).handler(this.storeCheckNotifyHandler).end();
// 自定义菜单事件
newRouter.rule().async(false).msgType(EVENT).event(EventType.CLICK).handler(this.menuHandler).end();
// 点击菜单连接事件
newRouter.rule().async(false).msgType(EVENT).event(EventType.VIEW).handler(this.nullHandler).end();
// 关注事件
newRouter.rule().async(false).msgType(EVENT).event(SUBSCRIBE).handler(this.subscribeHandler).end();
// 取消关注事件
newRouter.rule().async(false).msgType(EVENT).event(UNSUBSCRIBE).handler(this.unsubscribeHandler).end();
// 上报地理位置事件
newRouter.rule().async(false).msgType(EVENT).event(EventType.LOCATION).handler(this.locationHandler).end();
// 接收地理位置消息
newRouter.rule().async(false).msgType(XmlMsgType.LOCATION).handler(this.locationHandler).end();
// 扫码事件
newRouter.rule().async(false).msgType(EVENT).event(EventType.SCAN).handler(this.scanHandler).end();
// 默认
newRouter.rule().async(false).handler(this.msgHandler).end();
return newRouter;
}
}

View File

@ -1,46 +0,0 @@
package com.rymcu.forest.wx.mp.config;
import com.rymcu.forest.wx.mp.utils.JsonUtils;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.List;
/**
* wechat mp properties
*
* @author Binary Wang(https://github.com/binarywang)
*/
@Data
@ConfigurationProperties(prefix = "wx.mp")
public class WxMpProperties {
private List<MpConfig> configs;
@Data
public static class MpConfig {
/**
* 设置微信公众号的appid
*/
private String appId;
/**
* 设置微信公众号的app secret
*/
private String secret;
/**
* 设置微信公众号的token
*/
private String token;
/**
* 设置微信公众号的EncodingAESKey
*/
private String aesKey;
}
@Override
public String toString() {
return JsonUtils.toJson(this);
}
}

View File

@ -1,133 +0,0 @@
package com.rymcu.forest.wx.mp.controller;
import com.rymcu.forest.wx.mp.service.WxMenuService;
import lombok.AllArgsConstructor;
import me.chanjar.weixin.common.bean.menu.WxMenu;
import me.chanjar.weixin.common.bean.menu.WxMenuButton;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.menu.WxMpGetSelfMenuInfoResult;
import me.chanjar.weixin.mp.bean.menu.WxMpMenu;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.io.IOException;
import java.net.MalformedURLException;
import static me.chanjar.weixin.common.api.WxConsts.MenuButtonType;
/**
* @author Binary Wang(https://github.com/binarywang)
*/
@AllArgsConstructor
@RestController
@RequestMapping("/wx/menu/{appId}")
public class WxMenuController {
private final WxMpService wxService;
@Resource
private WxMenuService wxMenuService;
/**
* <pre>
* 自定义菜单创建接口
* 详情请见https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141013&token=&lang=zh_CN
* 如果要创建个性化菜单请设置matchrule属性
* 详情请见https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN
* </pre>
*
* @return 如果是个性化菜单则返回menuid否则返回null
*/
@PostMapping("/create")
public String menuCreate(@PathVariable String appId, @RequestBody WxMenu menu) throws WxErrorException {
return this.wxService.switchoverTo(appId).getMenuService().menuCreate(menu);
}
@GetMapping("/create")
public String menuCreateSample(@PathVariable String appId) throws WxErrorException, IOException {
this.wxService.switchover(appId);
return this.wxService.getMenuService().menuCreate(wxMenuService.getMenus());
}
/**
* <pre>
* 自定义菜单创建接口
* 详情请见 https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141013&token=&lang=zh_CN
* 如果要创建个性化菜单请设置matchrule属性
* 详情请见https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN
* </pre>
*
* @return 如果是个性化菜单则返回menuid否则返回null
*/
@PostMapping("/createByJson")
public String menuCreate(@PathVariable String appId, @RequestBody String json) throws WxErrorException {
return this.wxService.switchoverTo(appId).getMenuService().menuCreate(json);
}
/**
* <pre>
* 自定义菜单删除接口
* 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141015&token=&lang=zh_CN
* </pre>
*/
@GetMapping("/delete")
public void menuDelete(@PathVariable String appId) throws WxErrorException {
this.wxService.switchoverTo(appId).getMenuService().menuDelete();
}
/**
* <pre>
* 删除个性化菜单接口
* 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN
* </pre>
*
* @param menuId 个性化菜单的menuid
*/
@GetMapping("/delete/{menuId}")
public void menuDelete(@PathVariable String appId, @PathVariable String menuId) throws WxErrorException {
this.wxService.switchoverTo(appId).getMenuService().menuDelete(menuId);
}
/**
* <pre>
* 自定义菜单查询接口
* 详情请见 https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141014&token=&lang=zh_CN
* </pre>
*/
@GetMapping("/get")
public WxMpMenu menuGet(@PathVariable String appId) throws WxErrorException {
return this.wxService.switchoverTo(appId).getMenuService().menuGet();
}
/**
* <pre>
* 测试个性化菜单匹配结果
* 详情请见: http://mp.weixin.qq.com/wiki/0/c48ccd12b69ae023159b4bfaa7c39c20.html
* </pre>
*
* @param userid 可以是粉丝的OpenID也可以是粉丝的微信号
*/
@GetMapping("/menuTryMatch/{userid}")
public WxMenu menuTryMatch(@PathVariable String appId, @PathVariable String userid) throws WxErrorException {
return this.wxService.switchoverTo(appId).getMenuService().menuTryMatch(userid);
}
/**
* <pre>
* 获取自定义菜单配置接口
* 本接口将会提供公众号当前使用的自定义菜单的配置如果公众号是通过API调用设置的菜单则返回菜单的开发配置而如果公众号是在公众平台官网通过网站功能发布菜单则本接口返回运营者设置的菜单配置
* 请注意
* 1第三方平台开发者可以通过本接口在旗下公众号将业务授权给你后立即通过本接口检测公众号的自定义菜单配置并通过接口再次给公众号设置好自动回复规则以提升公众号运营者的业务体验
* 2本接口与自定义菜单查询接口的不同之处在于本接口无论公众号的接口是如何设置的都能查询到接口而自定义菜单查询接口则仅能查询到使用API设置的菜单配置
* 3认证/未认证的服务号/订阅号以及接口测试号均拥有该接口权限
* 4从第三方平台的公众号登录授权机制上来说该接口从属于消息与菜单权限集
* 5本接口中返回的图片/语音/视频为临时素材临时素材每次获取都不同3天内有效通过素材管理-获取临时素材接口来获取这些素材本接口返回的图文消息为永久素材素材通过素材管理-获取永久素材接口来获取这些素材
* 接口调用请求说明:
* http请求方式: GET请使用https协议
* https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token=ACCESS_TOKEN
* </pre>
*/
@GetMapping("/getSelfMenuInfo")
public WxMpGetSelfMenuInfoResult getSelfMenuInfo(@PathVariable String appId) throws WxErrorException {
return this.wxService.switchoverTo(appId).getMenuService().getSelfMenuInfo();
}
}

View File

@ -1,112 +0,0 @@
package com.rymcu.forest.wx.mp.controller;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
/**
* @author Binary Wang(https://github.com/binarywang)
*/
@Slf4j
@AllArgsConstructor
@RestController
@RequestMapping("/wx/portal/{appId}")
public class WxPortalController {
private final WxMpService wxService;
private final WxMpMessageRouter messageRouter;
@GetMapping(produces = "text/plain;charset=utf-8")
public String authGet(@PathVariable String appId,
@RequestParam(name = "signature", required = false) String signature,
@RequestParam(name = "timestamp", required = false) String timestamp,
@RequestParam(name = "nonce", required = false) String nonce,
@RequestParam(name = "echostr", required = false) String echostr) {
log.info("\n接收到来自微信服务器的认证消息[{}, {}, {}, {}]", signature,
timestamp, nonce, echostr);
if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) {
throw new IllegalArgumentException("请求参数非法,请核实!");
}
if (!this.wxService.switchover(appId)) {
throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置,请核实!", appId));
}
if (wxService.checkSignature(timestamp, nonce, signature)) {
return echostr;
}
return "非法请求";
}
@PostMapping(produces = "application/xml; charset=UTF-8")
public String post(@PathVariable String appId,
@RequestBody String requestBody,
@RequestParam("signature") String signature,
@RequestParam("timestamp") String timestamp,
@RequestParam("nonce") String nonce,
@RequestParam("openid") String openid,
@RequestParam(name = "encrypt_type", required = false) String encType,
@RequestParam(name = "msg_signature", required = false) String msgSignature) {
log.info("\n接收微信请求[openid=[{}], [signature=[{}], encType=[{}], msgSignature=[{}],"
+ " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
openid, signature, encType, msgSignature, timestamp, nonce, requestBody);
if (!this.wxService.switchover(appId)) {
throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置,请核实!", appId));
}
if (!wxService.checkSignature(timestamp, nonce, signature)) {
throw new IllegalArgumentException("非法请求,可能属于伪造的请求!");
}
String out = null;
if (encType == null) {
// 明文传输的消息
WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(requestBody);
WxMpXmlOutMessage outMessage = this.route(inMessage);
if (outMessage == null) {
return "";
}
out = outMessage.toXml();
} else if ("aes".equalsIgnoreCase(encType)) {
// aes加密的消息
WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody, wxService.getWxMpConfigStorage(),
timestamp, nonce, msgSignature);
log.debug("\n消息解密后内容为\n{} ", inMessage.toString());
WxMpXmlOutMessage outMessage = this.route(inMessage);
if (outMessage == null) {
return "";
}
out = outMessage.toEncryptedXml(wxService.getWxMpConfigStorage());
}
log.debug("\n组装回复信息{}", out);
return out;
}
private WxMpXmlOutMessage route(WxMpXmlMessage message) {
try {
return this.messageRouter.route(message);
} catch (Exception e) {
log.error("路由消息时出现异常!", e);
}
return null;
}
}

View File

@ -1,39 +0,0 @@
package com.rymcu.forest.wx.mp.controller;
import lombok.AllArgsConstructor;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* @author Edward
*/
@AllArgsConstructor
@Controller
@RequestMapping("/wx/redirect/{appId}")
public class WxRedirectController {
private final WxMpService wxService;
@RequestMapping("/greet")
public String greetUser(@PathVariable String appId, @RequestParam String code, ModelMap map) {
if (!this.wxService.switchover(appId)) {
throw new IllegalArgumentException(String.format("未找到对应appId=[%s]的配置,请核实!", appId));
}
try {
WxOAuth2AccessToken accessToken = wxService.getOAuth2Service().getAccessToken(code);
WxOAuth2UserInfo user = wxService.getOAuth2Service().getUserInfo(accessToken, null);
map.put("user", user);
} catch (WxErrorException e) {
e.printStackTrace();
}
return "greet_user";
}
}

View File

@ -1,77 +0,0 @@
package com.rymcu.forest.wx.mp.controller;
import com.rymcu.forest.service.WxUserService;
import com.rymcu.forest.util.ContextHolderUtils;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.bean.WxJsapiSignature;
import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.URIUtil;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
* @author ronger
*/
@Controller
@RequestMapping("/wx/oauth/{appId}")
public class WxoAuthController {
@Resource
private WxMpService wxMpService;
@Resource
private WxUserService wxUserService;
@Value("${resource.domain}")
private String domain;
@Value("${server.servlet.context-path}")
private String contextPath;
@GetMapping
public String wxAuth(@PathVariable String appId, @RequestParam(name = "redirectUrl") String redirectUrl) {
StringBuilder baseUrl;
wxMpService.switchoverTo(appId);
// 测试号
if ("wxa49093339a5a822b".equals(appId)) {
baseUrl = new StringBuilder("http://1wx.rymcu.com").append(contextPath);
} else {
baseUrl = new StringBuilder(domain).append(contextPath);
}
StringBuilder accessTokenUrl = baseUrl.append("/wx/oauth/" + appId + "/getAccessToken?redirectUrl=").append(URIUtil.encodeURIComponent(redirectUrl));
String oauth2Url = wxMpService.getOAuth2Service().buildAuthorizationUrl(accessTokenUrl.toString(), WxConsts.OAuth2Scope.SNSAPI_USERINFO, null);
return "redirect:" + oauth2Url;
}
@GetMapping("getAccessToken")
public String getAccessToken(@PathVariable String appId, @RequestParam(name = "code") String code, @RequestParam(name = "redirectUrl") String redirectUrl) throws Exception {
wxMpService.switchoverTo(appId);
WxOAuth2AccessToken oAuth2AccessToken = wxMpService.getOAuth2Service().getAccessToken(code);
boolean valid = wxMpService.getOAuth2Service().validateAccessToken(oAuth2AccessToken);
if (!valid) {
throw new Exception("无权限");
}
WxMpUser wxMpUser = wxMpService.getUserService().userInfo(oAuth2AccessToken.getOpenId());
wxUserService.saveUser(wxMpUser, appId);
ContextHolderUtils.getSession2().setAttribute("wxUser", wxMpUser);
return "redirect:" + redirectUrl;
}
@GetMapping("validJs")
@ResponseBody
public WxJsapiSignature validJs(String url) throws WxErrorException {
return wxMpService.createJsapiSignature(url);
}
@GetMapping("t")
public String reOauth() {
return "wx/oauth";
}
}

View File

@ -1,29 +0,0 @@
package com.rymcu.forest.wx.mp.error;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* <pre>
* 出错页面控制器
* Created by Binary Wang on 2018/8/25.
* </pre>
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
@Controller
@RequestMapping("/error")
public class ErrorController {
@GetMapping(value = "/404")
public String error404() {
return "error";
}
@GetMapping(value = "/500")
public String error500() {
return "error";
}
}

View File

@ -1,27 +0,0 @@
package com.rymcu.forest.wx.mp.error;
import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.server.ErrorPageRegistrar;
import org.springframework.boot.web.server.ErrorPageRegistry;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
/**
* <pre>
* 配置错误状态与对应访问路径
* Created by Binary Wang on 2018/8/25.
* </pre>
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
@Component
public class ErrorPageConfiguration implements ErrorPageRegistrar {
@Override
public void registerErrorPages(ErrorPageRegistry errorPageRegistry) {
errorPageRegistry.addErrorPages(
new ErrorPage(HttpStatus.NOT_FOUND, "/error/404"),
new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500")
);
}
}

View File

@ -1,12 +0,0 @@
package com.rymcu.forest.wx.mp.handler;
import me.chanjar.weixin.mp.api.WxMpMessageHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Binary Wang(https://github.com/binarywang)
*/
public abstract class AbstractHandler implements WxMpMessageHandler {
protected Logger logger = LoggerFactory.getLogger(getClass());
}

View File

@ -1,25 +0,0 @@
package com.rymcu.forest.wx.mp.handler;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* @author Binary Wang(https://github.com/binarywang)
*/
@Component
public class KfSessionHandler extends AbstractHandler {
@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
Map<String, Object> context, WxMpService wxMpService,
WxSessionManager sessionManager) {
//TODO 对会话做处理
return null;
}
}

View File

@ -1,44 +0,0 @@
package com.rymcu.forest.wx.mp.handler;
import com.rymcu.forest.wx.mp.builder.TextBuilder;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.stereotype.Component;
import java.util.Map;
import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType;
/**
* @author Binary Wang(https://github.com/binarywang)
*/
@Component
public class LocationHandler extends AbstractHandler {
@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
Map<String, Object> context, WxMpService wxMpService,
WxSessionManager sessionManager) {
if (wxMessage.getMsgType().equals(XmlMsgType.LOCATION)) {
//TODO 接收处理用户发送的地理位置消息
try {
String content = "感谢反馈,您的的地理位置已收到!";
return new TextBuilder().build(content, wxMessage, null);
} catch (Exception e) {
this.logger.error("位置消息接收处理失败", e);
return null;
}
}
//上报地理位置事件
this.logger.info("上报地理位置,纬度 : {},经度 : {},精度 : {}",
wxMessage.getLatitude(), wxMessage.getLongitude(), String.valueOf(wxMessage.getPrecision()));
//TODO 可以将用户地理位置信息保存到本地数据库以便以后使用
return null;
}
}

View File

@ -1,25 +0,0 @@
package com.rymcu.forest.wx.mp.handler;
import com.rymcu.forest.wx.mp.utils.JsonUtils;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* @author Binary Wang(https://github.com/binarywang)
*/
@Component
public class LogHandler extends AbstractHandler {
@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
Map<String, Object> context, WxMpService wxMpService,
WxSessionManager sessionManager) {
this.logger.info("\n接收到请求消息内容{}", JsonUtils.toJson(wxMessage));
return null;
}
}

View File

@ -1,35 +0,0 @@
package com.rymcu.forest.wx.mp.handler;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.stereotype.Component;
import java.util.Map;
import static me.chanjar.weixin.common.api.WxConsts.EventType;
/**
* @author Binary Wang(https://github.com/binarywang)
*/
@Component
public class MenuHandler extends AbstractHandler {
@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
Map<String, Object> context, WxMpService weixinService,
WxSessionManager sessionManager) {
String msg = String.format("type:%s, event:%s, key:%s",
wxMessage.getMsgType(), wxMessage.getEvent(),
wxMessage.getEventKey());
if (EventType.VIEW.equals(wxMessage.getEvent())) {
return null;
}
return WxMpXmlOutMessage.TEXT().content(msg)
.fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser())
.build();
}
}

View File

@ -1,45 +0,0 @@
package com.rymcu.forest.wx.mp.handler;
import com.rymcu.forest.wx.mp.builder.TextBuilder;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import java.util.Map;
import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType;
/**
* @author Binary Wang(https://github.com/binarywang)
*/
@Component
public class MsgHandler extends AbstractHandler {
@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
Map<String, Object> context, WxMpService wxMpService,
WxSessionManager sessionManager) {
if (!wxMessage.getMsgType().equals(XmlMsgType.EVENT)) {
//TODO 可以选择将消息保存到本地
}
if (wxMessage == null || StringUtils.isBlank(wxMessage.getContent())) {
return WxMpXmlOutMessage.TRANSFER_CUSTOMER_SERVICE()
.fromUser(wxMessage.getToUser())
.toUser(wxMessage.getFromUser()).build();
}
logger.info("\n接收到 {} 公众号请求消息,内容:{}", wxMpService.getWxMpConfigStorage().getAppId(), wxMessage);
String content = "我们已经收到您的留言,稍后客服将会联系您!";
return new TextBuilder().build(content, wxMessage, wxMpService);
}
}

View File

@ -1,24 +0,0 @@
package com.rymcu.forest.wx.mp.handler;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* @author Binary Wang(https://github.com/binarywang)
*/
@Component
public class NullHandler extends AbstractHandler {
@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
Map<String, Object> context, WxMpService wxMpService,
WxSessionManager sessionManager) {
return null;
}
}

View File

@ -1,25 +0,0 @@
package com.rymcu.forest.wx.mp.handler;
import java.util.Map;
import org.springframework.stereotype.Component;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
/**
* @author Binary Wang(https://github.com/binarywang)
*/
@Component
public class ScanHandler extends AbstractHandler {
@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMpXmlMessage, Map<String, Object> map,
WxMpService wxMpService, WxSessionManager wxSessionManager) throws WxErrorException {
// 扫码事件处理
return null;
}
}

View File

@ -1,27 +0,0 @@
package com.rymcu.forest.wx.mp.handler;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* 门店审核事件处理
*
* @author Binary Wang(https://github.com/binarywang)
*/
@Component
public class StoreCheckNotifyHandler extends AbstractHandler {
@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
Map<String, Object> context, WxMpService wxMpService,
WxSessionManager sessionManager) {
// TODO 处理门店审核事件
return null;
}
}

View File

@ -1,71 +0,0 @@
package com.rymcu.forest.wx.mp.handler;
import java.util.Map;
import com.rymcu.forest.wx.mp.builder.TextBuilder;
import org.springframework.stereotype.Component;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
/**
* @author Binary Wang(https://github.com/binarywang)
*/
@Component
public class SubscribeHandler extends AbstractHandler {
@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
Map<String, Object> context, WxMpService weixinService,
WxSessionManager sessionManager) throws WxErrorException {
this.logger.info("新关注用户 OPENID: " + wxMessage.getFromUser());
// 获取微信用户基本信息
try {
WxMpUser userWxInfo = weixinService.getUserService()
.userInfo(wxMessage.getFromUser(), null);
if (userWxInfo != null) {
// TODO 可以添加关注用户到本地数据库
}
} catch (WxErrorException e) {
if (e.getError().getErrorCode() == 48001) {
this.logger.info("该公众号没有获取用户信息权限!");
}
}
WxMpXmlOutMessage responseResult = null;
try {
responseResult = this.handleSpecial(wxMessage);
} catch (Exception e) {
this.logger.error(e.getMessage(), e);
}
if (responseResult != null) {
return responseResult;
}
try {
return new TextBuilder().build("感谢关注", wxMessage, weixinService);
} catch (Exception e) {
this.logger.error(e.getMessage(), e);
}
return null;
}
/**
* 处理特殊请求比如如果是扫码进来的可以做相应处理
*/
private WxMpXmlOutMessage handleSpecial(WxMpXmlMessage wxMessage)
throws Exception {
//TODO
return null;
}
}

View File

@ -1,27 +0,0 @@
package com.rymcu.forest.wx.mp.handler;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* @author Binary Wang(https://github.com/binarywang)
*/
@Component
public class UnsubscribeHandler extends AbstractHandler {
@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
Map<String, Object> context, WxMpService wxMpService,
WxSessionManager sessionManager) {
String openId = wxMessage.getFromUser();
this.logger.info("取消关注用户 OPENID: " + openId);
// TODO 可以更新本地数据库为取消关注状态
return null;
}
}

View File

@ -1,17 +0,0 @@
package com.rymcu.forest.wx.mp.service;
import me.chanjar.weixin.common.bean.menu.WxMenu;
import java.io.IOException;
/**
* @author ronger
*/
public interface WxMenuService {
/**
* 获取公众号菜单配置
* @return
* @throws IOException
*/
WxMenu getMenus() throws IOException;
}

View File

@ -1,46 +0,0 @@
package com.rymcu.forest.wx.mp.service.impl;
import com.rymcu.forest.wx.mp.service.WxMenuService;
import me.chanjar.weixin.common.bean.menu.WxMenu;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
/**
* @author ronger
*/
@Service
public class WxMenuServiceImpl implements WxMenuService {
@Value("classpath:wxMpMenus.json")
private Resource menuResource;
@Override
public WxMenu getMenus() throws IOException {
File file = menuResource.getFile();
String menuJson = this.jsonRead(file);
WxMenu wxMenu = WxMenu.fromJson(menuJson);
return wxMenu;
}
private String jsonRead(File file) {
Scanner scanner = null;
StringBuilder buffer = new StringBuilder();
try {
scanner = new Scanner(file, "utf-8");
while (scanner.hasNextLine()) {
buffer.append(scanner.nextLine());
}
} catch (Exception e) {
} finally {
if (scanner != null) {
scanner.close();
}
}
return buffer.toString();
}
}

View File

@ -1,9 +0,0 @@
package com.rymcu.forest.wx.mp.utils;
import com.alibaba.fastjson.JSONObject;
public class JsonUtils {
public static String toJson(Object obj) {
return JSONObject.toJSONString(obj);
}
}

View File

@ -1,42 +0,0 @@
package com.rymcu.forest.wx.open.config;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* @author <a href="https://github.com/007gzs">007</a>
*/
@Getter
@Setter
@ConfigurationProperties(prefix = "wx.open")
public class WxOpenProperties {
/**
* 设置微信三方平台的appid
*/
private String componentAppId;
/**
* 设置微信三方平台的app secret
*/
private String componentSecret;
/**
* 设置微信三方平台的token
*/
private String componentToken;
/**
* 设置微信三方平台的EncodingAESKey
*/
private String componentAesKey;
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this,
ToStringStyle.MULTI_LINE_STYLE);
}
}

View File

@ -1,78 +0,0 @@
package com.rymcu.forest.wx.open.controller;
import com.rymcu.forest.wx.open.handler.WxOpenServiceHandler;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.open.bean.result.WxOpenAuthorizerInfoResult;
import me.chanjar.weixin.open.bean.result.WxOpenQueryAuthResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author <a href="https://github.com/007gzs">007</a>
*/
@Controller
@RequestMapping("/wx/open/auth")
public class WxOpenApiController {
private final Logger logger = LoggerFactory.getLogger(getClass());
@Resource
private WxOpenServiceHandler wxOpenServiceHandler;
@GetMapping("/goto_auth_url_show")
@ResponseBody
public String gotoPreAuthUrlShow(){
return "<a href='goto_auth_url'>go</a>";
}
@GetMapping("/goto_auth_url")
public void gotoPreAuthUrl(HttpServletRequest request, HttpServletResponse response){
System.out.println("===================================Host:");
System.out.println(request.getHeader("host"));
String host = request.getHeader("host");
String url = "http://"+host+"/open/auth/jump";
try {
url = wxOpenServiceHandler.getWxOpenComponentService().getPreAuthUrl(url);
// 添加来源解决302跳转来源丢失的问题
response.addHeader("Referer", "http://"+host);
response.sendRedirect(url);
} catch (WxErrorException | IOException e) {
logger.error("gotoPreAuthUrl", e);
throw new RuntimeException(e);
}
}
@GetMapping("/jump")
@ResponseBody
public WxOpenQueryAuthResult jump(@RequestParam("auth_code") String authorizationCode){
try {
WxOpenQueryAuthResult queryAuthResult = wxOpenServiceHandler.getWxOpenComponentService().getQueryAuth(authorizationCode);
logger.info("getQueryAuth", queryAuthResult);
return queryAuthResult;
} catch (WxErrorException e) {
logger.error("gotoPreAuthUrl", e);
throw new RuntimeException(e);
}
}
@GetMapping("/get_auth_info")
@ResponseBody
public WxOpenAuthorizerInfoResult getAuthInfo(@RequestParam String appId){
try {
return wxOpenServiceHandler.getWxOpenComponentService().getAuthorizerInfo(appId);
} catch (WxErrorException e) {
logger.error("getAuthInfo", e);
throw new RuntimeException(e);
}
}
}

View File

@ -1,122 +0,0 @@
package com.rymcu.forest.wx.open.controller;
import com.rymcu.forest.wx.open.handler.WxOpenServiceHandler;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import me.chanjar.weixin.open.bean.message.WxOpenXmlMessage;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* @author <a href="https://github.com/007gzs">007</a>
*/
@RestController
@RequestMapping("/wx/notify")
public class WxOpenNotifyController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
protected WxOpenServiceHandler wxOpenService;
/**
* 全网发布官方测试小程序 AppId
*/
private final static String testMiniProgramAppId = "wxd101a85aa106f53e";
/**
* 全网发布官方测试公众号 AppId
*/
private final static String testMpAppId = "wx570bc396a51b8ff8";
private final static String TESTCOMPONENT_MSG_TYPE_TEXT = "TESTCOMPONENT_MSG_TYPE_TEXT";
private final static String TESTCOMPONENT_MSG_TYPE_TEXT_callback = "TESTCOMPONENT_MSG_TYPE_TEXT_callback";
@RequestMapping("/receive_ticket")
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("非法请求,可能属于伪造的请求!");
}
// 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);
}
return "success";
}
@RequestMapping("/{appId}/callback")
public Object callback(@RequestBody(required = false) String requestBody,
@PathVariable("appId") String appId,
@RequestParam("signature") String signature,
@RequestParam("timestamp") String timestamp,
@RequestParam("nonce") String nonce,
@RequestParam("openid") String openid,
@RequestParam("encrypt_type") String encType,
@RequestParam("msg_signature") String msgSignature) {
this.logger.info(
"\n接收微信请求[appId=[{}], openid=[{}], signature=[{}], encType=[{}], msgSignature=[{}],"
+ " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
appId, openid, signature, encType, msgSignature, timestamp, nonce, requestBody);
if (!StringUtils.equalsIgnoreCase("aes", encType)
|| !wxOpenService.getWxOpenComponentService().checkSignature(timestamp, nonce, signature)) {
throw new IllegalArgumentException("非法请求,可能属于伪造的请求!");
}
String out = "";
// aes加密的消息
WxMpXmlMessage inMessage = WxOpenXmlMessage.fromEncryptedMpXml(requestBody,
wxOpenService.getWxOpenConfigStorage(), timestamp, nonce, msgSignature);
this.logger.debug("\n消息解密后内容为\n{} ", inMessage.toString());
// 全网发布测试用例
if (StringUtils.equalsAnyIgnoreCase(appId, testMiniProgramAppId, testMpAppId)) {
try {
if (StringUtils.equals(inMessage.getMsgType(), WxConsts.XmlMsgType.TEXT)) {
if (StringUtils.equals(inMessage.getContent(), TESTCOMPONENT_MSG_TYPE_TEXT)) {
out = WxOpenXmlMessage.wxMpOutXmlMessageToEncryptedXml(
WxMpXmlOutMessage.TEXT().content(TESTCOMPONENT_MSG_TYPE_TEXT_callback)
.fromUser(inMessage.getToUser())
.toUser(inMessage.getFromUser())
.build(),
wxOpenService.getWxOpenConfigStorage()
);
} else if (StringUtils.startsWith(inMessage.getContent(), "QUERY_AUTH_CODE:")) {
String msg = inMessage.getContent().replace("QUERY_AUTH_CODE:", "") + "_from_api";
WxMpKefuMessage kefuMessage = WxMpKefuMessage.TEXT().content(msg).toUser(inMessage.getFromUser()).build();
wxOpenService.getWxOpenComponentService().getWxMpServiceByAppid(appId).getKefuService().sendKefuMessage(kefuMessage);
}
} else if (StringUtils.equals(inMessage.getMsgType(), "event")) {
WxMpKefuMessage kefuMessage = WxMpKefuMessage.TEXT().content(inMessage.getEvent() + "from_callback").toUser(inMessage.getFromUser()).build();
wxOpenService.getWxOpenComponentService().getWxMpServiceByAppid(appId).getKefuService().sendKefuMessage(kefuMessage);
}
} catch (WxErrorException e) {
logger.error("callback", e);
}
} else {
WxMpXmlOutMessage outMessage = wxOpenService.getWxOpenMessageRouter().route(inMessage, appId);
if (outMessage != null) {
out = WxOpenXmlMessage.wxMpOutXmlMessageToEncryptedXml(outMessage, wxOpenService.getWxOpenConfigStorage());
}
}
return out;
}
}

View File

@ -1,67 +0,0 @@
package com.rymcu.forest.wx.open.handler;
import com.rymcu.forest.config.RedisProperties;
import com.rymcu.forest.wx.open.config.WxOpenProperties;
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.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Service;
import redis.clients.jedis.JedisPool;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
/**
* @author ronger
*/
@Service
@EnableConfigurationProperties({WxOpenProperties.class, RedisProperties.class})
public class WxOpenServiceHandler extends WxOpenServiceImpl {
private Logger logger = LoggerFactory.getLogger(getClass());
@Resource
private WxOpenProperties wxOpenProperties;
@Resource
private RedisProperties redisProperties;
private static JedisPool pool;
private WxOpenMessageRouter wxOpenMessageRouter;
@PostConstruct
public void init() {
WxOpenInRedisConfigStorage inRedisConfigStorage = new WxOpenInRedisConfigStorage(getJedisPool());
inRedisConfigStorage.setComponentAppId(wxOpenProperties.getComponentAppId());
inRedisConfigStorage.setComponentAppSecret(wxOpenProperties.getComponentSecret());
inRedisConfigStorage.setComponentToken(wxOpenProperties.getComponentToken());
inRedisConfigStorage.setComponentAesKey(wxOpenProperties.getComponentAesKey());
setWxOpenConfigStorage(inRedisConfigStorage);
wxOpenMessageRouter = new WxOpenMessageRouter(this);
wxOpenMessageRouter.rule().handler((wxMpXmlMessage, map, wxMpService, wxSessionManager) -> {
logger.info("\n接收到 {} 公众号请求消息,内容:{}", wxMpService.getWxMpConfigStorage().getAppId(), wxMpXmlMessage);
return null;
}).next();
}
private JedisPool getJedisPool() {
if (pool == null) {
synchronized (WxOpenServiceHandler.class) {
if (pool == null) {
pool = new JedisPool(redisProperties, redisProperties.getHost(),
redisProperties.getPort(), redisProperties.getConnectionTimeout(),
redisProperties.getSoTimeout(), redisProperties.getPassword(),
redisProperties.getDatabase(), redisProperties.getClientName(),
redisProperties.isSsl(), redisProperties.getSslSocketFactory(),
redisProperties.getSslParameters(), redisProperties.getHostnameVerifier());
}
}
}
return pool;
}
public WxOpenMessageRouter getWxOpenMessageRouter() {
return wxOpenMessageRouter;
}
}