yshop1.9.1,WxJava升级到3.6,微信公众号服务配置重构,修复后台配置公众号API端必须要重启才能生效的问题

This commit is contained in:
hupeng
2020-01-20 14:44:51 +08:00
parent 90b29e6b86
commit 97dbcde392
15 changed files with 182 additions and 521 deletions

View File

@ -1 +1 @@
nohup java -jar yshop-api-1.8.jar --spring.profiles.active=prod &
nohup java -jar yshop-api-1.9.jar --spring.profiles.active=prod &

View File

@ -1,4 +1,4 @@
PID=$(ps -ef | grep yshop-api-1.8.jar | grep -v grep | awk '{ print $2 }')
PID=$(ps -ef | grep yshop-api-1.9.jar | grep -v grep | awk '{ print $2 }')
if [ -z "$PID" ];then
echo Application is already stopped
else

View File

@ -1425,8 +1425,8 @@ public class YxStoreOrderServiceImpl extends BaseServiceImpl<YxStoreOrderMapper,
//使用MQ延时消息
mqProducer.sendMsg("yshop-topic",storeOrder.getId().toString());
log.info("投递延时订单id [{}]", storeOrder.getId());
//mqProducer.sendMsg("yshop-topic",storeOrder.getId().toString());
//log.info("投递延时订单id [{}]", storeOrder.getId());
return storeOrder;
}

View File

