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.setNickname(wxMpUser.getNickname());
+ wxUser.setHeadImgUrl(wxMpUser.getHeadImgUrl());
+ wxUser.setCountry(wxMpUser.getCountry());
+ wxUser.setProvince(wxMpUser.getProvince());
+ wxUser.setCity(wxMpUser.getCity());
+ wxUser.setSex(wxMpUser.getSex());
+ wxUser.setSubscribe(wxMpUser.getSubscribe());
+ wxUser.setSubscribeTime(wxMpUser.getSubscribeTime());
+ wxUser.setUnionId(wxMpUser.getUnionId());
+ wxUser.setOpenId(wxMpUser.getOpenId());
+ wxUser.setLanguage(wxMpUser.getLanguage());
+ wxUser.setSexDesc(wxMpUser.getSexDesc());
+ return wxUser;
+ }
+}
diff --git a/src/main/java/com/rymcu/vertical/task/BaiDuCronTask.java b/src/main/java/com/rymcu/forest/task/BaiDuCronTask.java
similarity index 82%
rename from src/main/java/com/rymcu/vertical/task/BaiDuCronTask.java
rename to src/main/java/com/rymcu/forest/task/BaiDuCronTask.java
index 36b8f89..097d7ff 100644
--- a/src/main/java/com/rymcu/vertical/task/BaiDuCronTask.java
+++ b/src/main/java/com/rymcu/forest/task/BaiDuCronTask.java
@@ -1,7 +1,7 @@
-package com.rymcu.vertical.task;
+package com.rymcu.forest.task;
-import com.rymcu.vertical.core.constant.ProjectConstant;
-import com.rymcu.vertical.util.BaiDuUtils;
+import com.rymcu.forest.core.constant.ProjectConstant;
+import com.rymcu.forest.util.BaiDuUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
diff --git a/src/main/java/com/rymcu/forest/util/BaiDuAipUtils.java b/src/main/java/com/rymcu/forest/util/BaiDuAipUtils.java
new file mode 100644
index 0000000..a49c1e6
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/util/BaiDuAipUtils.java
@@ -0,0 +1,197 @@
+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 = "4.1 进制转换基础知识 \n" +
+ "进制实际是一个非常简单易懂的概念,对于初学者来说也很容易上手。我们接触最多的就是十进制了,它的特点为逢十进一,包含 0,1,2,3,4,5,6,7,8,9 共十个元素。在生活中我们用到的基本都是十进制了,所以大家对它已经非常熟悉并能应用自如,但是在计算机(包括单片机)世界里,所有都是以二进制为基础的。二进制的特点为逢二进一,包含 0,1 共两个元素。计算机中的数据都是以二进制存储的,这就是我们所说的 0,1 世界。通常我们讲的 32 位或 64 位操作系统这里的位指的就是二进制位数。因为我们实际多用十进制,那么我们在和计算机系统沟通过程中,十进制与二进制之间的转换就变得很重要了。进制之间的转换如下表所示。 \n" +
+ " \n" +
+ "二进制转换十进制公式如下: \n" +
+ " \n" +
+ "其中,n 表示二进制的位数。 \n" +
+ "下面我们举个例子来更加直观的说明这个公式: \n" +
+ "例如:1101,这是一个 4 位的二进制数,计算如下, \n" +
+ " \n" +
+ "大家可以利用这个公式计算的结果和上表进行一一对照。 \n" +
+ "十六进制也是我们常用的进制,它的特点为逢十六进一,包括 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F 共十六个元素。实际上十六进制是二进制的一种特殊形式,十六进制的 1 位等价于二进制的 4 位,在 C 语言编程中我们常用十六进制来表示二进制数。在实际应用中我们常常该数字之前加一个前缀来表示他的进制:“0b”表示二进制,“0x”表示十六进制。下面我们举例说明: \n" +
+ "0b10010010 = 0x92 \n" +
+ "上面一个八位的二进制数转换为一个两位的十六进制数。二进制的前 4 位等于十六进制的第 1 位: \n" +
+ "0b1001 = 0x9 \n" +
+ "二进制数的后 4 位等于十六进制的第 2 位: \n" +
+ "0b0010 = 0x2 \n" +
+ "在计算机中,我们通常所说的二进制的 1 位也叫 1bit,8 位表示 1 个字节,也叫 1Byte。根据二进制与十六机制的关系,一个 2 位的十六进制数则可表示 1 个字节。在运用的过程中牢记 0~15 的十进制与二进制、十六进制之间的转换关系对于程序的编写有很大的好处。
\n" +
+ "4.2 闪烁 LED 小灯 \n" +
+ "怎么让 LED 小灯闪烁?我们最先想到的办法当然是先让 LED 小灯点亮,延时一段时间,熄灭 LED 小灯,再延时一段时间,一直循环上面的步骤就能实现 LED 小灯的闪烁了。根据第 3 章的知识我们知道点亮 LED 的语句为“led0 = 0;”,熄灭 LED 的语句为“led0 = 1;”。按照第 3 章介绍我们重新建立一个 LED 小灯闪烁的工程。程序代码设计如下:
\n" +
+ "#include<reg52.h> //寄存器声明头文件 \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<5000;i++);//延时一段时间 \n" +
+ " led0 = 1;//熄灭LED小灯 \n" +
+ " for(i=0;i<5000;i++);//再延时一段时间 \n" +
+ " } \n" +
+ "} \n" +
+ "
\n" +
+ "4.3\t跑马灯设计 \n" +
+ "在我们的开发板上设计了 8 个依次排列的 LED 小灯,让小灯依次点亮和熄灭实现跑马灯的效果是我们这一节的主要内容。
\n" +
+ "4.3.1 硬件设计 \n" +
+ "8 个 LED 小灯的硬件电路设计原理图如下图所示: \n" +
+ " \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 小灯的亮灭。 \n" +
+ "该实验要实现的功能为:首先点亮 LED0,然后延迟一段时间,熄灭 LED0,熄灭 LED0 点亮 LED1,延迟一段时间,熄灭 LED1 点亮 LED2,延迟一段时间,一直到熄灭 LED6 点亮 LED7,依照上面的步骤一直循环下去,便实现了一个简单的跑马灯的效果。
\n" +
+ "4.3.2 软件设计 \n" +
+ "前面我们试验中都是只对 P1.0 这个管脚进行赋值,来控制 LED 小灯 led0 的亮灭。实际在编写程序的过程中我们可以对 P1 寄存器进行直接赋值来同时控制 8 个 LED 小灯。 \n" +
+ " \n" +
+ "如上表所示,P1 寄存器是一个 8 位的寄存器,最高位到最低位依次对应的 P1.7 管脚到 P1.0 管脚。点亮某个 LED 小灯的二进制,十六进制赋值如上表所示。例如 P1 = 0xFE;表示点亮 led0,P1=0x7F;则表示点亮 led7。在软件代码设计时,我们想到的第一个方法为依次点亮小灯并延时,代码如下所示。
\n" +
+ "#include<reg52.h> //加载头文件\n" +
+ "int i;\n" +
+ "\n" +
+ "void main()//主函数入口\n" +
+ "{\n" +
+ "\tP1 = 0xFE; //点亮LED0\n" +
+ "\tfor(i=0;i<5000;i++);//延时一段时间\n" +
+ "\tP1 = 0xFD; //点亮LED1\n" +
+ "\tfor(i=0;i<5000;i++);//延时一段时间\n" +
+ "\tP1 = 0xFB; //点亮LED2\n" +
+ "\tfor(i=0;i<5000;i++);//延时一段时间\n" +
+ "\tP1 = 0xF7; //点亮LED3\n" +
+ "\tfor(i=0;i<5000;i++);//延时一段时间\n" +
+ "\tP1 = 0xEF; //点亮LED4\n" +
+ "\tfor(i=0;i<5000;i++);//延时一段时间\n" +
+ "\tP1 = 0xDF; //点亮LED5\n" +
+ "\tfor(i=0;i<5000;i++);//延时一段时间\n" +
+ "\tP1 = 0xBF; //点亮LED6\n" +
+ "\tfor(i=0;i<5000;i++);//延时一段时间\n" +
+ "\tP1 = 0x7F; //点亮LED7\n" +
+ "\tfor(i=0;i<5000;i++);//延时一段时间\n" +
+ "} \n" +
+ "
\n" +
+ "我们对代码进行一下小的改进,这个方法这里称之为“左移取反”法,这个方法在很多的应用中都能用到,非常实用。代码如下图所示。
\n" +
+ "#include<reg52.h> //加载头文件\n" +
+ "int i;\n" +
+ "int flag=0;\n" +
+ " \n" +
+ "void main()//主函数入口\n" +
+ "{ \n" +
+ " P0 = 0xff;\n" +
+ "\twhile(1)\n" +
+ "\t{\n" +
+ "\t\tP1 = ~(0x01<<flag);//P1的值等于1左移flag位后取反,点亮第flag位LED小灯亮\n" +
+ "\t\tfor(i=0;i<25000;i++);//延时一段时间\n" +
+ "\n" +
+ "\t\tif(flag>=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" +
+ "
\n" +
+ "我们对上面代码进行分析,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 为其他值时,大家可以进行一一分析。
\n" +
+ "4.3.3 下载验证 \n" +
+ "将程序通过 STC-isp 软件下载到单片机,观察 8 个 LED 小灯效果与设想的效果是否一致?至此,本章的内容讲解完毕,内容包括进制转换的基础知识、LED 小灯闪速程序以及跑马灯的两种程序。大家在动手操作的过程中多多下载到单片机中观察现象,加深印象。
\n";
+ System.out.println(getKeywords(title, content));
+ System.out.println(getNewsSummary(title, content, 200));
+
+ }
+
+ public static List 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 options = new HashMap(1);
+
+ // 新闻摘要接口
+ JSONObject res = client.keyword(title, Html2TextUtil.getContent(content), options);
+ List 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 options = new HashMap(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 options = new HashMap(1);
+ options.put("title", title);
+
+ // 新闻摘要接口
+ JSONObject res = client.newsSummary(Html2TextUtil.getContent(content), maxSummaryLen, options);
+ return res.getString("summary");
+ }
+
+}
diff --git a/src/main/java/com/rymcu/vertical/util/BaiDuUtils.java b/src/main/java/com/rymcu/forest/util/BaiDuUtils.java
similarity index 99%
rename from src/main/java/com/rymcu/vertical/util/BaiDuUtils.java
rename to src/main/java/com/rymcu/forest/util/BaiDuUtils.java
index 3e72334..a85d72e 100644
--- a/src/main/java/com/rymcu/vertical/util/BaiDuUtils.java
+++ b/src/main/java/com/rymcu/forest/util/BaiDuUtils.java
@@ -1,4 +1,4 @@
-package com.rymcu.vertical.util;
+package com.rymcu.forest.util;
import jodd.http.HttpRequest;
import jodd.http.HttpResponse;
diff --git a/src/main/java/com/rymcu/vertical/util/BeanCopierUtil.java b/src/main/java/com/rymcu/forest/util/BeanCopierUtil.java
similarity index 98%
rename from src/main/java/com/rymcu/vertical/util/BeanCopierUtil.java
rename to src/main/java/com/rymcu/forest/util/BeanCopierUtil.java
index 18aac4f..6186f19 100644
--- a/src/main/java/com/rymcu/vertical/util/BeanCopierUtil.java
+++ b/src/main/java/com/rymcu/forest/util/BeanCopierUtil.java
@@ -1,4 +1,4 @@
-package com.rymcu.vertical.util;
+package com.rymcu.forest.util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.beans.BeanCopier;
diff --git a/src/main/java/com/rymcu/vertical/util/CacheUtils.java b/src/main/java/com/rymcu/forest/util/CacheUtils.java
similarity index 98%
rename from src/main/java/com/rymcu/vertical/util/CacheUtils.java
rename to src/main/java/com/rymcu/forest/util/CacheUtils.java
index c532cd7..2e99989 100644
--- a/src/main/java/com/rymcu/vertical/util/CacheUtils.java
+++ b/src/main/java/com/rymcu/forest/util/CacheUtils.java
@@ -1,4 +1,4 @@
-package com.rymcu.vertical.util;
+package com.rymcu.forest.util;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;
diff --git a/src/main/java/com/rymcu/vertical/util/ContextHolderUtils.java b/src/main/java/com/rymcu/forest/util/ContextHolderUtils.java
similarity index 98%
rename from src/main/java/com/rymcu/vertical/util/ContextHolderUtils.java
rename to src/main/java/com/rymcu/forest/util/ContextHolderUtils.java
index 37e6743..e8fa42b 100644
--- a/src/main/java/com/rymcu/vertical/util/ContextHolderUtils.java
+++ b/src/main/java/com/rymcu/forest/util/ContextHolderUtils.java
@@ -1,4 +1,4 @@
-package com.rymcu.vertical.util;
+package com.rymcu.forest.util;
import org.apache.commons.lang.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
diff --git a/src/main/java/com/rymcu/vertical/util/Digests.java b/src/main/java/com/rymcu/forest/util/Digests.java
similarity index 98%
rename from src/main/java/com/rymcu/vertical/util/Digests.java
rename to src/main/java/com/rymcu/forest/util/Digests.java
index 2629d1a..52464cf 100644
--- a/src/main/java/com/rymcu/vertical/util/Digests.java
+++ b/src/main/java/com/rymcu/forest/util/Digests.java
@@ -1,4 +1,4 @@
-package com.rymcu.vertical.util;
+package com.rymcu.forest.util;
import org.apache.commons.lang3.Validate;
diff --git a/src/main/java/com/rymcu/vertical/util/Encodes.java b/src/main/java/com/rymcu/forest/util/Encodes.java
similarity index 99%
rename from src/main/java/com/rymcu/vertical/util/Encodes.java
rename to src/main/java/com/rymcu/forest/util/Encodes.java
index 8c42241..009cef7 100644
--- a/src/main/java/com/rymcu/vertical/util/Encodes.java
+++ b/src/main/java/com/rymcu/forest/util/Encodes.java
@@ -1,7 +1,7 @@
/**
* Copyright © 2012-2016 zkjkgc All rights reserved.
*/
-package com.rymcu.vertical.util;
+package com.rymcu.forest.util;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Base64;
diff --git a/src/main/java/com/rymcu/vertical/util/ErrorCode.java b/src/main/java/com/rymcu/forest/util/ErrorCode.java
similarity index 94%
rename from src/main/java/com/rymcu/vertical/util/ErrorCode.java
rename to src/main/java/com/rymcu/forest/util/ErrorCode.java
index 86a36ad..79f818e 100644
--- a/src/main/java/com/rymcu/vertical/util/ErrorCode.java
+++ b/src/main/java/com/rymcu/forest/util/ErrorCode.java
@@ -1,4 +1,4 @@
-package com.rymcu.vertical.util;
+package com.rymcu.forest.util;
/**
*
diff --git a/src/main/java/com/rymcu/vertical/util/Exceptions.java b/src/main/java/com/rymcu/forest/util/Exceptions.java
similarity index 98%
rename from src/main/java/com/rymcu/vertical/util/Exceptions.java
rename to src/main/java/com/rymcu/forest/util/Exceptions.java
index 6d3c30d..97c1ede 100644
--- a/src/main/java/com/rymcu/vertical/util/Exceptions.java
+++ b/src/main/java/com/rymcu/forest/util/Exceptions.java
@@ -1,7 +1,7 @@
/**
* Copyright © 2012-2016 zkjkgc All rights reserved.
*/
-package com.rymcu.vertical.util;
+package com.rymcu.forest.util;
import javax.servlet.http.HttpServletRequest;
import java.io.PrintWriter;
diff --git a/src/main/java/com/rymcu/vertical/util/FileUtils.java b/src/main/java/com/rymcu/forest/util/FileUtils.java
similarity index 99%
rename from src/main/java/com/rymcu/vertical/util/FileUtils.java
rename to src/main/java/com/rymcu/forest/util/FileUtils.java
index 137c0c3..7d87994 100644
--- a/src/main/java/com/rymcu/vertical/util/FileUtils.java
+++ b/src/main/java/com/rymcu/forest/util/FileUtils.java
@@ -1,4 +1,4 @@
-package com.rymcu.vertical.util;
+package com.rymcu.forest.util;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
diff --git a/src/main/java/com/rymcu/vertical/util/Html2TextUtil.java b/src/main/java/com/rymcu/forest/util/Html2TextUtil.java
similarity index 97%
rename from src/main/java/com/rymcu/vertical/util/Html2TextUtil.java
rename to src/main/java/com/rymcu/forest/util/Html2TextUtil.java
index fb06f28..c4030cc 100644
--- a/src/main/java/com/rymcu/vertical/util/Html2TextUtil.java
+++ b/src/main/java/com/rymcu/forest/util/Html2TextUtil.java
@@ -1,4 +1,4 @@
-package com.rymcu.vertical.util;
+package com.rymcu.forest.util;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.parser.ParserDelegator;
diff --git a/src/main/java/com/rymcu/forest/util/NotificationUtils.java b/src/main/java/com/rymcu/forest/util/NotificationUtils.java
new file mode 100644
index 0000000..b301bdd
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/util/NotificationUtils.java
@@ -0,0 +1,86 @@
+package com.rymcu.forest.util;
+
+import com.rymcu.forest.core.constant.NotificationConstant;
+import com.rymcu.forest.entity.Follow;
+import com.rymcu.forest.entity.Notification;
+import com.rymcu.forest.entity.User;
+import com.rymcu.forest.service.FollowService;
+import com.rymcu.forest.service.NotificationService;
+import com.rymcu.forest.service.UserService;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.concurrent.*;
+
+/**
+ * 消息通知工具类
+ *
+ * @author ronger
+ */
+public class NotificationUtils {
+
+ @Resource
+ private static NotificationService notificationService = SpringContextHolder.getBean(NotificationService.class);
+ @Resource
+ private static UserService userService = SpringContextHolder.getBean(UserService.class);
+ @Resource
+ private static FollowService followService = SpringContextHolder.getBean(FollowService.class);
+
+ public static void sendAnnouncement(Integer dataId, String dataType, String dataSummary) {
+ ExecutorService executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue());
+ CompletableFuture.supplyAsync(() -> {
+ try {
+ List users = userService.findAll();
+ users.forEach(user -> {
+ saveNotification(user.getIdUser(), dataId, dataType, dataSummary);
+ });
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ return 0;
+ }, executor);
+ }
+
+ public static void saveNotification(Integer idUser, Integer dataId, String dataType, String dataSummary) {
+ ExecutorService executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue());
+ CompletableFuture.supplyAsync(() -> {
+ try {
+ Notification notification = notificationService.findNotification(idUser, dataId, dataType);
+ if (notification == null || NotificationConstant.UpdateArticle.equals(dataType)) {
+ System.out.println("------------------- 开始执行消息通知 ------------------");
+ Integer result = notificationService.save(idUser, dataId, dataType, dataSummary);
+ if (result == 0) {
+ // TODO 记录操作失败数据
+ }
+ }
+ } catch (Exception ex) {
+ // TODO 记录操作失败数据
+ ex.printStackTrace();
+ }
+ return 0;
+ }, executor);
+
+ }
+
+ public static void sendArticlePush(Integer dataId, String dataType, String dataSummary, Integer articleAuthorId) {
+ ExecutorService executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue());
+ CompletableFuture.supplyAsync(() -> {
+ try {
+ List follows;
+ if (NotificationConstant.PostArticle.equals(dataType)) {
+ // 关注用户通知
+ follows = followService.findByFollowingId("0", articleAuthorId);
+ } else {
+ // 关注文章通知
+ follows = followService.findByFollowingId("3", articleAuthorId);
+ }
+ follows.forEach(follow -> {
+ saveNotification(follow.getFollowerId(), dataId, dataType, dataSummary);
+ });
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ return 0;
+ }, executor);
+ }
+}
diff --git a/src/main/java/com/rymcu/vertical/util/SpringContextHolder.java b/src/main/java/com/rymcu/forest/util/SpringContextHolder.java
similarity index 96%
rename from src/main/java/com/rymcu/vertical/util/SpringContextHolder.java
rename to src/main/java/com/rymcu/forest/util/SpringContextHolder.java
index b5dbf14..9e99cf3 100644
--- a/src/main/java/com/rymcu/vertical/util/SpringContextHolder.java
+++ b/src/main/java/com/rymcu/forest/util/SpringContextHolder.java
@@ -1,7 +1,7 @@
/**
* Copyright © 2012-2016 zkjkgc All rights reserved.
*/
-package com.rymcu.vertical.util;
+package com.rymcu.forest.util;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
@@ -13,10 +13,6 @@ import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.util.Date;
-
/**
* 以静态变量保存Spring ApplicationContext, 可在任何代码任何地方任何时候取出ApplicaitonContext.
*
diff --git a/src/main/java/com/rymcu/vertical/util/UserUtils.java b/src/main/java/com/rymcu/forest/util/UserUtils.java
similarity index 85%
rename from src/main/java/com/rymcu/vertical/util/UserUtils.java
rename to src/main/java/com/rymcu/forest/util/UserUtils.java
index 502b6b0..9441268 100644
--- a/src/main/java/com/rymcu/vertical/util/UserUtils.java
+++ b/src/main/java/com/rymcu/forest/util/UserUtils.java
@@ -1,13 +1,13 @@
-package com.rymcu.vertical.util;
+package com.rymcu.forest.util;
-import com.rymcu.vertical.dto.TokenUser;
-import com.rymcu.vertical.entity.User;
-import com.rymcu.vertical.jwt.def.JwtConstants;
-import com.rymcu.vertical.jwt.model.TokenModel;
-import com.rymcu.vertical.jwt.service.TokenManager;
-import com.rymcu.vertical.mapper.UserMapper;
-import com.rymcu.vertical.web.api.exception.ErrorCode;
-import com.rymcu.vertical.web.api.exception.BaseApiException;
+import com.rymcu.forest.dto.TokenUser;
+import com.rymcu.forest.entity.User;
+import com.rymcu.forest.jwt.def.JwtConstants;
+import com.rymcu.forest.jwt.model.TokenModel;
+import com.rymcu.forest.jwt.service.TokenManager;
+import com.rymcu.forest.mapper.UserMapper;
+import com.rymcu.forest.web.api.exception.ErrorCode;
+import com.rymcu.forest.web.api.exception.BaseApiException;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureException;
diff --git a/src/main/java/com/rymcu/vertical/util/Utils.java b/src/main/java/com/rymcu/forest/util/Utils.java
similarity index 96%
rename from src/main/java/com/rymcu/vertical/util/Utils.java
rename to src/main/java/com/rymcu/forest/util/Utils.java
index 7b55a2f..2cd80da 100644
--- a/src/main/java/com/rymcu/vertical/util/Utils.java
+++ b/src/main/java/com/rymcu/forest/util/Utils.java
@@ -1,10 +1,10 @@
-package com.rymcu.vertical.util;
+package com.rymcu.forest.util;
import com.github.pagehelper.PageInfo;
-import com.rymcu.vertical.dto.ArticleDTO;
-import com.rymcu.vertical.dto.NotificationDTO;
-import com.rymcu.vertical.entity.Notification;
-import com.rymcu.vertical.entity.User;
+import com.rymcu.forest.dto.ArticleDTO;
+import com.rymcu.forest.dto.NotificationDTO;
+import com.rymcu.forest.entity.Notification;
+import com.rymcu.forest.entity.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.InvalidSessionException;
import org.apache.shiro.session.Session;
diff --git a/src/main/java/com/rymcu/vertical/util/oConvertUtils.java b/src/main/java/com/rymcu/forest/util/oConvertUtils.java
similarity index 99%
rename from src/main/java/com/rymcu/vertical/util/oConvertUtils.java
rename to src/main/java/com/rymcu/forest/util/oConvertUtils.java
index 95ba686..782922b 100644
--- a/src/main/java/com/rymcu/vertical/util/oConvertUtils.java
+++ b/src/main/java/com/rymcu/forest/util/oConvertUtils.java
@@ -1,4 +1,4 @@
-package com.rymcu.vertical.util;
+package com.rymcu.forest.util;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
diff --git a/src/main/java/com/rymcu/vertical/web/api/admin/AdminController.java b/src/main/java/com/rymcu/forest/web/api/admin/AdminController.java
similarity index 96%
rename from src/main/java/com/rymcu/vertical/web/api/admin/AdminController.java
rename to src/main/java/com/rymcu/forest/web/api/admin/AdminController.java
index d2ca280..6dee51a 100644
--- a/src/main/java/com/rymcu/vertical/web/api/admin/AdminController.java
+++ b/src/main/java/com/rymcu/forest/web/api/admin/AdminController.java
@@ -1,14 +1,14 @@
-package com.rymcu.vertical.web.api.admin;
+package com.rymcu.forest.web.api.admin;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
-import com.rymcu.vertical.core.result.GlobalResult;
-import com.rymcu.vertical.core.result.GlobalResultGenerator;
-import com.rymcu.vertical.dto.admin.TopicTagDTO;
-import com.rymcu.vertical.dto.admin.UserRoleDTO;
-import com.rymcu.vertical.entity.*;
-import com.rymcu.vertical.service.*;
-import com.rymcu.vertical.util.Utils;
+import com.rymcu.forest.core.result.GlobalResult;
+import com.rymcu.forest.core.result.GlobalResultGenerator;
+import com.rymcu.forest.dto.admin.TopicTagDTO;
+import com.rymcu.forest.dto.admin.UserRoleDTO;
+import com.rymcu.forest.entity.*;
+import com.rymcu.forest.service.*;
+import com.rymcu.forest.util.Utils;
import org.apache.commons.lang.StringUtils;
import org.springframework.web.bind.annotation.*;
diff --git a/src/main/java/com/rymcu/vertical/web/api/admin/DashboardController.java b/src/main/java/com/rymcu/forest/web/api/admin/DashboardController.java
similarity index 79%
rename from src/main/java/com/rymcu/vertical/web/api/admin/DashboardController.java
rename to src/main/java/com/rymcu/forest/web/api/admin/DashboardController.java
index f039f0d..c1e797f 100644
--- a/src/main/java/com/rymcu/vertical/web/api/admin/DashboardController.java
+++ b/src/main/java/com/rymcu/forest/web/api/admin/DashboardController.java
@@ -1,9 +1,9 @@
-package com.rymcu.vertical.web.api.admin;
+package com.rymcu.forest.web.api.admin;
-import com.rymcu.vertical.core.result.GlobalResult;
-import com.rymcu.vertical.core.result.GlobalResultGenerator;
-import com.rymcu.vertical.dto.admin.Dashboard;
-import com.rymcu.vertical.service.DashboardService;
+import com.rymcu.forest.core.result.GlobalResult;
+import com.rymcu.forest.core.result.GlobalResultGenerator;
+import com.rymcu.forest.dto.admin.Dashboard;
+import com.rymcu.forest.service.DashboardService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
diff --git a/src/main/java/com/rymcu/vertical/web/api/article/ArticleController.java b/src/main/java/com/rymcu/forest/web/api/article/ArticleController.java
similarity index 86%
rename from src/main/java/com/rymcu/vertical/web/api/article/ArticleController.java
rename to src/main/java/com/rymcu/forest/web/api/article/ArticleController.java
index 1bf5b85..118bf38 100644
--- a/src/main/java/com/rymcu/vertical/web/api/article/ArticleController.java
+++ b/src/main/java/com/rymcu/forest/web/api/article/ArticleController.java
@@ -1,16 +1,16 @@
-package com.rymcu.vertical.web.api.article;
+package com.rymcu.forest.web.api.article;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
-import com.rymcu.vertical.core.result.GlobalResult;
-import com.rymcu.vertical.core.result.GlobalResultGenerator;
-import com.rymcu.vertical.dto.ArticleDTO;
-import com.rymcu.vertical.dto.CommentDTO;
-import com.rymcu.vertical.entity.Article;
-import com.rymcu.vertical.service.ArticleService;
-import com.rymcu.vertical.service.CommentService;
-import com.rymcu.vertical.util.Utils;
-import com.rymcu.vertical.web.api.exception.BaseApiException;
+import com.rymcu.forest.core.result.GlobalResult;
+import com.rymcu.forest.core.result.GlobalResultGenerator;
+import com.rymcu.forest.dto.ArticleDTO;
+import com.rymcu.forest.dto.CommentDTO;
+import com.rymcu.forest.entity.Article;
+import com.rymcu.forest.service.ArticleService;
+import com.rymcu.forest.service.CommentService;
+import com.rymcu.forest.util.Utils;
+import com.rymcu.forest.web.api.exception.BaseApiException;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
diff --git a/src/main/java/com/rymcu/vertical/web/api/comment/CommentController.java b/src/main/java/com/rymcu/forest/web/api/comment/CommentController.java
similarity index 73%
rename from src/main/java/com/rymcu/vertical/web/api/comment/CommentController.java
rename to src/main/java/com/rymcu/forest/web/api/comment/CommentController.java
index 07999fe..7ca1ed4 100644
--- a/src/main/java/com/rymcu/vertical/web/api/comment/CommentController.java
+++ b/src/main/java/com/rymcu/forest/web/api/comment/CommentController.java
@@ -1,10 +1,10 @@
-package com.rymcu.vertical.web.api.comment;
+package com.rymcu.forest.web.api.comment;
-import com.rymcu.vertical.core.result.GlobalResult;
-import com.rymcu.vertical.core.result.GlobalResultGenerator;
-import com.rymcu.vertical.entity.Comment;
-import com.rymcu.vertical.service.CommentService;
-import com.rymcu.vertical.web.api.exception.BaseApiException;
+import com.rymcu.forest.core.result.GlobalResult;
+import com.rymcu.forest.core.result.GlobalResultGenerator;
+import com.rymcu.forest.entity.Comment;
+import com.rymcu.forest.service.CommentService;
+import com.rymcu.forest.web.api.exception.BaseApiException;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
diff --git a/src/main/java/com/rymcu/vertical/web/api/common/CommonApiController.java b/src/main/java/com/rymcu/forest/web/api/common/CommonApiController.java
similarity index 86%
rename from src/main/java/com/rymcu/vertical/web/api/common/CommonApiController.java
rename to src/main/java/com/rymcu/forest/web/api/common/CommonApiController.java
index 34f4971..715f8de 100644
--- a/src/main/java/com/rymcu/vertical/web/api/common/CommonApiController.java
+++ b/src/main/java/com/rymcu/forest/web/api/common/CommonApiController.java
@@ -1,20 +1,19 @@
-package com.rymcu.vertical.web.api.common;
+package com.rymcu.forest.web.api.common;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
-import com.rymcu.vertical.core.result.GlobalResult;
-import com.rymcu.vertical.core.result.GlobalResultGenerator;
-import com.rymcu.vertical.core.result.GlobalResultMessage;
-import com.rymcu.vertical.core.service.log.annotation.VisitLogger;
-import com.rymcu.vertical.dto.*;
-import com.rymcu.vertical.entity.User;
-import com.rymcu.vertical.service.ArticleService;
-import com.rymcu.vertical.service.JavaMailService;
-import com.rymcu.vertical.service.PortfolioService;
-import com.rymcu.vertical.service.UserService;
-import com.rymcu.vertical.util.UserUtils;
-import com.rymcu.vertical.util.Utils;
-import io.swagger.annotations.ApiOperation;
+import com.rymcu.forest.core.result.GlobalResult;
+import com.rymcu.forest.core.result.GlobalResultGenerator;
+import com.rymcu.forest.core.result.GlobalResultMessage;
+import com.rymcu.forest.core.service.log.annotation.VisitLogger;
+import com.rymcu.forest.dto.*;
+import com.rymcu.forest.entity.User;
+import com.rymcu.forest.service.ArticleService;
+import com.rymcu.forest.service.JavaMailService;
+import com.rymcu.forest.service.PortfolioService;
+import com.rymcu.forest.service.UserService;
+import com.rymcu.forest.util.UserUtils;
+import com.rymcu.forest.util.Utils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@@ -39,7 +38,6 @@ public class CommonApiController {
@Resource
private PortfolioService portfolioService;
- @ApiOperation(value = "获取邮件验证码")
@GetMapping("/get-email-code")
public GlobalResult> getEmailCode(@RequestParam("email") String email) throws MessagingException {
Map map = new HashMap<>(1);
@@ -56,7 +54,6 @@ public class CommonApiController {
return GlobalResultGenerator.genSuccessResult(map);
}
- @ApiOperation(value = "获取找回密码邮件")
@GetMapping("/get-forget-password-email")
public GlobalResult> getForgetPasswordEmail(@RequestParam("email") String email) throws MessagingException {
Map map = new HashMap<>(1);
diff --git a/src/main/java/com/rymcu/forest/web/api/common/UploadController.java b/src/main/java/com/rymcu/forest/web/api/common/UploadController.java
new file mode 100644
index 0000000..44a2a14
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/web/api/common/UploadController.java
@@ -0,0 +1,250 @@
+package com.rymcu.forest.web.api.common;
+
+import com.rymcu.forest.core.result.GlobalResult;
+import com.rymcu.forest.core.result.GlobalResultGenerator;
+import com.rymcu.forest.dto.LinkToImageUrlDTO;
+import com.rymcu.forest.dto.TokenUser;
+import com.rymcu.forest.jwt.def.JwtConstants;
+import com.rymcu.forest.util.FileUtils;
+import com.rymcu.forest.util.SpringContextHolder;
+import com.rymcu.forest.util.UserUtils;
+import com.rymcu.forest.util.Utils;
+import com.rymcu.forest.web.api.exception.BaseApiException;
+import com.rymcu.forest.web.api.exception.ErrorCode;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.lang.StringUtils;
+import org.springframework.core.env.Environment;
+import org.springframework.util.FileCopyUtils;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.*;
+
+/**
+ * 文件上传控制器
+ *
+ * @author ronger
+ */
+@RestController
+@RequestMapping("/api/v1/upload")
+public class UploadController {
+
+ private final static String UPLOAD_SIMPLE_URL = "/api/upload/file";
+ private final static String UPLOAD_URL = "/api/upload/file/batch";
+ private final static String LINK_TO_IMAGE_URL = "/api/upload/file/link";
+
+ private static Environment env = SpringContextHolder.getBean(Environment.class);
+
+ @PostMapping("/file")
+ public GlobalResult uploadPicture(@RequestParam(value = "file", required = false) MultipartFile multipartFile, @RequestParam(defaultValue = "1") Integer type, HttpServletRequest request) {
+ if (multipartFile == null) {
+ return GlobalResultGenerator.genErrorResult("请选择要上传的文件");
+ }
+ String typePath = getTypePath(type);
+ //图片存储路径
+ String ctxHeadPicPath = env.getProperty("resource.pic-path");
+ String dir = ctxHeadPicPath + "/" + typePath;
+ File file = new File(dir);
+ if (!file.exists()) {
+ file.mkdirs();// 创建文件根目录
+ }
+
+ String localPath = Utils.getProperty("resource.file-path") + "/" + typePath + "/";
+
+ String orgName = multipartFile.getOriginalFilename();
+ String fileName = System.currentTimeMillis() + "." + FileUtils.getExtend(orgName).toLowerCase();
+
+ String savePath = file.getPath() + File.separator + fileName;
+
+ Map data = new HashMap(2);
+ File saveFile = new File(savePath);
+ try {
+ FileCopyUtils.copy(multipartFile.getBytes(), saveFile);
+ data.put("url", localPath + fileName);
+ } catch (IOException e) {
+ data.put("message", "上传失败!");
+ }
+ return GlobalResultGenerator.genSuccessResult(data);
+
+ }
+
+ @PostMapping("/file/batch")
+ public GlobalResult batchFileUpload(@RequestParam(value = "file[]", required = false) MultipartFile[] multipartFiles, @RequestParam(defaultValue = "1") Integer type, HttpServletRequest request) {
+ String typePath = getTypePath(type);
+ //图片存储路径
+ String ctxHeadPicPath = env.getProperty("resource.pic-path");
+ String dir = ctxHeadPicPath + "/" + typePath;
+ File file = new File(dir);
+ if (!file.exists()) {
+ file.mkdirs();// 创建文件根目录
+ }
+
+ String localPath = Utils.getProperty("resource.file-path") + "/" + typePath + "/";
+ Map succMap = new HashMap(10);
+ Set errFiles = new HashSet();
+
+ for (int i = 0, len = multipartFiles.length; i < len; i++) {
+ MultipartFile multipartFile = multipartFiles[i];
+ String orgName = multipartFile.getOriginalFilename();
+ String fileName = System.currentTimeMillis() + "." + FileUtils.getExtend(orgName).toLowerCase();
+
+ String savePath = file.getPath() + File.separator + fileName;
+
+ File saveFile = new File(savePath);
+ try {
+ FileCopyUtils.copy(multipartFile.getBytes(), saveFile);
+ succMap.put(orgName, localPath + fileName);
+ } catch (IOException e) {
+ errFiles.add(orgName);
+ }
+ }
+ Map data = new HashMap(2);
+ data.put("errFiles", errFiles);
+ data.put("succMap", succMap);
+ return GlobalResultGenerator.genSuccessResult(data);
+ }
+
+ private static String getTypePath(Integer type) {
+ String typePath;
+ switch (type) {
+ case 0:
+ typePath = "avatar";
+ break;
+ case 1:
+ typePath = "article";
+ break;
+ case 2:
+ typePath = "tags";
+ break;
+ default:
+ typePath = "images";
+ }
+ return typePath;
+ }
+
+ @GetMapping("/simple/token")
+ public GlobalResult uploadSimpleToken(HttpServletRequest request) throws BaseApiException {
+ String authHeader = request.getHeader(JwtConstants.AUTHORIZATION);
+ if (StringUtils.isBlank(authHeader)) {
+ throw new BaseApiException(ErrorCode.UNAUTHORIZED);
+ }
+ TokenUser tokenUser = UserUtils.getTokenUser(authHeader);
+ Map map = new HashMap(2);
+ map.put("uploadToken", tokenUser.getToken());
+ map.put("uploadURL", UPLOAD_SIMPLE_URL);
+ map.put("linkToImageURL", LINK_TO_IMAGE_URL);
+ return GlobalResultGenerator.genSuccessResult(map);
+ }
+
+ @GetMapping("/token")
+ public GlobalResult uploadToken(HttpServletRequest request) throws BaseApiException {
+ String authHeader = request.getHeader(JwtConstants.AUTHORIZATION);
+ if (StringUtils.isBlank(authHeader)) {
+ throw new BaseApiException(ErrorCode.UNAUTHORIZED);
+ }
+ TokenUser tokenUser = UserUtils.getTokenUser(authHeader);
+ Map map = new HashMap(2);
+ map.put("uploadToken", tokenUser.getToken());
+ map.put("uploadURL", UPLOAD_URL);
+ map.put("linkToImageURL", LINK_TO_IMAGE_URL);
+ return GlobalResultGenerator.genSuccessResult(map);
+ }
+
+ @PostMapping("/file/link")
+ public GlobalResult linkToImageUrl(@RequestBody LinkToImageUrlDTO linkToImageUrlDTO) throws IOException {
+ String url = linkToImageUrlDTO.getUrl();
+ URL link = new URL(url);
+ HttpURLConnection conn = (HttpURLConnection)link.openConnection();
+ //设置超时间为3秒
+ conn.setConnectTimeout(3*1000);
+ //防止屏蔽程序抓取而返回403错误
+ conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36");
+ conn.setRequestProperty("referer", "");
+
+ //得到输入流
+ InputStream inputStream = conn.getInputStream();
+ //获取自己数组
+ byte[] getData = readInputStream(inputStream);
+ Integer type = linkToImageUrlDTO.getType();
+ if (Objects.isNull(type)) {
+ type = 1;
+ }
+ String typePath = getTypePath(type);
+ //图片存储路径
+ String ctxHeadPicPath = env.getProperty("resource.pic-path");
+ String dir = ctxHeadPicPath + "/" + typePath;
+ File file = new File(dir);
+ if (!file.exists()) {
+ file.mkdirs();// 创建文件根目录
+ }
+
+ String localPath = Utils.getProperty("resource.file-path") + "/" + typePath + "/";
+
+ String orgName = url.substring(url.lastIndexOf("."));
+ String fileName = System.currentTimeMillis() + FileUtils.getExtend(orgName).toLowerCase();
+
+ String savePath = file.getPath() + File.separator + fileName;
+
+ Map data = new HashMap(2);
+ File saveFile = new File(savePath);
+ try {
+ FileCopyUtils.copy(getData, saveFile);
+ data.put("originalURL", url);
+ data.put("url", localPath + fileName);
+ } catch (IOException e) {
+ data.put("message", "上传失败!");
+ }
+ return GlobalResultGenerator.genSuccessResult(data);
+
+ }
+
+ public static String uploadBase64File(String fileStr, Integer type) {
+ if (StringUtils.isBlank(fileStr)) {
+ return "";
+ }
+ String typePath = getTypePath(type);
+ //图片存储路径
+ String ctxHeadPicPath = env.getProperty("resource.pic-path");
+ String dir = ctxHeadPicPath + "/" + typePath;
+ File file = new File(dir);
+ if (!file.exists()) {
+ file.mkdirs();// 创建文件根目录
+ }
+
+ String localPath = Utils.getProperty("resource.file-path") + "/" + typePath + "/";
+ String fileName = System.currentTimeMillis() + ".png";
+ String savePath = file.getPath() + File.separator + fileName;
+ File saveFile = new File(savePath);
+ try {
+ FileCopyUtils.copy(Base64.decodeBase64(fileStr.substring(fileStr.indexOf(",") + 1)), saveFile);
+ fileStr = localPath + fileName;
+ } catch (IOException e) {
+ fileStr = "上传失败!";
+ }
+ return fileStr;
+ }
+
+ /**
+ * 从输入流中获取字节数组
+ * @param inputStream
+ * @return
+ * @throws IOException
+ */
+ public static byte[] readInputStream(InputStream inputStream) throws IOException {
+ byte[] buffer = new byte[1024];
+ int len = 0;
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ while((len = inputStream.read(buffer)) != -1) {
+ bos.write(buffer, 0, len);
+ }
+ bos.close();
+ return bos.toByteArray();
+ }
+}
diff --git a/src/main/java/com/rymcu/vertical/web/api/common/WebSocketController.java b/src/main/java/com/rymcu/forest/web/api/common/WebSocketController.java
similarity index 94%
rename from src/main/java/com/rymcu/vertical/web/api/common/WebSocketController.java
rename to src/main/java/com/rymcu/forest/web/api/common/WebSocketController.java
index 5df9660..62f5e26 100644
--- a/src/main/java/com/rymcu/vertical/web/api/common/WebSocketController.java
+++ b/src/main/java/com/rymcu/forest/web/api/common/WebSocketController.java
@@ -1,8 +1,7 @@
-package com.rymcu.vertical.web.api.common;
+package com.rymcu.forest.web.api.common;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.messaging.handler.annotation.DestinationVariable;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessagingTemplate;
diff --git a/src/main/java/com/rymcu/vertical/web/api/exception/BaseApiException.java b/src/main/java/com/rymcu/forest/web/api/exception/BaseApiException.java
similarity index 92%
rename from src/main/java/com/rymcu/vertical/web/api/exception/BaseApiException.java
rename to src/main/java/com/rymcu/forest/web/api/exception/BaseApiException.java
index 9611c42..5140c70 100644
--- a/src/main/java/com/rymcu/vertical/web/api/exception/BaseApiException.java
+++ b/src/main/java/com/rymcu/forest/web/api/exception/BaseApiException.java
@@ -1,4 +1,4 @@
-package com.rymcu.vertical.web.api.exception;
+package com.rymcu.forest.web.api.exception;
/**
* 服务(业务)异常如“ 账号或密码错误 ”,该异常只做INFO级别的日志记录 @see WebMvcConfigurer
diff --git a/src/main/java/com/rymcu/vertical/web/api/exception/BaseApiExceptionHandler.java b/src/main/java/com/rymcu/forest/web/api/exception/BaseApiExceptionHandler.java
similarity index 83%
rename from src/main/java/com/rymcu/vertical/web/api/exception/BaseApiExceptionHandler.java
rename to src/main/java/com/rymcu/forest/web/api/exception/BaseApiExceptionHandler.java
index 7a6a34f..4291bda 100644
--- a/src/main/java/com/rymcu/vertical/web/api/exception/BaseApiExceptionHandler.java
+++ b/src/main/java/com/rymcu/forest/web/api/exception/BaseApiExceptionHandler.java
@@ -1,7 +1,7 @@
-package com.rymcu.vertical.web.api.exception;
+package com.rymcu.forest.web.api.exception;
-import com.rymcu.vertical.config.BaseExceptionHandler;
-import com.rymcu.vertical.core.result.GlobalResult;
+import com.rymcu.forest.config.BaseExceptionHandler;
+import com.rymcu.forest.core.result.GlobalResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
@@ -11,7 +11,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-@ControllerAdvice(basePackages = {"com.rymcu.vertical.web.api", "com.rymcu.vertical.jwt"} )
+@ControllerAdvice(basePackages = {"com.rymcu.forest.web.api", "com.rymcu.forest.jwt"} )
public class BaseApiExceptionHandler {
private final Logger logger = LoggerFactory.getLogger(BaseExceptionHandler.class);
diff --git a/src/main/java/com/rymcu/vertical/web/api/exception/ErrorCode.java b/src/main/java/com/rymcu/forest/web/api/exception/ErrorCode.java
similarity index 93%
rename from src/main/java/com/rymcu/vertical/web/api/exception/ErrorCode.java
rename to src/main/java/com/rymcu/forest/web/api/exception/ErrorCode.java
index ebea4c3..45964a1 100644
--- a/src/main/java/com/rymcu/vertical/web/api/exception/ErrorCode.java
+++ b/src/main/java/com/rymcu/forest/web/api/exception/ErrorCode.java
@@ -1,4 +1,4 @@
-package com.rymcu.vertical.web.api.exception;
+package com.rymcu.forest.web.api.exception;
public enum ErrorCode {
diff --git a/src/main/java/com/rymcu/forest/web/api/follow/FollowController.java b/src/main/java/com/rymcu/forest/web/api/follow/FollowController.java
new file mode 100644
index 0000000..673144a
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/web/api/follow/FollowController.java
@@ -0,0 +1,41 @@
+package com.rymcu.forest.web.api.follow;
+
+import com.rymcu.forest.core.result.GlobalResult;
+import com.rymcu.forest.core.result.GlobalResultGenerator;
+import com.rymcu.forest.entity.Follow;
+import com.rymcu.forest.service.FollowService;
+import com.rymcu.forest.web.api.exception.BaseApiException;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+
+/**
+ * @author ronger
+ */
+@RestController
+@RequestMapping("/api/v1/follow")
+public class FollowController {
+
+ @Resource
+ private FollowService followService;
+
+ @GetMapping("/is-follow")
+ public GlobalResult isFollow(@RequestParam Integer followingId, @RequestParam String followingType) throws BaseApiException {
+ Boolean b = followService.isFollow(followingId, followingType);
+ return GlobalResultGenerator.genSuccessResult(b);
+ }
+
+ @PostMapping
+ public GlobalResult follow(@RequestBody Follow follow) throws BaseApiException {
+ Boolean b = followService.follow(follow);
+ return GlobalResultGenerator.genSuccessResult(b);
+ }
+
+ @PostMapping("cancel-follow")
+ public GlobalResult cancelFollow(@RequestBody Follow follow) throws BaseApiException {
+ Boolean b = followService.cancelFollow(follow);
+ return GlobalResultGenerator.genSuccessResult(b);
+ }
+
+
+}
diff --git a/src/main/java/com/rymcu/vertical/web/api/notification/NotificationController.java b/src/main/java/com/rymcu/forest/web/api/notification/NotificationController.java
similarity index 79%
rename from src/main/java/com/rymcu/vertical/web/api/notification/NotificationController.java
rename to src/main/java/com/rymcu/forest/web/api/notification/NotificationController.java
index 7f8085e..e4509f1 100644
--- a/src/main/java/com/rymcu/vertical/web/api/notification/NotificationController.java
+++ b/src/main/java/com/rymcu/forest/web/api/notification/NotificationController.java
@@ -1,16 +1,16 @@
-package com.rymcu.vertical.web.api.notification;
+package com.rymcu.forest.web.api.notification;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
-import com.rymcu.vertical.core.result.GlobalResult;
-import com.rymcu.vertical.core.result.GlobalResultGenerator;
-import com.rymcu.vertical.dto.NotificationDTO;
-import com.rymcu.vertical.entity.Notification;
-import com.rymcu.vertical.entity.User;
-import com.rymcu.vertical.service.NotificationService;
-import com.rymcu.vertical.util.UserUtils;
-import com.rymcu.vertical.util.Utils;
-import com.rymcu.vertical.web.api.exception.BaseApiException;
+import com.rymcu.forest.core.result.GlobalResult;
+import com.rymcu.forest.core.result.GlobalResultGenerator;
+import com.rymcu.forest.dto.NotificationDTO;
+import com.rymcu.forest.entity.Notification;
+import com.rymcu.forest.entity.User;
+import com.rymcu.forest.service.NotificationService;
+import com.rymcu.forest.util.UserUtils;
+import com.rymcu.forest.util.Utils;
+import com.rymcu.forest.web.api.exception.BaseApiException;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
diff --git a/src/main/java/com/rymcu/vertical/web/api/portfolio/PortfolioController.java b/src/main/java/com/rymcu/forest/web/api/portfolio/PortfolioController.java
similarity index 86%
rename from src/main/java/com/rymcu/vertical/web/api/portfolio/PortfolioController.java
rename to src/main/java/com/rymcu/forest/web/api/portfolio/PortfolioController.java
index 4a4b0a2..66251cb 100644
--- a/src/main/java/com/rymcu/vertical/web/api/portfolio/PortfolioController.java
+++ b/src/main/java/com/rymcu/forest/web/api/portfolio/PortfolioController.java
@@ -1,12 +1,12 @@
-package com.rymcu.vertical.web.api.portfolio;
+package com.rymcu.forest.web.api.portfolio;
-import com.rymcu.vertical.core.result.GlobalResult;
-import com.rymcu.vertical.core.result.GlobalResultGenerator;
-import com.rymcu.vertical.dto.PortfolioArticleDTO;
-import com.rymcu.vertical.dto.PortfolioDTO;
-import com.rymcu.vertical.entity.Portfolio;
-import com.rymcu.vertical.service.PortfolioService;
-import com.rymcu.vertical.web.api.exception.BaseApiException;
+import com.rymcu.forest.core.result.GlobalResult;
+import com.rymcu.forest.core.result.GlobalResultGenerator;
+import com.rymcu.forest.dto.PortfolioArticleDTO;
+import com.rymcu.forest.dto.PortfolioDTO;
+import com.rymcu.forest.entity.Portfolio;
+import com.rymcu.forest.service.PortfolioService;
+import com.rymcu.forest.web.api.exception.BaseApiException;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
diff --git a/src/main/java/com/rymcu/vertical/web/api/tag/TagController.java b/src/main/java/com/rymcu/forest/web/api/tag/TagController.java
similarity index 74%
rename from src/main/java/com/rymcu/vertical/web/api/tag/TagController.java
rename to src/main/java/com/rymcu/forest/web/api/tag/TagController.java
index aa185a9..dda3353 100644
--- a/src/main/java/com/rymcu/vertical/web/api/tag/TagController.java
+++ b/src/main/java/com/rymcu/forest/web/api/tag/TagController.java
@@ -1,14 +1,14 @@
-package com.rymcu.vertical.web.api.tag;
+package com.rymcu.forest.web.api.tag;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
-import com.rymcu.vertical.core.result.GlobalResult;
-import com.rymcu.vertical.core.result.GlobalResultGenerator;
-import com.rymcu.vertical.dto.ArticleDTO;
-import com.rymcu.vertical.dto.LabelModel;
-import com.rymcu.vertical.service.ArticleService;
-import com.rymcu.vertical.service.TagService;
-import com.rymcu.vertical.util.Utils;
+import com.rymcu.forest.core.result.GlobalResult;
+import com.rymcu.forest.core.result.GlobalResultGenerator;
+import com.rymcu.forest.dto.ArticleDTO;
+import com.rymcu.forest.dto.LabelModel;
+import com.rymcu.forest.service.ArticleService;
+import com.rymcu.forest.service.TagService;
+import com.rymcu.forest.util.Utils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
diff --git a/src/main/java/com/rymcu/vertical/web/api/topic/TopicController.java b/src/main/java/com/rymcu/forest/web/api/topic/TopicController.java
similarity index 71%
rename from src/main/java/com/rymcu/vertical/web/api/topic/TopicController.java
rename to src/main/java/com/rymcu/forest/web/api/topic/TopicController.java
index beed345..56d55f0 100644
--- a/src/main/java/com/rymcu/vertical/web/api/topic/TopicController.java
+++ b/src/main/java/com/rymcu/forest/web/api/topic/TopicController.java
@@ -1,15 +1,15 @@
-package com.rymcu.vertical.web.api.topic;
+package com.rymcu.forest.web.api.topic;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
-import com.rymcu.vertical.core.result.GlobalResult;
-import com.rymcu.vertical.core.result.GlobalResultGenerator;
-import com.rymcu.vertical.core.service.log.annotation.VisitLogger;
-import com.rymcu.vertical.dto.ArticleDTO;
-import com.rymcu.vertical.entity.Topic;
-import com.rymcu.vertical.service.ArticleService;
-import com.rymcu.vertical.service.TopicService;
-import com.rymcu.vertical.util.Utils;
+import com.rymcu.forest.core.result.GlobalResult;
+import com.rymcu.forest.core.result.GlobalResultGenerator;
+import com.rymcu.forest.core.service.log.annotation.VisitLogger;
+import com.rymcu.forest.dto.ArticleDTO;
+import com.rymcu.forest.entity.Topic;
+import com.rymcu.forest.service.ArticleService;
+import com.rymcu.forest.service.TopicService;
+import com.rymcu.forest.util.Utils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
diff --git a/src/main/java/com/rymcu/forest/web/api/user/UserController.java b/src/main/java/com/rymcu/forest/web/api/user/UserController.java
new file mode 100644
index 0000000..f7e154e
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/web/api/user/UserController.java
@@ -0,0 +1,114 @@
+package com.rymcu.forest.web.api.user;
+
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import com.rymcu.forest.core.result.GlobalResult;
+import com.rymcu.forest.core.result.GlobalResultGenerator;
+import com.rymcu.forest.core.service.log.annotation.VisitLogger;
+import com.rymcu.forest.dto.ArticleDTO;
+import com.rymcu.forest.dto.PortfolioDTO;
+import com.rymcu.forest.dto.UserDTO;
+import com.rymcu.forest.entity.UserExtend;
+import com.rymcu.forest.service.ArticleService;
+import com.rymcu.forest.service.FollowService;
+import com.rymcu.forest.service.PortfolioService;
+import com.rymcu.forest.service.UserService;
+import com.rymcu.forest.util.Utils;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author ronger
+ */
+@RestController
+@RequestMapping("/api/v1/user")
+public class UserController {
+
+ @Resource
+ private UserService userService;
+ @Resource
+ private ArticleService articleService;
+ @Resource
+ private PortfolioService portfolioService;
+ @Resource
+ private FollowService followService;
+
+ @GetMapping("/{nickname}")
+ @VisitLogger
+ public GlobalResult detail(@PathVariable String nickname){
+ UserDTO userDTO = userService.findUserDTOByNickname(nickname);
+ return GlobalResultGenerator.genSuccessResult(userDTO);
+ }
+
+ @GetMapping("/{nickname}/articles")
+ public GlobalResult userArticles(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "12") Integer rows, @PathVariable String nickname){
+ UserDTO userDTO = userService.findUserDTOByNickname(nickname);
+ if (userDTO == null){
+ return GlobalResultGenerator.genErrorResult("用户不存在!");
+ }
+ PageHelper.startPage(page, rows);
+ List list = articleService.findUserArticlesByIdUser(userDTO.getIdUser());
+ PageInfo pageInfo = new PageInfo(list);
+ Map map = Utils.getArticlesGlobalResult(pageInfo);
+ return GlobalResultGenerator.genSuccessResult(map);
+ }
+
+ @GetMapping("/{nickname}/portfolios")
+ public GlobalResult userPortfolios(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "12") Integer rows, @PathVariable String nickname){
+ UserDTO userDTO = userService.findUserDTOByNickname(nickname);
+ if (userDTO == null){
+ return GlobalResultGenerator.genErrorResult("用户不存在!");
+ }
+ PageHelper.startPage(page, rows);
+ List list = portfolioService.findUserPortfoliosByUser(userDTO);
+ PageInfo pageInfo = new PageInfo(list);
+ Map map = new HashMap(2);
+ map.put("portfolios", list);
+ Map pagination = Utils.getPagination(pageInfo);
+ map.put("pagination", pagination);
+ return GlobalResultGenerator.genSuccessResult(map);
+ }
+
+ @GetMapping("/{nickname}/followers")
+ public GlobalResult userFollowers(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "12") Integer rows, @PathVariable String nickname){
+ UserDTO userDTO = userService.findUserDTOByNickname(nickname);
+ if (userDTO == null){
+ return GlobalResultGenerator.genErrorResult("用户不存在!");
+ }
+ PageHelper.startPage(page, rows);
+ List list = followService.findUserFollowersByUser(userDTO);
+ PageInfo pageInfo = new PageInfo(list);
+ Map map = new HashMap(2);
+ map.put("users", list);
+ Map pagination = Utils.getPagination(pageInfo);
+ map.put("pagination", pagination);
+ return GlobalResultGenerator.genSuccessResult(map);
+ }
+
+ @GetMapping("/{nickname}/followings")
+ public GlobalResult userFollowings(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "12") Integer rows, @PathVariable String nickname){
+ UserDTO userDTO = userService.findUserDTOByNickname(nickname);
+ if (userDTO == null){
+ return GlobalResultGenerator.genErrorResult("用户不存在!");
+ }
+ PageHelper.startPage(page, rows);
+ List list = followService.findUserFollowingsByUser(userDTO);
+ PageInfo pageInfo = new PageInfo(list);
+ Map map = new HashMap(2);
+ map.put("users", list);
+ Map pagination = Utils.getPagination(pageInfo);
+ map.put("pagination", pagination);
+ return GlobalResultGenerator.genSuccessResult(map);
+ }
+
+ @GetMapping("/{nickname}/user-extend")
+ public GlobalResult userExtend(@PathVariable String nickname) {
+ UserExtend userExtend = userService.selectUserExtendByNickname(nickname);
+ return GlobalResultGenerator.genSuccessResult(userExtend);
+ }
+
+}
diff --git a/src/main/java/com/rymcu/forest/web/api/user/UserInfoController.java b/src/main/java/com/rymcu/forest/web/api/user/UserInfoController.java
new file mode 100644
index 0000000..4b74209
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/web/api/user/UserInfoController.java
@@ -0,0 +1,59 @@
+package com.rymcu.forest.web.api.user;
+
+import com.rymcu.forest.core.result.GlobalResult;
+import com.rymcu.forest.core.result.GlobalResultGenerator;
+import com.rymcu.forest.dto.*;
+import com.rymcu.forest.entity.UserExtend;
+import com.rymcu.forest.service.UserService;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.util.Map;
+
+/**
+ * @author ronger
+ */
+@RestController
+@RequestMapping("/api/v1/user-info")
+public class UserInfoController {
+
+ @Resource
+ private UserService userService;
+
+ @GetMapping("/detail/{idUser}")
+ public GlobalResult detail(@PathVariable Integer idUser) {
+ Map map = userService.findUserInfo(idUser);
+ return GlobalResultGenerator.genSuccessResult(map);
+ }
+
+ @GetMapping("/check-nickname")
+ public GlobalResult checkNickname(@RequestParam Integer idUser, @RequestParam String nickname) {
+ Map map = userService.checkNickname(idUser,nickname);
+ return GlobalResultGenerator.genSuccessResult(map);
+ }
+
+ @PatchMapping("/update")
+ public GlobalResult updateUserInfo(@RequestBody UserInfoDTO user) {
+ Map map = userService.updateUserInfo(user);
+ return GlobalResultGenerator.genSuccessResult(map);
+ }
+
+ @PatchMapping("/update-extend")
+ public GlobalResult updateUserExtend(@RequestBody UserExtend userExtend) {
+ Map map = userService.updateUserExtend(userExtend);
+ return GlobalResultGenerator.genSuccessResult(map);
+ }
+
+ @PatchMapping("/update-email")
+ public GlobalResult updateEmail(@RequestBody ChangeEmailDTO changeEmailDTO) {
+ Map map = userService.updateEmail(changeEmailDTO);
+ return GlobalResultGenerator.genSuccessResult(map);
+ }
+
+ @PatchMapping("/update-password")
+ public GlobalResult updatePassword(@RequestBody UpdatePasswordDTO updatePasswordDTO) {
+ Map map = userService.updatePassword(updatePasswordDTO);
+ return GlobalResultGenerator.genSuccessResult(map);
+ }
+
+}
diff --git a/src/main/java/com/rymcu/forest/wx/miniapp/config/WxMaConfiguration.java b/src/main/java/com/rymcu/forest/wx/miniapp/config/WxMaConfiguration.java
new file mode 100644
index 0000000..73f28e6
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/miniapp/config/WxMaConfiguration.java
@@ -0,0 +1,149 @@
+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 Binary Wang
+ */
+@Slf4j
+@Configuration
+@EnableConfigurationProperties(WxMaProperties.class)
+public class WxMaConfiguration {
+ private final WxMaProperties properties;
+
+ private static final Map routers = Maps.newHashMap();
+ private static Map 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 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.Data("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;
+ };
+
+}
diff --git a/src/main/java/com/rymcu/forest/wx/miniapp/config/WxMaProperties.java b/src/main/java/com/rymcu/forest/wx/miniapp/config/WxMaProperties.java
new file mode 100644
index 0000000..f91fbff
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/miniapp/config/WxMaProperties.java
@@ -0,0 +1,45 @@
+package com.rymcu.forest.wx.miniapp.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import java.util.List;
+
+/**
+ * @author Binary Wang
+ */
+@Data
+@ConfigurationProperties(prefix = "wx.miniapp")
+public class WxMaProperties {
+
+ private List 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;
+ }
+
+}
diff --git a/src/main/java/com/rymcu/forest/wx/miniapp/controller/WxMaMediaController.java b/src/main/java/com/rymcu/forest/wx/miniapp/controller/WxMaMediaController.java
new file mode 100644
index 0000000..3fae69c
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/miniapp/controller/WxMaMediaController.java
@@ -0,0 +1,80 @@
+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;
+
+/**
+ *
+ * 小程序临时素材接口
+ * Created by BinaryWang on 2017/6/16.
+ *
+ *
+ * @author Binary Wang
+ */
+@RestController
+@RequestMapping("/wx/media/{appId}")
+public class WxMaMediaController {
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ /**
+ * 上传临时素材
+ *
+ * @return 素材的media_id列表,实际上如果有的话,只会有一个
+ */
+ @PostMapping("/upload")
+ public List 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 it = multiRequest.getFileNames();
+ List 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);
+ }
+}
diff --git a/src/main/java/com/rymcu/forest/wx/miniapp/controller/WxMaUserController.java b/src/main/java/com/rymcu/forest/wx/miniapp/controller/WxMaUserController.java
new file mode 100644
index 0000000..e628940
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/miniapp/controller/WxMaUserController.java
@@ -0,0 +1,93 @@
+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 Binary Wang
+ */
+@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();
+ }
+ }
+
+ /**
+ *
+ * 获取用户信息接口
+ *
+ */
+ @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);
+ }
+
+ /**
+ *
+ * 获取用户绑定手机号信息
+ *
+ */
+ @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);
+ }
+
+}
diff --git a/src/main/java/com/rymcu/forest/wx/miniapp/utils/JsonUtils.java b/src/main/java/com/rymcu/forest/wx/miniapp/utils/JsonUtils.java
new file mode 100644
index 0000000..3687ab9
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/miniapp/utils/JsonUtils.java
@@ -0,0 +1,28 @@
+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 Binary Wang
+ */
+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;
+ }
+}
diff --git a/src/main/java/com/rymcu/forest/wx/mp/builder/AbstractBuilder.java b/src/main/java/com/rymcu/forest/wx/mp/builder/AbstractBuilder.java
new file mode 100644
index 0000000..0a0dc86
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/mp/builder/AbstractBuilder.java
@@ -0,0 +1,17 @@
+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);
+}
diff --git a/src/main/java/com/rymcu/forest/wx/mp/builder/ImageBuilder.java b/src/main/java/com/rymcu/forest/wx/mp/builder/ImageBuilder.java
new file mode 100644
index 0000000..7c12ec2
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/mp/builder/ImageBuilder.java
@@ -0,0 +1,24 @@
+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;
+ }
+
+}
diff --git a/src/main/java/com/rymcu/forest/wx/mp/builder/TextBuilder.java b/src/main/java/com/rymcu/forest/wx/mp/builder/TextBuilder.java
new file mode 100644
index 0000000..097d402
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/mp/builder/TextBuilder.java
@@ -0,0 +1,22 @@
+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;
+ }
+
+}
diff --git a/src/main/java/com/rymcu/forest/wx/mp/config/WxMpConfiguration.java b/src/main/java/com/rymcu/forest/wx/mp/config/WxMpConfiguration.java
new file mode 100644
index 0000000..694b0f2
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/mp/config/WxMpConfiguration.java
@@ -0,0 +1,111 @@
+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 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;
+ }
+
+}
diff --git a/src/main/java/com/rymcu/forest/wx/mp/config/WxMpProperties.java b/src/main/java/com/rymcu/forest/wx/mp/config/WxMpProperties.java
new file mode 100644
index 0000000..234e0c6
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/mp/config/WxMpProperties.java
@@ -0,0 +1,46 @@
+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 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);
+ }
+}
diff --git a/src/main/java/com/rymcu/forest/wx/mp/controller/WxMenuController.java b/src/main/java/com/rymcu/forest/wx/mp/controller/WxMenuController.java
new file mode 100644
index 0000000..09668aa
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/mp/controller/WxMenuController.java
@@ -0,0 +1,171 @@
+package com.rymcu.forest.wx.mp.controller;
+
+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.web.bind.annotation.*;
+
+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;
+
+ /**
+ *
+ * 自定义菜单创建接口
+ * 详情请见: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
+ *
+ *
+ * @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, MalformedURLException {
+ WxMenu menu = new WxMenu();
+ WxMenuButton button1 = new WxMenuButton();
+ button1.setType(MenuButtonType.VIEW);
+ button1.setName("官方网站");
+ button1.setUrl("https://rymcu.com");
+
+// WxMenuButton button2 = new WxMenuButton();
+// button2.setType(WxConsts.BUTTON_MINIPROGRAM);
+// button2.setName("小程序");
+// button2.setAppId("wx286b93c14bbf93aa");
+// button2.setPagePath("pages/lunar/index.html");
+// button2.setUrl("http://mp.weixin.qq.com");
+
+ WxMenuButton button3 = new WxMenuButton();
+ button3.setName("学习教程");
+
+ menu.getButtons().add(button1);
+// menu.getButtons().add(button2);
+ menu.getButtons().add(button3);
+
+ WxMenuButton button31 = new WxMenuButton();
+ button31.setType(MenuButtonType.VIEW);
+ button31.setName("51单片机入门教程");
+ button31.setUrl("https://mp.weixin.qq.com/mp/homepage?__biz=MzA3NjMzMzM1Mw==&hid=1&sn=672df75323f9976d990f6be14355070b");
+
+// WxMenuButton button34 = new WxMenuButton();
+// button34.setType(MenuButtonType.VIEW);
+// button34.setName("获取用户信息");
+//
+// ServletRequestAttributes servletRequestAttributes =
+// (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+// if (servletRequestAttributes != null) {
+// HttpServletRequest request = servletRequestAttributes.getRequest();
+// URL requestURL = new URL(request.getRequestURL().toString());
+// String url = this.wxService.switchoverTo(appId).oauth2buildAuthorizationUrl(
+// String.format("%s://%s/wx/redirect/%s/greet", requestURL.getProtocol(), requestURL.getHost(), appId),
+// WxConsts.OAuth2Scope.SNSAPI_USERINFO, null);
+// button34.setUrl(url);
+// }
+
+ button3.getSubButtons().add(button31);
+// button3.getSubButtons().add(button34);
+
+ this.wxService.switchover(appId);
+ return this.wxService.getMenuService().menuCreate(menu);
+ }
+
+ /**
+ *
+ * 自定义菜单创建接口
+ * 详情请见: 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
+ *
+ *
+ * @return 如果是个性化菜单,则返回menuid,否则返回null
+ */
+ @PostMapping("/createByJson")
+ public String menuCreate(@PathVariable String appId, @RequestBody String json) throws WxErrorException {
+ return this.wxService.switchoverTo(appId).getMenuService().menuCreate(json);
+ }
+
+ /**
+ *
+ * 自定义菜单删除接口
+ * 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141015&token=&lang=zh_CN
+ *
+ */
+ @GetMapping("/delete")
+ public void menuDelete(@PathVariable String appId) throws WxErrorException {
+ this.wxService.switchoverTo(appId).getMenuService().menuDelete();
+ }
+
+ /**
+ *
+ * 删除个性化菜单接口
+ * 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN
+ *
+ *
+ * @param menuId 个性化菜单的menuid
+ */
+ @GetMapping("/delete/{menuId}")
+ public void menuDelete(@PathVariable String appId, @PathVariable String menuId) throws WxErrorException {
+ this.wxService.switchoverTo(appId).getMenuService().menuDelete(menuId);
+ }
+
+ /**
+ *
+ * 自定义菜单查询接口
+ * 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141014&token=&lang=zh_CN
+ *
+ */
+ @GetMapping("/get")
+ public WxMpMenu menuGet(@PathVariable String appId) throws WxErrorException {
+ return this.wxService.switchoverTo(appId).getMenuService().menuGet();
+ }
+
+ /**
+ *
+ * 测试个性化菜单匹配结果
+ * 详情请见: http://mp.weixin.qq.com/wiki/0/c48ccd12b69ae023159b4bfaa7c39c20.html
+ *
+ *
+ * @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);
+ }
+
+ /**
+ *
+ * 获取自定义菜单配置接口
+ * 本接口将会提供公众号当前使用的自定义菜单的配置,如果公众号是通过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
+ *
+ */
+ @GetMapping("/getSelfMenuInfo")
+ public WxMpGetSelfMenuInfoResult getSelfMenuInfo(@PathVariable String appId) throws WxErrorException {
+ return this.wxService.switchoverTo(appId).getMenuService().getSelfMenuInfo();
+ }
+}
diff --git a/src/main/java/com/rymcu/forest/wx/mp/controller/WxPortalController.java b/src/main/java/com/rymcu/forest/wx/mp/controller/WxPortalController.java
new file mode 100644
index 0000000..c3fc4ae
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/mp/controller/WxPortalController.java
@@ -0,0 +1,112 @@
+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;
+ }
+
+}
diff --git a/src/main/java/com/rymcu/forest/wx/mp/controller/WxRedirectController.java b/src/main/java/com/rymcu/forest/wx/mp/controller/WxRedirectController.java
new file mode 100644
index 0000000..0395f65
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/mp/controller/WxRedirectController.java
@@ -0,0 +1,39 @@
+package com.rymcu.forest.wx.mp.controller;
+
+import lombok.AllArgsConstructor;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
+import me.chanjar.weixin.mp.bean.result.WxMpUser;
+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 {
+ WxMpOAuth2AccessToken accessToken = wxService.getOAuth2Service().getAccessToken(code);
+ WxMpUser user = wxService.getOAuth2Service().getUserInfo(accessToken, null);
+ map.put("user", user);
+ } catch (WxErrorException e) {
+ e.printStackTrace();
+ }
+
+ return "greet_user";
+ }
+}
diff --git a/src/main/java/com/rymcu/forest/wx/mp/controller/WxoAuthController.java b/src/main/java/com/rymcu/forest/wx/mp/controller/WxoAuthController.java
new file mode 100644
index 0000000..d302914
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/mp/controller/WxoAuthController.java
@@ -0,0 +1,77 @@
+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.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.URIUtil;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
+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_BASE, 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);
+ WxMpOAuth2AccessToken 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";
+ }
+}
diff --git a/src/main/java/com/rymcu/forest/wx/mp/error/ErrorController.java b/src/main/java/com/rymcu/forest/wx/mp/error/ErrorController.java
new file mode 100644
index 0000000..e345a88
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/mp/error/ErrorController.java
@@ -0,0 +1,29 @@
+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;
+
+/**
+ *
+ * 出错页面控制器
+ * Created by Binary Wang on 2018/8/25.
+ *
+ *
+ * @author Binary Wang
+ */
+@Controller
+@RequestMapping("/error")
+public class ErrorController {
+
+ @GetMapping(value = "/404")
+ public String error404() {
+ return "error";
+ }
+
+ @GetMapping(value = "/500")
+ public String error500() {
+ return "error";
+ }
+
+}
diff --git a/src/main/java/com/rymcu/forest/wx/mp/error/ErrorPageConfiguration.java b/src/main/java/com/rymcu/forest/wx/mp/error/ErrorPageConfiguration.java
new file mode 100644
index 0000000..39dec24
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/mp/error/ErrorPageConfiguration.java
@@ -0,0 +1,27 @@
+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;
+
+/**
+ *
+ * 配置错误状态与对应访问路径
+ * Created by Binary Wang on 2018/8/25.
+ *
+ *
+ * @author Binary Wang
+ */
+@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")
+ );
+ }
+
+}
diff --git a/src/main/java/com/rymcu/forest/wx/mp/handler/AbstractHandler.java b/src/main/java/com/rymcu/forest/wx/mp/handler/AbstractHandler.java
new file mode 100644
index 0000000..f241032
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/mp/handler/AbstractHandler.java
@@ -0,0 +1,12 @@
+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());
+}
diff --git a/src/main/java/com/rymcu/forest/wx/mp/handler/KfSessionHandler.java b/src/main/java/com/rymcu/forest/wx/mp/handler/KfSessionHandler.java
new file mode 100644
index 0000000..464a85d
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/mp/handler/KfSessionHandler.java
@@ -0,0 +1,25 @@
+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 context, WxMpService wxMpService,
+ WxSessionManager sessionManager) {
+ //TODO 对会话做处理
+ return null;
+ }
+
+}
diff --git a/src/main/java/com/rymcu/forest/wx/mp/handler/LocationHandler.java b/src/main/java/com/rymcu/forest/wx/mp/handler/LocationHandler.java
new file mode 100644
index 0000000..7502c6d
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/mp/handler/LocationHandler.java
@@ -0,0 +1,44 @@
+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 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;
+ }
+
+}
diff --git a/src/main/java/com/rymcu/forest/wx/mp/handler/LogHandler.java b/src/main/java/com/rymcu/forest/wx/mp/handler/LogHandler.java
new file mode 100644
index 0000000..8744d49
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/mp/handler/LogHandler.java
@@ -0,0 +1,25 @@
+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 context, WxMpService wxMpService,
+ WxSessionManager sessionManager) {
+ this.logger.info("\n接收到请求消息,内容:{}", JsonUtils.toJson(wxMessage));
+ return null;
+ }
+
+}
diff --git a/src/main/java/com/rymcu/forest/wx/mp/handler/MenuHandler.java b/src/main/java/com/rymcu/forest/wx/mp/handler/MenuHandler.java
new file mode 100644
index 0000000..0faedf0
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/mp/handler/MenuHandler.java
@@ -0,0 +1,35 @@
+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 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();
+ }
+
+}
diff --git a/src/main/java/com/rymcu/forest/wx/mp/handler/MsgHandler.java b/src/main/java/com/rymcu/forest/wx/mp/handler/MsgHandler.java
new file mode 100644
index 0000000..9aec3ec
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/mp/handler/MsgHandler.java
@@ -0,0 +1,45 @@
+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 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);
+
+ }
+
+}
diff --git a/src/main/java/com/rymcu/forest/wx/mp/handler/NullHandler.java b/src/main/java/com/rymcu/forest/wx/mp/handler/NullHandler.java
new file mode 100644
index 0000000..907cba4
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/mp/handler/NullHandler.java
@@ -0,0 +1,24 @@
+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 context, WxMpService wxMpService,
+ WxSessionManager sessionManager) {
+ return null;
+ }
+
+}
diff --git a/src/main/java/com/rymcu/forest/wx/mp/handler/ScanHandler.java b/src/main/java/com/rymcu/forest/wx/mp/handler/ScanHandler.java
new file mode 100644
index 0000000..c4f3ab1
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/mp/handler/ScanHandler.java
@@ -0,0 +1,25 @@
+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 map,
+ WxMpService wxMpService, WxSessionManager wxSessionManager) throws WxErrorException {
+ // 扫码事件处理
+ return null;
+ }
+}
diff --git a/src/main/java/com/rymcu/forest/wx/mp/handler/StoreCheckNotifyHandler.java b/src/main/java/com/rymcu/forest/wx/mp/handler/StoreCheckNotifyHandler.java
new file mode 100644
index 0000000..bcc973b
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/mp/handler/StoreCheckNotifyHandler.java
@@ -0,0 +1,27 @@
+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 context, WxMpService wxMpService,
+ WxSessionManager sessionManager) {
+ // TODO 处理门店审核事件
+ return null;
+ }
+
+}
diff --git a/src/main/java/com/rymcu/forest/wx/mp/handler/SubscribeHandler.java b/src/main/java/com/rymcu/forest/wx/mp/handler/SubscribeHandler.java
new file mode 100644
index 0000000..1e1f4da
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/mp/handler/SubscribeHandler.java
@@ -0,0 +1,71 @@
+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 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;
+ }
+
+}
diff --git a/src/main/java/com/rymcu/forest/wx/mp/handler/UnsubscribeHandler.java b/src/main/java/com/rymcu/forest/wx/mp/handler/UnsubscribeHandler.java
new file mode 100644
index 0000000..1e84cee
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/mp/handler/UnsubscribeHandler.java
@@ -0,0 +1,27 @@
+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 context, WxMpService wxMpService,
+ WxSessionManager sessionManager) {
+ String openId = wxMessage.getFromUser();
+ this.logger.info("取消关注用户 OPENID: " + openId);
+ // TODO 可以更新本地数据库为取消关注状态
+ return null;
+ }
+
+}
diff --git a/src/main/java/com/rymcu/forest/wx/mp/utils/JsonUtils.java b/src/main/java/com/rymcu/forest/wx/mp/utils/JsonUtils.java
new file mode 100644
index 0000000..c0520b6
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/mp/utils/JsonUtils.java
@@ -0,0 +1,9 @@
+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);
+ }
+}
diff --git a/src/main/java/com/rymcu/forest/wx/open/config/WxOpenProperties.java b/src/main/java/com/rymcu/forest/wx/open/config/WxOpenProperties.java
new file mode 100644
index 0000000..184c738
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/open/config/WxOpenProperties.java
@@ -0,0 +1,42 @@
+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 007
+ */
+@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);
+ }
+}
diff --git a/src/main/java/com/rymcu/forest/wx/open/controller/WxOpenApiController.java b/src/main/java/com/rymcu/forest/wx/open/controller/WxOpenApiController.java
new file mode 100644
index 0000000..96837a6
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/open/controller/WxOpenApiController.java
@@ -0,0 +1,78 @@
+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 007
+ */
+@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 "go ";
+ }
+
+ @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);
+ }
+ }
+}
diff --git a/src/main/java/com/rymcu/forest/wx/open/controller/WxOpenNotifyController.java b/src/main/java/com/rymcu/forest/wx/open/controller/WxOpenNotifyController.java
new file mode 100644
index 0000000..0a83d0e
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/open/controller/WxOpenNotifyController.java
@@ -0,0 +1,122 @@
+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 007
+ */
+@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;
+ }
+}
diff --git a/src/main/java/com/rymcu/forest/wx/open/handler/WxOpenServiceHandler.java b/src/main/java/com/rymcu/forest/wx/open/handler/WxOpenServiceHandler.java
new file mode 100644
index 0000000..bbf2b33
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/open/handler/WxOpenServiceHandler.java
@@ -0,0 +1,67 @@
+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;
+ }
+}
diff --git a/src/main/java/com/rymcu/vertical/config/Swagger2Configuration.java b/src/main/java/com/rymcu/vertical/config/Swagger2Configuration.java
deleted file mode 100644
index 471fdef..0000000
--- a/src/main/java/com/rymcu/vertical/config/Swagger2Configuration.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.rymcu.vertical.config;
-
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import springfox.documentation.builders.ApiInfoBuilder;
-import springfox.documentation.builders.PathSelectors;
-import springfox.documentation.builders.RequestHandlerSelectors;
-import springfox.documentation.service.ApiInfo;
-import springfox.documentation.spi.DocumentationType;
-import springfox.documentation.spring.web.plugins.Docket;
-import springfox.documentation.swagger2.annotations.EnableSwagger2;
-
-/**
- * @author ronger
- */
-@Configuration
-@EnableSwagger2
-public class Swagger2Configuration {
-
- @Bean
- public Docket createRestApi() {
- return new Docket(DocumentationType.SWAGGER_2)
- .apiInfo(apiInfo())
- .select()
- .apis(RequestHandlerSelectors.basePackage("com.rymcu.vertical.web.api"))
- .paths(PathSelectors.any())
- .build();
- }
-
- private ApiInfo apiInfo() {
- return new ApiInfoBuilder()
- .title("Vertical项目接口文档")
- .description("Vertical项目相关接口的文档")
- .termsOfServiceUrl("http://www.rymcu.com")
- .version("1.0")
- .build();
- }
-
-}
diff --git a/src/main/java/com/rymcu/vertical/mapper/SpecialDayMapper.java b/src/main/java/com/rymcu/vertical/mapper/SpecialDayMapper.java
deleted file mode 100644
index 9e9a964..0000000
--- a/src/main/java/com/rymcu/vertical/mapper/SpecialDayMapper.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.rymcu.vertical.mapper;
-
-import com.rymcu.vertical.core.mapper.Mapper;
-import com.rymcu.vertical.entity.SpecialDay;
-
-/**
- * @author ronger
- */
-public interface SpecialDayMapper extends Mapper {
-}
diff --git a/src/main/java/com/rymcu/vertical/mapper/VisitMapper.java b/src/main/java/com/rymcu/vertical/mapper/VisitMapper.java
deleted file mode 100644
index 0a2bba6..0000000
--- a/src/main/java/com/rymcu/vertical/mapper/VisitMapper.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.rymcu.vertical.mapper;
-
-import com.rymcu.vertical.core.mapper.Mapper;
-import com.rymcu.vertical.entity.Visit;
-
-/**
- * @author ronger
- */
-public interface VisitMapper extends Mapper {
-}
diff --git a/src/main/java/com/rymcu/vertical/service/SpecialDayService.java b/src/main/java/com/rymcu/vertical/service/SpecialDayService.java
deleted file mode 100644
index e5a8ff0..0000000
--- a/src/main/java/com/rymcu/vertical/service/SpecialDayService.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.rymcu.vertical.service;
-
-import com.rymcu.vertical.core.service.Service;
-import com.rymcu.vertical.entity.SpecialDay;
-
-/**
- * @author ronger
- */
-public interface SpecialDayService extends Service {
-}
diff --git a/src/main/java/com/rymcu/vertical/service/VisitService.java b/src/main/java/com/rymcu/vertical/service/VisitService.java
deleted file mode 100644
index 05b2327..0000000
--- a/src/main/java/com/rymcu/vertical/service/VisitService.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.rymcu.vertical.service;
-
-import com.rymcu.vertical.core.service.Service;
-import com.rymcu.vertical.entity.Visit;
-
-/**
- * @author ronger
- */
-public interface VisitService extends Service {
-}
diff --git a/src/main/java/com/rymcu/vertical/service/impl/VisitServiceImpl.java b/src/main/java/com/rymcu/vertical/service/impl/VisitServiceImpl.java
deleted file mode 100644
index 5ecb0f6..0000000
--- a/src/main/java/com/rymcu/vertical/service/impl/VisitServiceImpl.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.rymcu.vertical.service.impl;
-
-import com.rymcu.vertical.core.service.AbstractService;
-import com.rymcu.vertical.entity.Visit;
-import com.rymcu.vertical.service.VisitService;
-import org.springframework.stereotype.Service;
-
-/**
- * @author ronger
- */
-@Service
-public class VisitServiceImpl extends AbstractService implements VisitService {
-}
diff --git a/src/main/java/com/rymcu/vertical/util/NotificationUtils.java b/src/main/java/com/rymcu/vertical/util/NotificationUtils.java
deleted file mode 100644
index 7a42c0c..0000000
--- a/src/main/java/com/rymcu/vertical/util/NotificationUtils.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package com.rymcu.vertical.util;
-
-import com.rymcu.vertical.entity.Notification;
-import com.rymcu.vertical.entity.User;
-import com.rymcu.vertical.service.NotificationService;
-import com.rymcu.vertical.service.UserService;
-
-import javax.annotation.Resource;
-import java.util.List;
-import java.util.concurrent.*;
-
-/**
- * 消息通知工具类
- * @author ronger
- */
-public class NotificationUtils {
-
- @Resource
- private static NotificationService notificationService = SpringContextHolder.getBean(NotificationService.class);
- @Resource
- private static UserService userService = SpringContextHolder.getBean(UserService.class);
-
- public static void sendAnnouncement(Integer dataId, String dataType, String dataSummary) {
- ExecutorService executor= new ThreadPoolExecutor(1,1,0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue());
- CompletableFuture.supplyAsync(()-> {
- System.out.println("------------------- 开始执行消息通知 ------------------");
- try {
- List users = userService.findAll();
- users.forEach(user -> {
- Notification notification = notificationService.findNotification(user.getIdUser(),dataId,dataType);
- if (notification == null) {
- Integer result = notificationService.save(user.getIdUser(),dataId,dataType,dataSummary);
- if (result == 0) {
- saveNotification(user.getIdUser(),dataId,dataType,dataSummary);
- }
- }
- });
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- return 0;
- },executor);
- }
-
- public static void saveNotification(Integer idUser, Integer dataId, String dataType, String dataSummary) {
- ExecutorService executor= new ThreadPoolExecutor(1,1,0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue());
- CompletableFuture.supplyAsync(()-> {
- try {
- Notification notification = notificationService.findNotification(idUser,dataId,dataType);
- if (notification == null) {
- Integer result = notificationService.save(idUser,dataId,dataType,dataSummary);
- if (result == 0) {
- // TODO 记录操作失败数据
- }
- }
- } catch (Exception ex) {
- // TODO 记录操作失败数据
- ex.printStackTrace();
- }
- return 0;
- },executor);
-
- }
-}
diff --git a/src/main/java/com/rymcu/vertical/web/api/user/UserInfoController.java b/src/main/java/com/rymcu/vertical/web/api/user/UserInfoController.java
deleted file mode 100644
index 559b512..0000000
--- a/src/main/java/com/rymcu/vertical/web/api/user/UserInfoController.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.rymcu.vertical.web.api.user;
-
-import com.rymcu.vertical.core.result.GlobalResult;
-import com.rymcu.vertical.core.result.GlobalResultGenerator;
-import com.rymcu.vertical.dto.UserInfoDTO;
-import com.rymcu.vertical.service.UserService;
-import org.springframework.web.bind.annotation.*;
-
-import javax.annotation.Resource;
-import java.util.Map;
-
-/**
- * @author ronger
- */
-@RestController
-@RequestMapping("/api/v1/user-info")
-public class UserInfoController {
-
- @Resource
- private UserService userService;
-
- @GetMapping("/detail/{idUser}")
- public GlobalResult detail(@PathVariable Integer idUser) {
- Map map = userService.findUserInfo(idUser);
- return GlobalResultGenerator.genSuccessResult(map);
- }
-
- @GetMapping("/check-nickname")
- public GlobalResult checkNickname(@RequestParam Integer idUser, @RequestParam String nickname) {
- Map map = userService.checkNickname(idUser,nickname);
- return GlobalResultGenerator.genSuccessResult(map);
- }
-
- @PatchMapping("/update")
- public GlobalResult updateUserInfo(@RequestBody UserInfoDTO user) {
- Map map = userService.updateUserInfo(user);
- return GlobalResultGenerator.genSuccessResult(map);
- }
-
-}
diff --git a/src/main/java/mapper/ArticleMapper.xml b/src/main/java/mapper/ArticleMapper.xml
index d1f80cf..e181ab9 100644
--- a/src/main/java/mapper/ArticleMapper.xml
+++ b/src/main/java/mapper/ArticleMapper.xml
@@ -1,7 +1,7 @@
-
-
+
+
@@ -19,7 +19,7 @@
-
+
@@ -39,14 +39,14 @@
-
+
-
+
@@ -55,11 +55,12 @@
-
+
+
insert into vertical_article_content (id_article,article_content,article_content_html,created_time,updated_time)
@@ -74,6 +75,9 @@
update vertical_article set article_tags = #{tags} where id = #{idArticle}
+
+ update vertical_article set article_link = #{articleLink}, article_permalink = #{articlePermalink}, article_preview_content = #{articlePreviewContent} where id = #{idArticle}
+
delete from vertical_tag_article where id_article = #{id}
@@ -92,8 +96,7 @@
order by updated_time desc
- select art.*,su.nickname,su.avatar_url from vertical_article art join vertical_user su on art.article_author_id
- = su.id where art.id = #{id}
+ select art.*,su.nickname,su.avatar_url from vertical_article art join vertical_user su on art.article_author_id = su.id where art.id = #{id}
and art.article_status = 0
@@ -129,9 +132,12 @@
and instr(art.article_title, #{searchText}) > 0 and art.id not in (select id_vertical_article from vertical_portfolio_article where id_vertical_portfolio = #{idPortfolio}) order by updated_time desc
- select vp.portfolio_title,vp.portfolio_head_img_url,vpa.id_vertical_portfolio,vpa.id_vertical_article from vertical_portfolio vp join vertical_portfolio_article vpa on vp.id = vpa.id_vertical_portfolio where vpa.id_vertical_article = #{idArticle}
+ select vp.portfolio_title,vp.portfolio_head_img_url,vpa.id_vertical_portfolio,vpa.id_vertical_article,vpa.sort_no from vertical_portfolio vp join vertical_portfolio_article vpa on vp.id = vpa.id_vertical_portfolio where vpa.id_vertical_article = #{idArticle}
-
+
+ select va.article_title, va.id, va.article_permalink from vertical_portfolio_article vpa join vertical_article va on va.id = vpa.id_vertical_article where id_vertical_portfolio = #{idPortfolio} order by sort_no
+
+
\ No newline at end of file
diff --git a/src/main/java/mapper/CommentMapper.xml b/src/main/java/mapper/CommentMapper.xml
index cbc5cbc..ffb41a9 100644
--- a/src/main/java/mapper/CommentMapper.xml
+++ b/src/main/java/mapper/CommentMapper.xml
@@ -1,7 +1,7 @@
-
-
+
+
@@ -16,7 +16,7 @@
-
+
@@ -29,7 +29,7 @@
-
+
diff --git a/src/main/java/mapper/DashboardMapper.xml b/src/main/java/mapper/DashboardMapper.xml
index a777165..4db3f61 100644
--- a/src/main/java/mapper/DashboardMapper.xml
+++ b/src/main/java/mapper/DashboardMapper.xml
@@ -1,7 +1,7 @@
-
-
+
+
diff --git a/src/main/java/mapper/FollowMapper.xml b/src/main/java/mapper/FollowMapper.xml
new file mode 100644
index 0000000..8e82fe5
--- /dev/null
+++ b/src/main/java/mapper/FollowMapper.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ select ifnull((select true from vertical_follow where follower_id = #{followerId}
+ and following_id = #{followingId} and following_type = #{followingType}), false)
+
+
+ select id, nickname, avatar_type, avatar_url, account, signature from vertical_user vu
+ where exists (select * from vertical_follow vf where following_type = 0 and following_id = #{idUser} and follower_id = vu.id limit 1)
+
+
+ select id, nickname, avatar_type, avatar_url, account, signature from vertical_user vu
+ where exists (select * from vertical_follow vf where following_type = 0 and follower_id = #{idUser} and following_id = vu.id limit 1)
+
+
\ No newline at end of file
diff --git a/src/main/java/mapper/NotificationMapper.xml b/src/main/java/mapper/NotificationMapper.xml
index 063e356..a6e8dc2 100644
--- a/src/main/java/mapper/NotificationMapper.xml
+++ b/src/main/java/mapper/NotificationMapper.xml
@@ -1,7 +1,7 @@
-
-
+
+
diff --git a/src/main/java/mapper/PermissionMapper.xml b/src/main/java/mapper/PermissionMapper.xml
index 1120571..d0a9d8f 100644
--- a/src/main/java/mapper/PermissionMapper.xml
+++ b/src/main/java/mapper/PermissionMapper.xml
@@ -1,7 +1,7 @@
-
-
+
+
diff --git a/src/main/java/mapper/PortfolioMapper.xml b/src/main/java/mapper/PortfolioMapper.xml
index c7f93a4..d6f24d8 100644
--- a/src/main/java/mapper/PortfolioMapper.xml
+++ b/src/main/java/mapper/PortfolioMapper.xml
@@ -1,7 +1,7 @@
-
-
+
+
@@ -10,7 +10,7 @@
-
+
diff --git a/src/main/java/mapper/RoleMapper.xml b/src/main/java/mapper/RoleMapper.xml
index 95b5c0f..864639b 100644
--- a/src/main/java/mapper/RoleMapper.xml
+++ b/src/main/java/mapper/RoleMapper.xml
@@ -1,7 +1,7 @@
-
-
+
+
diff --git a/src/main/java/mapper/SpecialDayMapper.xml b/src/main/java/mapper/SpecialDayMapper.xml
index d4977b7..fecfeae 100644
--- a/src/main/java/mapper/SpecialDayMapper.xml
+++ b/src/main/java/mapper/SpecialDayMapper.xml
@@ -1,7 +1,7 @@
-
-
+
+
diff --git a/src/main/java/mapper/TagMapper.xml b/src/main/java/mapper/TagMapper.xml
index 6425fc0..108f4db 100644
--- a/src/main/java/mapper/TagMapper.xml
+++ b/src/main/java/mapper/TagMapper.xml
@@ -1,7 +1,7 @@
-
-
+
+
@@ -18,7 +18,7 @@
-
+
diff --git a/src/main/java/mapper/TopicMapper.xml b/src/main/java/mapper/TopicMapper.xml
index aebe73f..6c859f4 100644
--- a/src/main/java/mapper/TopicMapper.xml
+++ b/src/main/java/mapper/TopicMapper.xml
@@ -1,7 +1,7 @@
-
-
+
+
@@ -18,7 +18,7 @@
-
+
@@ -27,14 +27,14 @@
-
+
-
+
diff --git a/src/main/java/mapper/UserExtendMapper.xml b/src/main/java/mapper/UserExtendMapper.xml
new file mode 100644
index 0000000..565428b
--- /dev/null
+++ b/src/main/java/mapper/UserExtendMapper.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ select vue.* from vertical_user_extend vue join vertical_user vu on vue.id_user = vu.id
+ where vu.nickname = #{nickname} limit 1
+
+
\ No newline at end of file
diff --git a/src/main/java/mapper/UserMapper.xml b/src/main/java/mapper/UserMapper.xml
index 2874d2c..6c770b7 100644
--- a/src/main/java/mapper/UserMapper.xml
+++ b/src/main/java/mapper/UserMapper.xml
@@ -1,7 +1,7 @@
-
-
+
+
@@ -20,7 +20,7 @@
-
+
@@ -33,7 +33,7 @@
-
+
@@ -41,7 +41,7 @@
-
+
@@ -68,9 +68,15 @@
update vertical_user set last_login_time = sysdate() where id = #{idUser}
+
+ update vertical_user set email = #{email} where id = #{idUser}
+
+
+ update vertical_user set password = #{password} where id = #{idUser}
+
- select id, nickname, account, password, status from vertical_user where account = #{account} and status = 0
+ select id, nickname, account, password, status, avatar_type, avatar_url from vertical_user where (account = #{account} or email = #{account} ) and status = 0
select id, nickname, sex, avatar_type, avatar_url, email, phone, account, status, signature, last_login_time from vertical_user where account = #{account}
diff --git a/src/main/java/mapper/VisitMapper.xml b/src/main/java/mapper/VisitMapper.xml
index d912756..ad7ba5e 100644
--- a/src/main/java/mapper/VisitMapper.xml
+++ b/src/main/java/mapper/VisitMapper.xml
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/src/main/java/mapper/WxUserMapper.xml b/src/main/java/mapper/WxUserMapper.xml
new file mode 100644
index 0000000..ebcfc65
--- /dev/null
+++ b/src/main/java/mapper/WxUserMapper.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index 8254f9f..74dcc06 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -1,6 +1,6 @@
spring:
-# profiles:
-# active: dev
+ profiles:
+ active: dev
thymeleaf:
prefix: classpath:/templates/
suffix: .html
@@ -22,32 +22,58 @@ spring:
max-idle: 500
min-idle: 0
datasource:
- druid:
- url: jdbc:mysql://localhost:3306/vertical?characterEncoding=UTF-8&autoReconnect=true&useSSL=false
- username: root
- password: # 数据库密码
- driver-class-name: com.mysql.cj.jdbc.Driver
+ url: jdbc:mysql://localhost:3306/forest?characterEncoding=UTF-8&autoReconnect=true&useSSL=false
+ username: root
+ password: # 数据库密码
+ driver-class-name: com.mysql.cj.jdbc.Driver
resources:
add-mappings: true
mail:
- host: smtp.163.com
+ host: smtp.163.com # 网站发送邮件邮箱服务 host
port: 465
username: # 邮箱
password: # 密码
+wx:
+ open:
+ componentAppId: wx9c4a7dfb3238d5f6
+ componentSecret: e32a6f75ab6b746ec3ae38a39a79ba22
+ componentToken: rymcu
+ componentAesKey: NWIwMDQyZjU0YWI2NGFlZThkOWZhZTg3NTg4NzQwN2E
+ mp:
+ configs:
+ - appId: xxx #微信公众号消息服务器配置的 appId
+ secret: xxx #微信公众号消息服务器配置的 secret
+ token: xxx #微信公众号消息服务器配置的 token
+ aesKey: xxx #微信公众号消息服务器配置的 aesKey
+ miniapp:
+ configs:
+ - appid: #微信小程序消息服务器配置的 appid
+ secret: #微信小程序消息服务器配置的 secret
+ token: #微信小程序消息服务器配置的 token
+ aesKey: #微信小程序消息服务器配置的 EncodingAESKey
+ msgDataFormat: JSON
env: dev
logging:
file:
- path: /logs/vertical
+ path: /logs/forest
+ level:
+ com:
+ rymcu: info
server:
port: 8099
servlet:
- context-path: /vertical
+ context-path: /forest
version: 1.0
resource:
- file-path: https://abc.com/vertical
+ domain: http://yourdomain.com # 网站域名
+ file-path: http://yourdomain.com # 上传文件前缀域名
+ pic-path: /yoursrc/xx/nebula/static # 上传文件存储地址
baidu:
data:
- site: https://abc.com # 百度搜索资源配置网址
- token: xxxx # 百度搜索资源token
-reserved-words: \u7cfb\u7edf\u516c\u544a\u002c\u516c\u544a
+ site: https://yourdomain.com # 百度搜索绑定网站域名
+ token: xxxx
+ ai:
+ appId: xxx # 百度AI-文字识别 应用 appId
+ appKey: xxxx # 百度AI-文字识别 应用 appKey
+ secretKey: xxxx # 百度AI-文字识别 应用 secretKey
diff --git a/src/test/java/com/rymcu/vertical/VerticalApplicationTests.java b/src/test/java/com/rymcu/forest/ForestApplicationTests.java
similarity index 72%
rename from src/test/java/com/rymcu/vertical/VerticalApplicationTests.java
rename to src/test/java/com/rymcu/forest/ForestApplicationTests.java
index b3e4934..e7d9cce 100644
--- a/src/test/java/com/rymcu/vertical/VerticalApplicationTests.java
+++ b/src/test/java/com/rymcu/forest/ForestApplicationTests.java
@@ -1,10 +1,10 @@
-package com.rymcu.vertical;
+package com.rymcu.forest;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
-class VerticalApplicationTests {
+class ForestApplicationTests {
@Test
void contextLoads() {