Просмотр исходного кода

[公众号消息][修改]:公众号消息

release
Stormeye Wu 7 лет назад
Родитель
Сommit
0c1be0336a
25 измененных файлов: 1242 добавлений и 49 удалений
  1. +64
    -49
      mlWechatOpen/src/main/java/com/iformall/controller/WechatCalllbackController.java
  2. +17
    -0
      mlWechatOpen/src/main/java/com/iformall/mp/builder/AbstractBuilder.java
  3. +24
    -0
      mlWechatOpen/src/main/java/com/iformall/mp/builder/ImageBuilder.java
  4. +22
    -0
      mlWechatOpen/src/main/java/com/iformall/mp/builder/TextBuilder.java
  5. +49
    -0
      mlWechatOpen/src/main/java/com/iformall/mp/controller/WxMemController.java
  6. +190
    -0
      mlWechatOpen/src/main/java/com/iformall/mp/controller/WxMenuController.java
  7. +150
    -0
      mlWechatOpen/src/main/java/com/iformall/mp/controller/WxMpCallBackController.java
  8. +44
    -0
      mlWechatOpen/src/main/java/com/iformall/mp/controller/WxRedirectController.java
  9. +29
    -0
      mlWechatOpen/src/main/java/com/iformall/mp/error/ErrorController.java
  10. +27
    -0
      mlWechatOpen/src/main/java/com/iformall/mp/error/ErrorPageConfiguration.java
  11. +12
    -0
      mlWechatOpen/src/main/java/com/iformall/mp/handler/AbstractHandler.java
  12. +25
    -0
      mlWechatOpen/src/main/java/com/iformall/mp/handler/KfSessionHandler.java
  13. +44
    -0
      mlWechatOpen/src/main/java/com/iformall/mp/handler/LocationHandler.java
  14. +25
    -0
      mlWechatOpen/src/main/java/com/iformall/mp/handler/LogHandler.java
  15. +36
    -0
      mlWechatOpen/src/main/java/com/iformall/mp/handler/MenuHandler.java
  16. +51
    -0
      mlWechatOpen/src/main/java/com/iformall/mp/handler/MsgHandler.java
  17. +24
    -0
      mlWechatOpen/src/main/java/com/iformall/mp/handler/NullHandler.java
  18. +8
    -0
      mlWechatOpen/src/main/java/com/iformall/mp/handler/ScanHandler.java
  19. +27
    -0
      mlWechatOpen/src/main/java/com/iformall/mp/handler/StoreCheckNotifyHandler.java
  20. +70
    -0
      mlWechatOpen/src/main/java/com/iformall/mp/handler/SubscribeHandler.java
  21. +27
    -0
      mlWechatOpen/src/main/java/com/iformall/mp/handler/UnsubscribeHandler.java
  22. +116
    -0
      mlWechatOpen/src/main/java/com/iformall/mp/manager/WxMpManager.java
  23. +123
    -0
      mlWechatOpen/src/main/java/com/iformall/mp/service/WxMpManager.java
  24. +16
    -0
      mlWechatOpen/src/main/java/com/iformall/mp/utils/JsonUtils.java
  25. +22
    -0
      mlWechatOpen/src/main/java/com/iformall/mp/utils/MpUtil.java

+ 64
- 49
mlWechatOpen/src/main/java/com/iformall/controller/WechatCalllbackController.java Просмотреть файл