@ -29,6 +29,7 @@ import co.yixiang.modules.user.entity.YxWechatUser;
import co.yixiang.modules.user.service.YxUserService;
import co.yixiang.modules.user.service.YxWechatUserService;
import co.yixiang.modules.user.web.vo.YxUserQueryVo;
import co.yixiang.mp.config.WxMpConfiguration;
import co.yixiang.utils.OrderUtil;
import co.yixiang.utils.RedisUtil;
import co.yixiang.utils.RedisUtils;
@ -85,7 +86,6 @@ public class AuthController {
private final AuthenticationManagerBuilder authenticationManagerBuilder;
private final YxUserService userService;
private final PasswordEncoder passwordEncoder;
private final WxMpService wxService;
private final YxWechatUserService wechatUserService;
private final WxMaService wxMaService;
private final NotifyService notifyService;
@ -95,7 +95,7 @@ public class AuthController {
OnlineUserService onlineUserService, TokenProvider tokenProvider,
AuthenticationManagerBuilder authenticationManagerBuilder,
YxUserService userService, PasswordEncoder passwordEncoder,
WxMpService wxService, YxWechatUserService wechatUserService,
YxWechatUserService wechatUserService,
WxMaService wxMaService,NotifyService notifyService) {
this.properties = properties;
this.redisUtils = redisUtils;
@ -105,7 +105,6 @@ public class AuthController {
this.authenticationManagerBuilder = authenticationManagerBuilder;
this.userService = userService;
this.passwordEncoder = passwordEncoder;
this.wxService = wxService;
this.wechatUserService = wechatUserService;
this.wxMaService = wxMaService;
this.notifyService = notifyService;
@ -154,6 +153,11 @@ public class AuthController {
HttpServletRequest request) {
try {
String appId = RedisUtil.get("wechat_appid");
if(StrUtil.isBlank(appId)) {
return ApiResult.fail("请配置公众号");
}
WxMpService wxService = WxMpConfiguration.getWxMpService(appId);
WxMpOAuth2AccessToken wxMpOAuth2AccessToken = wxService.oauth2getAccessToken(code);
WxMpUser wxMpUser = wxService.oauth2getUserInfo(wxMpOAuth2AccessToken, null);
String openid = wxMpUser.getOpenId();

View File

@ -1,43 +1,29 @@
package co.yixiang.modules.wechat.web.controller;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import co.yixiang.annotation.AnonymousAccess;
import co.yixiang.common.api.ApiCode;
import co.yixiang.common.api.ApiResult;
import co.yixiang.common.web.controller.BaseController;
import co.yixiang.modules.order.entity.YxStoreOrder;
import co.yixiang.modules.order.service.YxStoreOrderService;
import co.yixiang.modules.order.web.vo.YxStoreOrderQueryVo;
import co.yixiang.modules.shop.service.YxSystemConfigService;
import co.yixiang.modules.user.entity.YxUser;
import co.yixiang.modules.user.entity.YxWechatUser;
import co.yixiang.modules.user.service.YxUserService;
import co.yixiang.modules.user.service.YxWechatUserService;
import co.yixiang.modules.user.web.vo.YxUserQueryVo;
import co.yixiang.utils.EncryptUtils;
import co.yixiang.utils.OrderUtil;
import co.yixiang.mp.config.WxMpConfiguration;
import co.yixiang.utils.RedisUtil;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.vdurmont.emoji.EmojiParser;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
@ -45,7 +31,6 @@ import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
@ -60,12 +45,8 @@ import java.util.Map;
@Api(value = "微信模块", tags = "微信模块", description = "微信模块")
public class WechatController extends BaseController {
private final WxMpService wxService;
private final YxWechatUserService wechatUserService;
private final YxUserService userService;
private final WxPayService wxPayService;
private final YxStoreOrderService orderService;
private final WxMpMessageRouter messageRouter;
private final YxSystemConfigService systemConfigService;
@ -92,6 +73,9 @@ public class WechatController extends BaseController {
@GetMapping("/wechat/config")
@ApiOperation(value = "jssdk配置",notes = "jssdk配置")
public ApiResult<Object> jsConfig(@RequestParam(value = "url") String url) throws WxErrorException {
String appId = RedisUtil.get("wechat_appid");
if(StrUtil.isBlank(appId)) return ApiResult.fail("请配置公众号");
WxMpService wxService = WxMpConfiguration.getWxMpService(appId);
return ApiResult.ok(wxService.createJsapiSignature(url));
}
@ -165,6 +149,9 @@ public class WechatController extends BaseController {
@RequestParam(name = "nonce", required = false) String nonce,
@RequestParam(name = "echostr", required = false) String echostr){
String appId = RedisUtil.get("wechat_appid");
if(StrUtil.isBlank(appId)) return "请配置公众号";
WxMpService wxService = WxMpConfiguration.getWxMpService(appId);
if (wxService.checkSignature(timestamp, nonce, signature)) {
return echostr;
}
@ -186,6 +173,12 @@ public class WechatController extends BaseController {
HttpServletRequest request,
HttpServletResponse response) throws IOException {
String appId = RedisUtil.get("wechat_appid");
if(StrUtil.isBlank(appId)) {
log.error("请配置公众号!");
return;
}
WxMpService wxService = WxMpConfiguration.getWxMpService(appId);
if (!wxService.checkSignature(timestamp, nonce, signature)) {
throw new IllegalArgumentException("非法请求,可能属于伪造的请求!");
@ -195,14 +188,14 @@ public class WechatController extends BaseController {
if (encType == null) {
// 明文传输的消息
WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(requestBody);
WxMpXmlOutMessage outMessage = this.route(inMessage);
WxMpXmlOutMessage outMessage = this.route(inMessage,appId);
if(outMessage == null) return;
out = outMessage.toXml();;
} else if ("aes".equalsIgnoreCase(encType)) {
// aes加密的消息
WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody, wxService.getWxMpConfigStorage(),
timestamp, nonce, msgSignature);
WxMpXmlOutMessage outMessage = this.route(inMessage);
WxMpXmlOutMessage outMessage = this.route(inMessage,appId);
if(outMessage == null) return;
out = outMessage.toEncryptedXml(wxService.getWxMpConfigStorage());
@ -214,9 +207,9 @@ public class WechatController extends BaseController {
writer.close();
}
private WxMpXmlOutMessage route(WxMpXmlMessage message) {
private WxMpXmlOutMessage route(WxMpXmlMessage message,String appId) {
try {
return this.messageRouter.route(message);
return WxMpConfiguration.getWxMpMessageRouter(appId).route(message);
} catch (Exception e) {
log.error("路由消息时出现异常!", e);
}

View File

@ -12,21 +12,25 @@
<artifactId>yshop-mp</artifactId>
<name>微信模块</name>
<properties>
<weixin-java.version>3.6.0</weixin-java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-mp</artifactId>
<version>3.5.0</version>
<version>${weixin-java.version}</version>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java-pay-spring-boot-starter</artifactId>
<version>3.5.0</version>
<version>${weixin-java.version}</version>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java-miniapp-spring-boot-starter</artifactId>
<version>3.5.0</version>
<version>${weixin-java.version}</version>
</dependency>
<dependency>
<groupId>co.yixiang</groupId>

View File

@ -1,141 +1,154 @@
package co.yixiang.mp.config;
import cn.hutool.core.util.StrUtil;
import co.yixiang.mp.handler.*;
import co.yixiang.utils.RedisUtil;
import lombok.AllArgsConstructor;
import com.google.common.collect.Maps;
import me.chanjar.weixin.common.api.WxConsts;
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.apache.poi.util.StringUtil;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import me.chanjar.weixin.mp.constant.WxMpEventConstants;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.Map;
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.MenuButtonType.CLICK;
import static me.chanjar.weixin.common.api.WxConsts.MenuButtonType.VIEW;
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 hupeng
* @date 2020/01/20
*/
@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;
private final RedisHandler redisHandler;
@Bean
public WxMpService wxMpService() {
private static Map<String, WxMpService> mpServices = Maps.newHashMap();
private static Map<String, WxMpMessageRouter> routers = Maps.newHashMap();
final List<WxMpProperties.MpConfig> configs = new ArrayList<>();
WxMpProperties.MpConfig mpConfig = new WxMpProperties.MpConfig();
String appId = redisHandler.getVal("wechat_appid");
String secret = redisHandler.getVal("wechat_appsecret");
String token = redisHandler.getVal("wechat_token");
String aesKey = redisHandler.getVal("wechat_encodingaeskey");
private static LogHandler logHandler;
private static NullHandler nullHandler;
private static KfSessionHandler kfSessionHandler;
private static StoreCheckNotifyHandler storeCheckNotifyHandler;
private static LocationHandler locationHandler;
private static MenuHandler menuHandler;
private static MsgHandler msgHandler;
private static UnsubscribeHandler unsubscribeHandler;
private static SubscribeHandler subscribeHandler;
private static ScanHandler scanHandler;
private static RedisHandler redisHandler;
if(StrUtil.isNotBlank(appId) && StrUtil.isNotBlank(secret)
&& StrUtil.isNotBlank(token) && StrUtil.isNotBlank(aesKey)) {
mpConfig.setAppId(appId);
mpConfig.setSecret(secret);
mpConfig.setToken(token);
mpConfig.setAesKey(aesKey);
System.out.println(mpConfig);
configs.add(mpConfig);
}else{
mpConfig.setAppId("111111");
mpConfig.setSecret("111111");
mpConfig.setToken("111111");
mpConfig.setAesKey("111111");
configs.add(mpConfig);
}
//System.out.println("configs:"+configs);
if (configs.isEmpty()) {
throw new RuntimeException("请先配置!");
}
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;
public WxMpConfiguration(LogHandler logHandler,NullHandler nullHandler,KfSessionHandler kfSessionHandler,
StoreCheckNotifyHandler storeCheckNotifyHandler,LocationHandler locationHandler,
MenuHandler menuHandler,MsgHandler msgHandler,UnsubscribeHandler unsubscribeHandler,
SubscribeHandler subscribeHandler,ScanHandler scanHandler,
RedisHandler redisHandler){
this.logHandler = logHandler;
this.nullHandler = nullHandler;
this.kfSessionHandler = kfSessionHandler;
this.storeCheckNotifyHandler = storeCheckNotifyHandler;
this.locationHandler = locationHandler;
this.menuHandler = menuHandler;
this.msgHandler = msgHandler;
this.unsubscribeHandler = unsubscribeHandler;
this.subscribeHandler = subscribeHandler;
this.scanHandler = scanHandler;
this.redisHandler = redisHandler;
}
@Bean
public WxMpMessageRouter messageRouter(WxMpService wxMpService) {
/**
* 获取WxMpService
* @return
*/
public static WxMpService getWxMpService(String appId) {
WxMpService wxMpService = mpServices.get(appId);
if(wxMpService == null) {
WxMpDefaultConfigImpl configStorage = new WxMpDefaultConfigImpl();
configStorage.setAppId(redisHandler.getVal("wechat_appid"));
configStorage.setSecret(redisHandler.getVal("wechat_appsecret"));
configStorage.setToken(redisHandler.getVal("wechat_token"));
configStorage.setAesKey(redisHandler.getVal("wechat_encodingaeskey"));
wxMpService = new WxMpServiceImpl();
wxMpService.setWxMpConfigStorage(configStorage);
mpServices.put(appId, wxMpService);
routers.put(appId, newRouter(wxMpService));
}
return wxMpService;
}
/**
* 移除WxMpService
* @param appId
*/
public static void removeWxMpService(String appId){
mpServices.remove(appId);
routers.remove(appId);
}
/**
* 获取WxMpMessageRouter
* @param appId
*/
public static WxMpMessageRouter getWxMpMessageRouter(String appId) {
WxMpMessageRouter wxMpMessageRouter = routers.get(appId);
return wxMpMessageRouter;
}
private static WxMpMessageRouter newRouter(WxMpService wxMpService) {
final WxMpMessageRouter newRouter = new WxMpMessageRouter(wxMpService);
// 记录所有事件的日志 (异步执行)
//newRouter.rule().handler(this.logHandler).next();
newRouter.rule().handler(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(XmlMsgType.EVENT)
.event(WxMpEventConstants.CustomerService.KF_CREATE_SESSION)
.handler(kfSessionHandler).end();
newRouter.rule().async(false).msgType(XmlMsgType.EVENT)
.event(WxMpEventConstants.CustomerService.KF_CLOSE_SESSION)
.handler(kfSessionHandler)
.end();
newRouter.rule().async(false).msgType(XmlMsgType.EVENT)
.event(WxMpEventConstants.CustomerService.KF_SWITCH_SESSION)
.handler(kfSessionHandler).end();
// 门店审核事件
//newRouter.rule().async(false).msgType(EVENT).event(POI_CHECK_NOTIFY).handler(this.storeCheckNotifyHandler).end();
newRouter.rule().async(false).msgType(XmlMsgType.EVENT)
.event(WxMpEventConstants.POI_CHECK_NOTIFY)
.handler(storeCheckNotifyHandler).end();
// 自定义菜单事件
newRouter.rule().async(false).msgType(EVENT).event(CLICK).handler(this.menuHandler).end();
newRouter.rule().async(false).msgType(XmlMsgType.EVENT)
.event(WxConsts.MenuButtonType.CLICK).handler(menuHandler).end();
// 点击菜单连接事件
newRouter.rule().async(false).msgType(EVENT).event(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(XmlMsgType.EVENT)
.event(WxConsts.MenuButtonType.VIEW).handler(menuHandler).end();
// 扫码事件
//newRouter.rule().async(false).msgType(EVENT).event(EventType.SCAN).handler(this.scanHandler).end();
newRouter.rule().async(false).msgType(XmlMsgType.EVENT)
.event(EventType.SCANCODE_WAITMSG).handler(menuHandler).end();
// 关注事件
newRouter.rule().async(false).msgType(XmlMsgType.EVENT)
.event(EventType.SUBSCRIBE).handler(subscribeHandler)
.end();
// 取消关注事件
newRouter.rule().async(false).msgType(XmlMsgType.EVENT)
.event(EventType.UNSUBSCRIBE)
.handler(unsubscribeHandler).end();
// 上报地理位置事件
newRouter.rule().async(false).msgType(XmlMsgType.EVENT)
.event(EventType.LOCATION).handler(locationHandler)
.end();
// 默认
newRouter.rule().async(false).handler(this.msgHandler).end();
newRouter.rule().async(false).handler(msgHandler).end();
return newRouter;
}

View File

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

View File

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

View File

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

View File

@ -1,37 +0,0 @@
package co.yixiang.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;
@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.oauth2getAccessToken(code);
WxMpUser user = wxService.oauth2getUserInfo(accessToken, null);
map.put("user", user);
} catch (WxErrorException e) {
e.printStackTrace();
}
return "greet_user";
}
}

View File

@ -3,9 +3,11 @@ package co.yixiang.mp.controller;
import cn.hutool.core.util.StrUtil;
import co.yixiang.exception.BadRequestException;
import co.yixiang.mp.config.WxMpConfiguration;
import co.yixiang.mp.domain.YxCache;
import co.yixiang.mp.service.YxCacheService;
import co.yixiang.utils.OrderUtil;
import co.yixiang.utils.RedisUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.Api;
@ -31,8 +33,6 @@ public class YxCacheController {
@Autowired
private YxCacheService yxCacheService;
@Autowired
private WxMpService wxService;
@ApiOperation(value = "查询菜单")
@ -53,6 +53,12 @@ public class YxCacheController {
YxCache yxCache = new YxCache();
Boolean isExist = yxCacheService.isExist("wechat_menus");
WxMenu menu = JSONObject.parseObject(jsonStr,WxMenu.class);
String appId = RedisUtil.get("wechat_appid");
if(StrUtil.isBlank(appId)) {
throw new BadRequestException("请配置公众号");
}
WxMpService wxService = WxMpConfiguration.getWxMpService(appId);
if(isExist){
yxCache.setKey("wechat_menus");
yxCache.setResult(jsonButton);

View File

@ -1,6 +1,9 @@
package co.yixiang.mp.service.impl;
import cn.hutool.core.util.StrUtil;
import co.yixiang.mp.config.WxMpConfiguration;
import co.yixiang.mp.service.WxMpTemplateMessageService;
import co.yixiang.utils.RedisUtil;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
@ -13,9 +16,6 @@ import java.util.Map;
@Component
public class WxMpTemplateMessageServiceImpl implements WxMpTemplateMessageService {
@Autowired
private WxMpService wxMpService;
@Override
public String sendWxMpTemplateMessage(String openId, String templateId, String url, Map<String,String> map){
WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder()
@ -25,8 +25,13 @@ public class WxMpTemplateMessageServiceImpl implements WxMpTemplateMessageServic
.build();
map.forEach( (k,v)-> { templateMessage.addData(new WxMpTemplateData(k, v, "#000000"));} );
String msgId = null;
String appId = RedisUtil.get("wechat_appid");
if(StrUtil.isBlank(appId)) {
return "请配置公众号";
}
WxMpService wxService = WxMpConfiguration.getWxMpService(appId);
try {
msgId = wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage);
msgId = wxService.getTemplateMsgService().sendTemplateMsg(templateMessage);
} catch (WxErrorException e) {
e.printStackTrace();
}

View File

@ -3,9 +3,12 @@ package co.yixiang.mp.service.impl;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import co.yixiang.exception.BadRequestException;
import co.yixiang.exception.ErrorRequestException;
import co.yixiang.mp.config.WxMpConfiguration;
import co.yixiang.mp.domain.YxArticle;
import co.yixiang.mp.repository.YxArticleRepository;
import co.yixiang.mp.service.YxArticleService;
@ -13,10 +16,7 @@ import co.yixiang.mp.service.dto.YxArticleDTO;
import co.yixiang.mp.service.dto.YxArticleQueryCriteria;
import co.yixiang.mp.service.mapper.YxArticleMapper;
import co.yixiang.mp.utils.URLUtils;
import co.yixiang.utils.OrderUtil;
import co.yixiang.utils.PageUtil;
import co.yixiang.utils.QueryHelp;
import co.yixiang.utils.ValidationUtil;
import co.yixiang.utils.*;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.error.WxErrorException;
@ -56,8 +56,6 @@ public class YxArticleServiceImpl implements YxArticleService {
@Autowired
private YxArticleMapper yxArticleMapper;
@Autowired
private WxMpService wxMpService;
@Value("${file.path}")
private String uploadDirStr;
@ -107,6 +105,12 @@ public class YxArticleServiceImpl implements YxArticleService {
@Override
public void uploadNews(YxArticleDTO wxNewsArticleItem) throws Exception {
String appId = RedisUtil.get("wechat_appid");
if(StrUtil.isBlank(appId)) {
throw new BadRequestException("请配置公众号");
}
WxMpService wxMpService = WxMpConfiguration.getWxMpService(appId);
WxMpMaterialNews wxMpMaterialNews = new WxMpMaterialNews();
@ -118,7 +122,6 @@ public class YxArticleServiceImpl implements YxArticleService {
article.setAuthor( wxNewsArticleItem.getAuthor() );
System.out.println(wxNewsArticleItem.getContent());
//处理content
String content = processContent(wxMpService, wxNewsArticleItem.getContent());

View File

@ -7,6 +7,7 @@ import co.yixiang.exception.BadRequestException;
import co.yixiang.modules.wechat.domain.YxSystemConfig;
import co.yixiang.modules.wechat.service.YxSystemConfigService;
import co.yixiang.modules.wechat.service.dto.YxSystemConfigQueryCriteria;
import co.yixiang.mp.config.WxMpConfiguration;
import co.yixiang.utils.RedisUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
@ -52,6 +53,10 @@ public class YxSystemConfigController {
YxSystemConfig yxSystemConfigModel = new YxSystemConfig();
yxSystemConfigModel.setMenuName(key);
yxSystemConfigModel.setValue(value.toString());
//重新配置微信相关
if(key.equals("wechat_appid")){
WxMpConfiguration.removeWxMpService(key);
}
RedisUtil.set(key,value.toString(),0);
if(ObjectUtil.isNull(yxSystemConfig)){
yxSystemConfigService.create(yxSystemConfigModel);