@@ -6,11 +6,15 @@ import com.iformall.common.Result;
import com.iformall.common.ResultData;
import com.iformall.domain.po.*;
import com.iformall.enums.*;
import com.iformall.mp.service.WxMpManager;
import com.iformall.mp.utils.MpUtil;
import com.iformall.service.*;
import com.iformall.service.wechat.WxOpenService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
@@ -59,10 +63,13 @@ public class WechatCalllbackController extends BaseController {
@Autowired
private MailService mailService;

@Autowired
private WxMpManager mpManager;

@RequestMapping(value = "/notify", method = RequestMethod.POST)
@ApiOperation("接收ticket回调")
public Object receiveTicket(HttpServletRequest request) throws IOException {
logger.info("[" +getIpAddr() + "]接收微信回调 /wxOpen/notify");
logger.info("[" + getIpAddr() + "]接收微信回调 /wxOpen/notify");
InputStream inStream = request.getInputStream();
ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
@@ -77,10 +84,10 @@ public class WechatCalllbackController extends BaseController {
inStream.close();

String timestamp = request.getParameter("timestamp");
String nonce = request.getParameter("nonce");
String nonce = request.getParameter("nonce");
String signature = request.getParameter("signature");
String encType = request.getParameter("encrypt_type");
String msgSignature= request.getParameter("msg_signature");
String msgSignature = request.getParameter("msg_signature");

/*
// 测试数据
@@ -108,19 +115,19 @@ public class WechatCalllbackController extends BaseController {
WxOpenXmlMessage inMessage = WxOpenXmlMessage.fromEncryptedXml(resultxml,
openService.getWxOpenConfigStorage(), timestamp, nonce, msgSignature);
this.logger.info("接收微信回调,消息解密后内容为:{} ", inMessage.toString());
if(inMessage.getInfoType().equals(EnumWxAuthorizationInfoType.COMPONENT_VERIFY_TICKET.getMessage())) {
if (inMessage.getInfoType().equals(EnumWxAuthorizationInfoType.COMPONENT_VERIFY_TICKET.getMessage())) {
// 保存component_verify_ticket
componentVerifyTicketService.saveOrUpdate(new WxComponentVerifyTicket(){
componentVerifyTicketService.saveOrUpdate(new WxComponentVerifyTicket() {
{
setComponentVerifyTicket(inMessage.getComponentVerifyTicket());
setCreateTime(new Date(Long.valueOf(inMessage.getCreateTime() * 1000)));
setComponentAppid(inMessage.getAppId());
setDeadline(new Date(Long.valueOf(System.currentTimeMillis() + (60*60*1000))));
setDeadline(new Date(Long.valueOf(System.currentTimeMillis() + (60 * 60 * 1000))));
}
});
} else if (inMessage.getInfoType().equals(EnumWxAuthorizationInfoType.AUTHORIZED.getMessage()) ||
inMessage.getInfoType().equals(EnumWxAuthorizationInfoType.UPDATEAUTHORIZED.getMessage())
) {
) {
try {
WxOpenQueryAuthResult queryAuthResult = openService.getWxOpenComponentService().getQueryAuth(inMessage.getAuthorizationCode());
logger.info("getQueryAuth", queryAuthResult);
@@ -129,7 +136,7 @@ public class WechatCalllbackController extends BaseController {
queryAuthResult.getAuthorizationInfo().getAuthorizerAppid());
logger.info(openAuthorizerInfoResult.toString());
// save auth info
authorizerInfoService.saveOrUpdate(new WxAuthorizerInfo(){
authorizerInfoService.saveOrUpdate(new WxAuthorizerInfo() {
{
setAuthorizerAppid(openAuthorizerInfoResult.getAuthorizationInfo().getAuthorizerAppid());
setAlias(openAuthorizerInfoResult.getAuthorizerInfo().getAlias());
@@ -143,7 +150,7 @@ public class WechatCalllbackController extends BaseController {
logger.error(e.getMessage());
}
} else if (inMessage.getInfoType().equals(EnumWxAuthorizationInfoType.UNAUTHORIZED.getMessage())) {
authorizerInfoService.saveOrUpdate(new WxAuthorizerInfo(){
authorizerInfoService.saveOrUpdate(new WxAuthorizerInfo() {
{
setAuthorizerAppid(inMessage.getAuthorizerAppid());
setAuthorizationStatus(EnumWxAuthorizationStatus.UNAUTHORIZED.getCode());
@@ -163,8 +170,16 @@ public class WechatCalllbackController extends BaseController {

@RequestMapping(value = "/{appId}/callback")
@ApiOperation("消息回调")
public Object callback(@PathVariable("appId") String appId, HttpServletRequest request) throws IOException {
logger.info("[" +getIpAddr() + "]接收微信APP回调 /{appId}/callback");
@ResponseBody
public String callback(@PathVariable("appId") String appId, HttpServletRequest request) throws IOException {
logger.info("[" + getIpAddr() + "]接收微信APP回调 /{appId}/callback");
String timestamp = request.getParameter("timestamp");
String nonce = request.getParameter("nonce");
String signature = request.getParameter("signature");
String encType = request.getParameter("encrypt_type");
String openid = request.getParameter("openid");
String msgSignature = request.getParameter("msg_signature");

InputStream inStream = request.getInputStream();
ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
@@ -178,27 +193,24 @@ public class WechatCalllbackController extends BaseController {
outSteam.close();
inStream.close();

String timestamp = request.getParameter("timestamp");
String nonce = request.getParameter("nonce");
String signature = request.getParameter("signature");
String encType = request.getParameter("encrypt_type");
String openid = request.getParameter("openid");
String msgSignature= request.getParameter("msg_signature");

logger.info("接收微信APP回调:[appId=[{}], openid=[{}], signature=[{}], encType=[{}], msgSignature=[{}],"
+ " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
appId, openid, signature, encType, msgSignature, timestamp, nonce, resultxml);
// 第三方平台一定接收的是加密的消息
if (!StringUtils.equalsIgnoreCase("aes", encType)
|| !openService.getWxOpenComponentService().checkSignature(timestamp, nonce, signature)) {
throw new IllegalArgumentException("非法请求,可能属于伪造的请求!");
}

WxAppinfo appinfo = appinfoService.getByAppId(appId);

String out = "";
// aes加密的消息
WxMpXmlMessage inMessage = WxOpenXmlMessage.fromEncryptedMpXml(resultxml,
openService.getWxOpenConfigStorage(), timestamp, nonce, msgSignature);
logger.info("接收微信APP回调,消息解密后内容为:\n{}", inMessage.toString());
// 全网发布测试用例
/*
if (StringUtils.equalsAnyIgnoreCase(appId, "wx570bc396a51b8ff8", "wxd101a85aa106f53e")) {
try {
if (StringUtils.equals(inMessage.getMsgType(), "text")) {
@@ -222,9 +234,12 @@ public class WechatCalllbackController extends BaseController {
} catch (WxErrorException e) {
logger.error("callback", e);
}
} else {
}
*/
if(appinfo.getType().equals(EnumAppType.B.getCode()) || appinfo.getType().equals(EnumAppType.C.getCode())) {
// 小程序
/**判断消息类型,调用对应的方法*/
switch (inMessage.getMsgType()){
switch (inMessage.getMsgType()) {
case "event": {
switch (inMessage.getEvent()) {
case "weapp_audit_success": { // 审核成功
@@ -246,18 +261,6 @@ public class WechatCalllbackController extends BaseController {
out = WxOpenXmlMessage.wxMpOutXmlMessageToEncryptedXml(outMessage, openService.getWxOpenConfigStorage());
logger.info(out);
}
/*
else {

WxMpXmlOutMessage outMsg = new WxMpXmlOutTextMessage();
outMsg.setCreateTime(System.currentTimeMillis());
outMsg.setToUserName(inMessage.getFromUser());
outMsg.setFromUserName(inMessage.getToUser());
outMsg.setMsgType("text");
((WxMpXmlOutTextMessage) outMsg).setContent(inMessage.getContent());
out = WxOpenXmlMessage.wxMpOutXmlMessageToEncryptedXml(outMsg, wxOpenService.getWxOpenConfigStorage());
}
*/
else {
out = "success";
}
@@ -265,9 +268,21 @@ public class WechatCalllbackController extends BaseController {
default:
return "success";
}
} else {
// 公众号
WxMpService mpService = MpUtil.getMpService(appinfo);
try {
WxMpXmlOutMessage outMessage = mpManager.getRouter(mpService).route(inMessage);
if (outMessage == null) {
this.logger.info("2 return: success");
return "success";
}
out = outMessage.toEncryptedXml(mpService.getWxMpConfigStorage());
} catch (Exception e) {
logger.error("路由消息时出现异常!", e);
}
}


return out;
}

@@ -275,8 +290,8 @@ public class WechatCalllbackController extends BaseController {


WxWeappAuditStatus auditStatus = weappAuditStatusService.getByAppId(appId);
if(auditStatus != null) {
if(success) {
if (auditStatus != null) {
if (success) {
auditStatus.setAuditStatus(EnumWeappAuditStatus.SUCCESS.getCode());
auditStatus.setAuditErrCode("");
} else {
@@ -289,21 +304,21 @@ public class WechatCalllbackController extends BaseController {

// 发邮件
WxAppinfo appinfo = appinfoService.getByAppId(appId);
if(appinfo != null) {
if (appinfo != null) {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式

StringBuilder titleSB = new StringBuilder();
if(appinfo.getType().equals(EnumAppType.C.getCode())) {
if (appinfo.getType().equals(EnumAppType.C.getCode())) {
titleSB.append("C端小程序");
} else if(appinfo.getType().equals(EnumAppType.B.getCode())) {
} else if (appinfo.getType().equals(EnumAppType.B.getCode())) {
titleSB.append("B端小程序");
} else if(appinfo.getType().equals(EnumAppType.MP_S.getCode())) {
} else if (appinfo.getType().equals(EnumAppType.MP_S.getCode())) {
titleSB.append("公众号-服务号");
} else if(appinfo.getType().equals(EnumAppType.MP_P.getCode())) {
} else if (appinfo.getType().equals(EnumAppType.MP_P.getCode())) {
titleSB.append("公众号-订阅号");
}
titleSB.append(appinfo.getName());
if(success) {
if (success) {
titleSB.append("审核通过");
} else {
titleSB.append("审核未通过");
@@ -311,13 +326,13 @@ public class WechatCalllbackController extends BaseController {

StringBuilder sb = new StringBuilder();
sb.append(df.format(new Date())).append("\n");
if(success) {
if (success) {
sb.append("审核通过\n");
} else {
sb.append("审核未通过\n").append("原因").append(reason);
}

String[] receivers = new String[] {"wangmei@iformall.com", "wuguoqiang@iformall.com", "huanghui@iformall.com", "sunmingming@iformall.com"};
String[] receivers = new String[]{"wangmei@iformall.com", "wuguoqiang@iformall.com", "huanghui@iformall.com", "sunmingming@iformall.com"};

//发送邮件
mailService.sendSimpleMail(receivers, titleSB.toString(), sb.toString());
@@ -326,15 +341,15 @@ public class WechatCalllbackController extends BaseController {

@GetMapping(value = "/createOpenPlatform")
@ApiOperation("创建微信开放平台")
public ResultData createOpenPlatform(@RequestParam(value="appId") String appId) {
public ResultData createOpenPlatform(@RequestParam(value = "appId") String appId) {
Gson gson = new GsonBuilder().create();
try {
String responseStr = openService.getWxOpenComponentService().getWxMpServiceByAppid(appId).createOpenPlatform(appId);
logger.info(responseStr);
WxOpenPlatformResult openPlatformResult = gson.fromJson(responseStr, WxOpenPlatformResult.class);
if(openPlatformResult.isSuccess()) {
if (openPlatformResult.isSuccess()) {
WxAuthorizerInfo authorizerInfo = authorizerInfoService.getByAppId(appId);
if(authorizerInfo != null) {
if (authorizerInfo != null) {
authorizerInfo.setId(authorizerInfo.getId());
authorizerInfo.setOpenAppid(openPlatformResult.getOpenAppid());
authorizerInfoService.updateOpenAppid(authorizerInfo);
@@ -355,7 +370,7 @@ public class WechatCalllbackController extends BaseController {
String responseStr = openService.getWxOpenComponentService().getWxMpServiceByAppid(appId).bindOpenPlatform(appId, openAppId);
logger.info(responseStr);
WxOpenResult openResult = gson.fromJson(responseStr, WxOpenResult.class);
if(openResult.isSuccess()) {
if (openResult.isSuccess()) {
return new ResultData();
}
return new ResultData(Result.ERROR, responseStr);
@@ -373,7 +388,7 @@ public class WechatCalllbackController extends BaseController {
String responseStr = openService.getWxOpenComponentService().getWxMpServiceByAppid(appId).unbindOpenPlatform(appId, openAppId);
logger.info(responseStr);
WxOpenResult openResult = gson.fromJson(responseStr, WxOpenResult.class);
if(openResult.isSuccess()) {
if (openResult.isSuccess()) {
return new ResultData();
}
return new ResultData(Result.ERROR, responseStr);
@@ -391,7 +406,7 @@ public class WechatCalllbackController extends BaseController {
String responseStr = openService.getWxOpenComponentService().getWxMpServiceByAppid(appId).getBindOpenPlatform(appId);
logger.info(responseStr);
WxOpenPlatformResult openPlatformResult = gson.fromJson(responseStr, WxOpenPlatformResult.class);
if(openPlatformResult.isSuccess()) {
if (openPlatformResult.isSuccess()) {
return new ResultData(openPlatformResult.getOpenAppid());
}
return new ResultData(Result.ERROR, responseStr);


+ 17
- 0
mlWechatOpen/src/main/java/com/iformall/mp/builder/AbstractBuilder.java Просмотреть файл

@@ -0,0 +1,17 @@
package com.iformall.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 Stormeye
*/
public abstract class AbstractBuilder {
protected final Logger logger = LoggerFactory.getLogger(getClass());

public abstract WxMpXmlOutMessage build(String content,
WxMpXmlMessage wxMessage, WxMpService service);
}

+ 24
- 0
mlWechatOpen/src/main/java/com/iformall/mp/builder/ImageBuilder.java Просмотреть файл

@@ -0,0 +1,24 @@
package com.iformall.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;
}

}

+ 22
- 0
mlWechatOpen/src/main/java/com/iformall/mp/builder/TextBuilder.java Просмотреть файл

@@ -0,0 +1,22 @@
package com.iformall.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;
}

}

+ 49
- 0
mlWechatOpen/src/main/java/com/iformall/mp/controller/WxMemController.java Просмотреть файл

@@ -0,0 +1,49 @@
package com.iformall.mp.controller;

import com.iformall.common.ResultData;
import com.iformall.mp.service.WxMpManager;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import me.chanjar.weixin.mp.bean.result.WxMpUserList;
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.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
* @author Stormeye
*/
@RestController
@RequestMapping("/wx/{account}/mem")
public class WxMemController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());

@Autowired
private WxMpManager wxMpManager;

@GetMapping("/syncAccountFansList")
public ResultData syncAccountFansList(@PathVariable String account) throws WxErrorException {
final WxMpService wxService = wxMpManager.getMpService(account);

WxMpUserList mpUserList = wxService.getUserService().userList(null);
logger.info(mpUserList.toString());
List<WxMpUser> userList = wxService.getUserService().userInfoList(mpUserList.getOpenids());
logger.info(userList.toString());
while(StringUtils.isNotBlank(mpUserList.getNextOpenid())) {
mpUserList = wxService.getUserService().userList(mpUserList.getNextOpenid());
logger.info(mpUserList.toString());
if(mpUserList.getOpenids().size() > 0) {
userList = wxService.getUserService().userInfoList(mpUserList.getOpenids());
logger.info(userList.toString());
}
}
return new ResultData();
}
}

+ 190
- 0
mlWechatOpen/src/main/java/com/iformall/mp/controller/WxMenuController.java Просмотреть файл

@@ -0,0 +1,190 @@
package com.iformall.mp.controller;

import com.iformall.mp.service.WxMpManager;
import me.chanjar.weixin.common.api.WxConsts;
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.bean.menu.WxMpGetSelfMenuInfoResult;
import me.chanjar.weixin.mp.bean.menu.WxMpMenu;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.net.MalformedURLException;
import java.net.URL;

import static me.chanjar.weixin.common.api.WxConsts.MenuButtonType;

/**
* @author Stormeye
*/
@RestController
@RequestMapping("/wx/menu/{account}")
public class WxMenuController {

@Autowired
private WxMpManager wxMpManager;

/**
* <pre>
* 自定义菜单创建接口
* 详情请见:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141013&token=&lang=zh_CN
* 如果要创建个性化菜单,请设置matchrule属性
* 详情请见:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN
* </pre>
*
* @return 如果是个性化菜单,则返回menuid,否则返回null
*/
@PostMapping("/create")
public String menuCreate(@PathVariable String account, @RequestBody WxMenu menu) throws WxErrorException {
return wxMpManager.getMpService(account).getMenuService().menuCreate(menu);
}

@GetMapping("/create")
public String menuCreateSample(@PathVariable String account) throws WxErrorException, MalformedURLException {
WxMenu menu = new WxMenu();
WxMenuButton button1 = new WxMenuButton();
button1.setType(MenuButtonType.CLICK);
button1.setName("今日歌曲");
button1.setKey("V1001_TODAY_MUSIC");

// 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("搜索");
button31.setUrl("http://www.soso.com/");

WxMenuButton button32 = new WxMenuButton();
button32.setType(MenuButtonType.VIEW);
button32.setName("视频");
button32.setUrl("http://v.qq.com/");

WxMenuButton button33 = new WxMenuButton();
button33.setType(MenuButtonType.CLICK);
button33.setName("赞一下我们");
button33.setKey("V1001_GOOD");

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 = wxMpManager.getMpService(account)
.oauth2buildAuthorizationUrl(
String.format("%s://%s/wx/redirect/%s/greet", requestURL.getProtocol(), requestURL.getHost(), account),
WxConsts.OAuth2Scope.SNSAPI_USERINFO, null);
button34.setUrl(url);
}

button3.getSubButtons().add(button31);
button3.getSubButtons().add(button32);
button3.getSubButtons().add(button33);
button3.getSubButtons().add(button34);

return wxMpManager.getMpService(account).getMenuService().menuCreate(menu);
}

/**
* <pre>
* 自定义菜单创建接口
* 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141013&token=&lang=zh_CN
* 如果要创建个性化菜单,请设置matchrule属性
* 详情请见:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN
* </pre>
*
* @param json
* @return 如果是个性化菜单,则返回menuid,否则返回null
*/
@PostMapping("/createByJson")
public String menuCreate(@PathVariable String account, @RequestBody String json) throws WxErrorException {
return wxMpManager.getMpService(account).getMenuService().menuCreate(json);
}

/**
* <pre>
* 自定义菜单删除接口
* 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141015&token=&lang=zh_CN
* </pre>
*/
@GetMapping("/delete")
public void menuDelete(@PathVariable String account) throws WxErrorException {
wxMpManager.getMpService(account).getMenuService().menuDelete();
}

/**
* <pre>
* 删除个性化菜单接口
* 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN
* </pre>
*
* @param menuId 个性化菜单的menuid
*/
@GetMapping("/delete/{menuId}")
public void menuDelete(@PathVariable String account, @PathVariable String menuId) throws WxErrorException {
wxMpManager.getMpService(account).getMenuService().menuDelete(menuId);
}

/**
* <pre>
* 自定义菜单查询接口
* 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141014&token=&lang=zh_CN
* </pre>
*/
@GetMapping("/get")
public WxMpMenu menuGet(@PathVariable String account) throws WxErrorException {
return wxMpManager.getMpService(account).getMenuService().menuGet();
}

/**
* <pre>
* 测试个性化菜单匹配结果
* 详情请见: http://mp.weixin.qq.com/wiki/0/c48ccd12b69ae023159b4bfaa7c39c20.html
* </pre>
*
* @param userid 可以是粉丝的OpenID,也可以是粉丝的微信号。
*/
@GetMapping("/menuTryMatch/{userid}")
public WxMenu menuTryMatch(@PathVariable String account, @PathVariable String userid) throws WxErrorException {
return wxMpManager.getMpService(account).getMenuService().menuTryMatch(userid);
}

/**
* <pre>
* 获取自定义菜单配置接口
* 本接口将会提供公众号当前使用的自定义菜单的配置,如果公众号是通过API调用设置的菜单,则返回菜单的开发配置,而如果公众号是在公众平台官网通过网站功能发布菜单,则本接口返回运营者设置的菜单配置。
* 请注意:
* 1、第三方平台开发者可以通过本接口,在旗下公众号将业务授权给你后,立即通过本接口检测公众号的自定义菜单配置,并通过接口再次给公众号设置好自动回复规则,以提升公众号运营者的业务体验。
* 2、本接口与自定义菜单查询接口的不同之处在于,本接口无论公众号的接口是如何设置的,都能查询到接口,而自定义菜单查询接口则仅能查询到使用API设置的菜单配置。
* 3、认证/未认证的服务号/订阅号,以及接口测试号,均拥有该接口权限。
* 4、从第三方平台的公众号登录授权机制上来说,该接口从属于消息与菜单权限集。
* 5、本接口中返回的图片/语音/视频为临时素材(临时素材每次获取都不同,3天内有效,通过素材管理-获取临时素材接口来获取这些素材),本接口返回的图文消息为永久素材素材(通过素材管理-获取永久素材接口来获取这些素材)。
* 接口调用请求说明:
* http请求方式: GET(请使用https协议)
* https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token=ACCESS_TOKEN
* </pre>
*/
@GetMapping("/getSelfMenuInfo")
public WxMpGetSelfMenuInfoResult getSelfMenuInfo(@PathVariable String account) throws WxErrorException {
return wxMpManager.getMpService(account).getMenuService().getSelfMenuInfo();
}
}

+ 150
- 0
mlWechatOpen/src/main/java/com/iformall/mp/controller/WxMpCallBackController.java Просмотреть файл

@@ -0,0 +1,150 @@
package com.iformall.mp.controller;

import com.iformall.mp.service.WxMpManager;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.nio.charset.Charset;

/**
* @author Stormeye
*/
@Controller
@RequestMapping("/wx")
public class WxMpCallBackController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());

@Autowired
private WxMpManager wxMpManager;

/**
* GET请求:进行URL、Tocken 认证;
* 1. 将token、timestamp、nonce三个参数进行字典序排序
* 2. 将三个参数字符串拼接成一个字符串进行sha1加密
* 3. 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
*/
@GetMapping(value = "/{account}/message")
@ResponseBody
public void authGet(@PathVariable String account, HttpServletRequest request, HttpServletResponse response) throws IOException {
String signature = request.getParameter("signature");// 微信加密签名
String timestamp = request.getParameter("timestamp");// 时间戳
String nonce = request.getParameter("nonce");// 随机数
String echostr = request.getParameter("echostr");// 随机字符串

if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) {
throw new IllegalArgumentException("请求参数非法,请核实!");
}

this.logger.info("接收到来自微信服务器的认证消息:[{}, {}, {}, {}]",
signature, timestamp, nonce, echostr);

// 数据库 ->
final WxMpService wxService = wxMpManager.getMpService(account);
if (wxService == null) {
throw new IllegalArgumentException(String.format("未找到对应account=[%s]的配置,请核实!", account));
}

if (wxService.checkSignature(timestamp, nonce, signature)) {
logger.info("微信服务验证成功");
PrintWriter out = response.getWriter();
out.print(echostr);
out.close();
}
}

/**
* POST 请求:进行消息处理;
*/
@PostMapping(value = "/{account}/message")
@ResponseBody
public String post(@PathVariable String account, HttpServletRequest request) throws IOException {
// 处理用户和微信公众账号交互消息
String signature = request.getParameter("signature");// 微信加密签名
String timestamp = request.getParameter("timestamp");// 时间戳
String nonce = request.getParameter("nonce");// 随机数
String openid = request.getParameter("openid");
String encType = request.getParameter("encrypt_type");
String msgSignature = request.getParameter("msg_signature");

if (StringUtils.isAnyBlank(signature, timestamp, nonce)) {
throw new IllegalArgumentException("请求参数非法,请核实!");
}

final WxMpService wxService = wxMpManager.getMpService(account);

if (!wxService.checkSignature(timestamp, nonce, signature)) {
throw new IllegalArgumentException("非法请求,可能属于伪造的请求!");
}

InputStream inStream = request.getInputStream();
ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = inStream.read(buffer)) != -1) {
outSteam.write(buffer, 0, len);
}
String requestBody = new String(outSteam.toByteArray(), Charset.forName("UTF-8"));
logger.info(requestBody);

outSteam.close();
inStream.close();

this.logger.info("\n接收微信请求:[openid=[{}], [signature=[{}], encType=[{}], msgSignature=[{}],"
+ " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
openid, signature, encType, msgSignature, timestamp, nonce, requestBody);

String out = null;
if (encType == null) {
// 明文传输的消息
WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(requestBody);

WxMpXmlOutMessage outMessage = this.route(inMessage, wxService);
if (outMessage == null) {
logger.info("1 return: success");
return "success";
}

out = outMessage.toXml();
logger.info(out);
} else if ("aes".equalsIgnoreCase(encType)) {
// aes加密的消息
WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody, wxService.getWxMpConfigStorage(),
timestamp, nonce, msgSignature);
this.logger.debug("\n消息解密后内容为:\n{} ", inMessage.toString());
WxMpXmlOutMessage outMessage = this.route(inMessage, wxService);
if (outMessage == null) {
this.logger.info("2 return: success");
return "success";
}
logger.info(outMessage.toXml());

out = outMessage.toEncryptedXml(wxService.getWxMpConfigStorage());
}
this.logger.info("\n组装回复信息:{}", out);
return out;
}

private WxMpXmlOutMessage route(WxMpXmlMessage message, WxMpService wxService) {
try {
return wxMpManager.getRouter(wxService).route(message);
} catch (Exception e) {
this.logger.error("路由消息时出现异常!", e);
}

return null;
}

}

+ 44
- 0
mlWechatOpen/src/main/java/com/iformall/mp/controller/WxRedirectController.java Просмотреть файл

@@ -0,0 +1,44 @@
package com.iformall.mp.controller;

import com.iformall.mp.service.WxMpManager;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
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 Stormeye
*/
@Controller
@RequestMapping("/wx/redirect/{account}")
public class WxRedirectController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());

@Autowired
private WxMpManager wxMpManager;


@RequestMapping("/greet")
public String greetUser(@PathVariable String account, @RequestParam String code, ModelMap map) {

WxMpService mpService = wxMpManager.getMpService(account);

try {
WxMpOAuth2AccessToken accessToken = mpService.oauth2getAccessToken(code);
WxMpUser user = mpService.oauth2getUserInfo(accessToken, null);
map.put("user", user);
} catch (WxErrorException e) {
e.printStackTrace();
}

return "greet_user";
}
}

+ 29
- 0
mlWechatOpen/src/main/java/com/iformall/mp/error/ErrorController.java Просмотреть файл

@@ -0,0 +1,29 @@
package com.iformall.mp.error;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

/**
* <pre>
* 出错页面控制器
* Created by Binary Wang on 2018/8/25.
* </pre>
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
@Controller
@RequestMapping("/error")
public class ErrorController {

@GetMapping(value = "/404")
public String error404() {
return "error";
}

@GetMapping(value = "/500")
public String error500() {
return "error";
}

}

+ 27
- 0
mlWechatOpen/src/main/java/com/iformall/mp/error/ErrorPageConfiguration.java Просмотреть файл

@@ -0,0 +1,27 @@
package com.iformall.mp.error;

import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.server.ErrorPageRegistrar;
import org.springframework.boot.web.server.ErrorPageRegistry;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

/**
* <pre>
* 配置错误状态与对应访问路径
* Created by Binary Wang on 2018/8/25.
* </pre>
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
@Component
public class ErrorPageConfiguration implements ErrorPageRegistrar {
@Override
public void registerErrorPages(ErrorPageRegistry errorPageRegistry) {
errorPageRegistry.addErrorPages(
new ErrorPage(HttpStatus.NOT_FOUND, "/error/404"),
new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500")
);
}

}

+ 12
- 0
mlWechatOpen/src/main/java/com/iformall/mp/handler/AbstractHandler.java Просмотреть файл

@@ -0,0 +1,12 @@
package com.iformall.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());
}

+ 25
- 0
mlWechatOpen/src/main/java/com/iformall/mp/handler/KfSessionHandler.java Просмотреть файл

@@ -0,0 +1,25 @@
package com.iformall.mp.handler;

import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
* @author Binary Wang(https://github.com/binarywang)
*/
@Component
public class KfSessionHandler extends AbstractHandler {

@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
Map<String, Object> context, WxMpService wxMpService,
WxSessionManager sessionManager) {
//TODO 对会话做处理
return null;
}

}

+ 44
- 0
mlWechatOpen/src/main/java/com/iformall/mp/handler/LocationHandler.java Просмотреть файл

@@ -0,0 +1,44 @@
package com.iformall.mp.handler;

import com.iformall.mp.builder.TextBuilder;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.stereotype.Component;

import java.util.Map;

import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType;

/**
* @author Binary Wang(https://github.com/binarywang)
*/
@Component
public class LocationHandler extends AbstractHandler {

@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
Map<String, Object> context, WxMpService wxMpService,
WxSessionManager sessionManager) {
if (wxMessage.getMsgType().equals(XmlMsgType.LOCATION)) {
//TODO 接收处理用户发送的地理位置消息
try {
String content = "感谢反馈,您的的地理位置已收到!";
return new TextBuilder().build(content, wxMessage, null);
} catch (Exception e) {
this.logger.error("位置消息接收处理失败", e);
return null;
}
}

//上报地理位置事件
this.logger.info("上报地理位置,纬度 : {},经度 : {},精度 : {}",
wxMessage.getLatitude(), wxMessage.getLongitude(), String.valueOf(wxMessage.getPrecision()));

//TODO 可以将用户地理位置信息保存到本地数据库,以便以后使用

return null;
}

}

+ 25
- 0
mlWechatOpen/src/main/java/com/iformall/mp/handler/LogHandler.java Просмотреть файл

@@ -0,0 +1,25 @@
package com.iformall.mp.handler;

import com.iformall.mp.utils.JsonUtils;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
* @author Binary Wang(https://github.com/binarywang)
*/
@Component
public class LogHandler extends AbstractHandler {
@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
Map<String, Object> context, WxMpService wxMpService,
WxSessionManager sessionManager) {
this.logger.info("\n接收到请求消息,内容:{}", JsonUtils.toJson(wxMessage));
return null;
}

}

+ 36
- 0
mlWechatOpen/src/main/java/com/iformall/mp/handler/MenuHandler.java Просмотреть файл

@@ -0,0 +1,36 @@
package com.iformall.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.MenuButtonType;

/**
* @author Binary Wang(https://github.com/binarywang)
*/
@Component
public class MenuHandler extends AbstractHandler {

@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
Map<String, Object> context, WxMpService weixinService,
WxSessionManager sessionManager) {

String msg = String.format("type:%s, event:%s, key:%s",
wxMessage.getMsgType(), wxMessage.getEvent(),
wxMessage.getEventKey());
if (MenuButtonType.VIEW.equals(wxMessage.getEvent())) {
return null;
}

return WxMpXmlOutMessage.TEXT().content(msg)
.fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser())
.build();
}

}

+ 51
- 0
mlWechatOpen/src/main/java/com/iformall/mp/handler/MsgHandler.java Просмотреть файл

@@ -0,0 +1,51 @@
package com.iformall.mp.handler;

import com.iformall.mp.builder.TextBuilder;
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 org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.util.Map;

import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType;

/**
* @author Binary Wang(https://github.com/binarywang)
*/
@Component
public class MsgHandler extends AbstractHandler {

@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
Map<String, Object> context, WxMpService weixinService,
WxSessionManager sessionManager) {

if (!wxMessage.getMsgType().equals(XmlMsgType.EVENT)) {
//TODO 可以选择将消息保存到本地
}

//当用户输入关键词如“你好”,“客服”等,并且有客服在线时,把消息转发给在线客服
try {
if (StringUtils.startsWithAny(wxMessage.getContent(), "你好", "客服")
&& weixinService.getKefuService().kfOnlineList()
.getKfOnlineList().size() > 0) {
return WxMpXmlOutMessage.TRANSFER_CUSTOMER_SERVICE()
.fromUser(wxMessage.getToUser())
.toUser(wxMessage.getFromUser()).build();
}
} catch (WxErrorException e) {
e.printStackTrace();
}

//TODO 组装回复消息
String content = "您好,有什么可以帮您";// "收到信息内容:" + JsonUtils.toJson(wxMessage);

return new TextBuilder().build(content, wxMessage, weixinService);

}

}

+ 24
- 0
mlWechatOpen/src/main/java/com/iformall/mp/handler/NullHandler.java Просмотреть файл

@@ -0,0 +1,24 @@
package com.iformall.mp.handler;

import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
* @author Binary Wang(https://github.com/binarywang)
*/
@Component
public class NullHandler extends AbstractHandler {

@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
Map<String, Object> context, WxMpService wxMpService,
WxSessionManager sessionManager) {
return null;
}

}

+ 8
- 0
mlWechatOpen/src/main/java/com/iformall/mp/handler/ScanHandler.java Просмотреть файл

@@ -0,0 +1,8 @@
package com.iformall.mp.handler;

/**
* @author Binary Wang(https://github.com/binarywang)
*/
public abstract class ScanHandler extends AbstractHandler {

}

+ 27
- 0
mlWechatOpen/src/main/java/com/iformall/mp/handler/StoreCheckNotifyHandler.java Просмотреть файл

@@ -0,0 +1,27 @@
package com.iformall.mp.handler;

import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
* 门店审核事件处理
*
* @author Binary Wang(https://github.com/binarywang)
*/
@Component
public class StoreCheckNotifyHandler extends AbstractHandler {

@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
Map<String, Object> context, WxMpService wxMpService,
WxSessionManager sessionManager) {
// TODO 处理门店审核事件
return null;
}

}

+ 70
- 0
mlWechatOpen/src/main/java/com/iformall/mp/handler/SubscribeHandler.java Просмотреть файл

@@ -0,0 +1,70 @@
package com.iformall.mp.handler;

import com.iformall.mp.builder.TextBuilder;
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;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
* @author Binary Wang(https://github.com/binarywang)
*/
@Component
public class SubscribeHandler extends AbstractHandler {

@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
Map<String, Object> context, WxMpService weixinService,
WxSessionManager sessionManager) throws WxErrorException {

this.logger.info("新关注用户 OPENID: " + wxMessage.getFromUser());

// 获取微信用户基本信息
try {
WxMpUser userWxInfo = weixinService.getUserService()
.userInfo(wxMessage.getFromUser(), null);
if (userWxInfo != null) {
// TODO 可以添加关注用户到本地数据库
}
} catch (WxErrorException e) {
if (e.getError().getErrorCode() == 48001) {
this.logger.info("该公众号没有获取用户信息权限!");
}
}


WxMpXmlOutMessage responseResult = null;
try {
responseResult = this.handleSpecial(wxMessage);
} catch (Exception e) {
this.logger.error(e.getMessage(), e);
}

if (responseResult != null) {
return responseResult;
}

try {
return new TextBuilder().build("感谢关注", wxMessage, weixinService);
} catch (Exception e) {
this.logger.error(e.getMessage(), e);
}

return null;
}

/**
* 处理特殊请求,比如如果是扫码进来的,可以做相应处理
*/
private WxMpXmlOutMessage handleSpecial(WxMpXmlMessage wxMessage)
throws Exception {
//TODO
return null;
}

}

+ 27
- 0
mlWechatOpen/src/main/java/com/iformall/mp/handler/UnsubscribeHandler.java Просмотреть файл

@@ -0,0 +1,27 @@
package com.iformall.mp.handler;

import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
* @author Binary Wang(https://github.com/binarywang)
*/
@Component
public class UnsubscribeHandler extends AbstractHandler {

@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
Map<String, Object> context, WxMpService wxMpService,
WxSessionManager sessionManager) {
String openId = wxMessage.getFromUser();
this.logger.info("取消关注用户 OPENID: " + openId);
// TODO 可以更新本地数据库为取消关注状态
return null;
}

}

+ 116
- 0
mlWechatOpen/src/main/java/com/iformall/mp/manager/WxMpManager.java Просмотреть файл

@@ -0,0 +1,116 @@
package com.iformall.mp.manager;

import com.iformall.domain.po.WxAppinfo;
import com.iformall.mp.handler.*;
import com.iformall.mp.utils.MpUtil;
import com.iformall.service.WxAppinfoService;
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.constant.WxMpEventConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import static me.chanjar.weixin.common.api.WxConsts.*;

/**
* wechat mp configuration
*
* @author Binary Wang(https://github.com/binarywang)
*/
@Service
public class WxMpManager {

@Autowired
private WxAppinfoService appinfoService;
@Autowired
private LogHandler logHandler;
@Autowired
private NullHandler nullHandler;
@Autowired
private KfSessionHandler kfSessionHandler;
@Autowired
private StoreCheckNotifyHandler storeCheckNotifyHandler;
@Autowired
private LocationHandler locationHandler;
@Autowired
private MenuHandler menuHandler;
@Autowired
private MsgHandler msgHandler;
@Autowired
private UnsubscribeHandler unsubscribeHandler;
@Autowired
private SubscribeHandler subscribeHandler;

public WxMpMessageRouter getRouter(WxAppinfo appinfo) {
WxMpService mpService = MpUtil.getMpService(appinfo);
if(mpService != null) {
return newRouter(mpService);
}
return null;
}

public WxMpMessageRouter getRouter(WxMpService mpService) {
return newRouter(mpService);
}

private WxMpMessageRouter newRouter(WxMpService wxMpService) {
final WxMpMessageRouter newRouter = new WxMpMessageRouter(wxMpService);

// 记录所有事件的日志 (异步执行)
newRouter.rule().handler(this.logHandler).next();

// 接收客服会话管理事件
newRouter.rule().async(false).msgType(XmlMsgType.EVENT)
.event(WxMpEventConstants.CustomerService.KF_CREATE_SESSION)
.handler(this.kfSessionHandler).end();
newRouter.rule().async(false).msgType(XmlMsgType.EVENT)
.event(WxMpEventConstants.CustomerService.KF_CLOSE_SESSION)
.handler(this.kfSessionHandler)
.end();
newRouter.rule().async(false).msgType(XmlMsgType.EVENT)
.event(WxMpEventConstants.CustomerService.KF_SWITCH_SESSION)
.handler(this.kfSessionHandler).end();

// 门店审核事件
newRouter.rule().async(false).msgType(XmlMsgType.EVENT)
.event(WxMpEventConstants.POI_CHECK_NOTIFY)
.handler(this.storeCheckNotifyHandler).end();

// 自定义菜单事件
newRouter.rule().async(false).msgType(XmlMsgType.EVENT)
.event(MenuButtonType.CLICK).handler(this.menuHandler).end();

// 点击菜单连接事件
newRouter.rule().async(false).msgType(XmlMsgType.EVENT)
.event(MenuButtonType.VIEW).handler(this.nullHandler).end();

// 关注事件
newRouter.rule().async(false).msgType(XmlMsgType.EVENT)
.event(EventType.SUBSCRIBE).handler(this.subscribeHandler)
.end();

// 取消关注事件
newRouter.rule().async(false).msgType(XmlMsgType.EVENT)
.event(EventType.UNSUBSCRIBE)
.handler(this.unsubscribeHandler).end();

// 上报地理位置事件
newRouter.rule().async(false).msgType(XmlMsgType.EVENT)
.event(EventType.LOCATION).handler(this.locationHandler)
.end();

// 接收地理位置消息
newRouter.rule().async(false).msgType(XmlMsgType.LOCATION)
.handler(this.locationHandler).end();

// 扫码事件
newRouter.rule().async(false).msgType(XmlMsgType.EVENT)
.event(EventType.SCAN).handler(this.nullHandler).end();

// 默认
newRouter.rule().async(false).handler(this.msgHandler).end();

return newRouter;
}

}

+ 123
- 0
mlWechatOpen/src/main/java/com/iformall/mp/service/WxMpManager.java Просмотреть файл

@@ -0,0 +1,123 @@
package com.iformall.mp.service;

import com.iformall.domain.po.WxAppinfo;
import com.iformall.mp.handler.*;
import com.iformall.mp.utils.MpUtil;
import com.iformall.service.WxAppinfoService;
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.constant.WxMpEventConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import static me.chanjar.weixin.common.api.WxConsts.*;

/**
* wechat mp configuration
*
* @author Binary Wang(https://github.com/binarywang)
*/
@Service
public class WxMpManager {

@Autowired
private WxAppinfoService appinfoService;
@Autowired
private LogHandler logHandler;
@Autowired
private NullHandler nullHandler;
@Autowired
private KfSessionHandler kfSessionHandler;
@Autowired
private StoreCheckNotifyHandler storeCheckNotifyHandler;
@Autowired
private LocationHandler locationHandler;
@Autowired
private MenuHandler menuHandler;
@Autowired
private MsgHandler msgHandler;
@Autowired
private UnsubscribeHandler unsubscribeHandler;
@Autowired
private SubscribeHandler subscribeHandler;

public WxMpMessageRouter getRouter(String appId) {
WxMpService mpService = getMpService(appId);
if(mpService != null) {
return newRouter(mpService);
}
return null;
}

public WxMpMessageRouter getRouter(WxMpService mpService) {
return newRouter(mpService);
}

public WxMpService getMpService(String appId) {
WxAppinfo appinfo = appinfoService.getByAppId(appId);
if(appinfo == null)
return null;
return MpUtil.getMpService(appinfo);
}

private WxMpMessageRouter newRouter(WxMpService wxMpService) {
final WxMpMessageRouter newRouter = new WxMpMessageRouter(wxMpService);

// 记录所有事件的日志 (异步执行)
newRouter.rule().handler(this.logHandler).next();

// 接收客服会话管理事件
newRouter.rule().async(false).msgType(XmlMsgType.EVENT)
.event(WxMpEventConstants.CustomerService.KF_CREATE_SESSION)
.handler(this.kfSessionHandler).end();
newRouter.rule().async(false).msgType(XmlMsgType.EVENT)
.event(WxMpEventConstants.CustomerService.KF_CLOSE_SESSION)
.handler(this.kfSessionHandler)
.end();
newRouter.rule().async(false).msgType(XmlMsgType.EVENT)
.event(WxMpEventConstants.CustomerService.KF_SWITCH_SESSION)
.handler(this.kfSessionHandler).end();

// 门店审核事件
newRouter.rule().async(false).msgType(XmlMsgType.EVENT)
.event(WxMpEventConstants.POI_CHECK_NOTIFY)
.handler(this.storeCheckNotifyHandler).end();

// 自定义菜单事件
newRouter.rule().async(false).msgType(XmlMsgType.EVENT)
.event(MenuButtonType.CLICK).handler(this.menuHandler).end();

// 点击菜单连接事件
newRouter.rule().async(false).msgType(XmlMsgType.EVENT)
.event(MenuButtonType.VIEW).handler(this.nullHandler).end();

// 关注事件
newRouter.rule().async(false).msgType(XmlMsgType.EVENT)
.event(EventType.SUBSCRIBE).handler(this.subscribeHandler)
.end();

// 取消关注事件
newRouter.rule().async(false).msgType(XmlMsgType.EVENT)
.event(EventType.UNSUBSCRIBE)
.handler(this.unsubscribeHandler).end();

// 上报地理位置事件
newRouter.rule().async(false).msgType(XmlMsgType.EVENT)
.event(EventType.LOCATION).handler(this.locationHandler)
.end();

// 接收地理位置消息
newRouter.rule().async(false).msgType(XmlMsgType.LOCATION)
.handler(this.locationHandler).end();

// 扫码事件
newRouter.rule().async(false).msgType(XmlMsgType.EVENT)
.event(EventType.SCAN).handler(this.nullHandler).end();

// 默认
newRouter.rule().async(false).handler(this.msgHandler).end();

return newRouter;
}

}

+ 16
- 0
mlWechatOpen/src/main/java/com/iformall/mp/utils/JsonUtils.java Просмотреть файл

@@ -0,0 +1,16 @@
package com.iformall.mp.utils;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

/**
* @author Binary Wang(https://github.com/binarywang)
*/
public class JsonUtils {
public static String toJson(Object obj) {
Gson gson = new GsonBuilder()
.setPrettyPrinting()
.create();
return gson.toJson(obj);
}
}

+ 22
- 0
mlWechatOpen/src/main/java/com/iformall/mp/utils/MpUtil.java Просмотреть файл

@@ -0,0 +1,22 @@
package com.iformall.mp.utils;

import com.iformall.domain.po.WxAppinfo;
import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;

/**
* @author Stormeye
*/
public class MpUtil {
static public WxMpService getMpService(WxAppinfo appinfo) {
WxMpInMemoryConfigStorage configStorage = new WxMpInMemoryConfigStorage();
configStorage.setAppId(appinfo.getAppId());
configStorage.setSecret(appinfo.getSecret());
configStorage.setToken(appinfo.getToken());
configStorage.setAesKey(appinfo.getAesKey());
WxMpService service = new WxMpServiceImpl();
service.setWxMpConfigStorage(configStorage);
return service;
}
}

Загрузка…
Отмена
Сохранить