✨ 微信开放平台服务集成
This commit is contained in:
parent
637c66135c
commit
e28e219428
@ -0,0 +1,68 @@
|
|||||||
|
package com.rymcu.vertical.wx.mp.controller;
|
||||||
|
|
||||||
|
import com.rymcu.vertical.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.Autowired;
|
||||||
|
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;
|
||||||
|
|
||||||
|
@Value("${resource.domain}")
|
||||||
|
private String domain;
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public String wxAuth(@PathVariable String appId, @RequestParam(name = "redirectUrl") String redirectUrl) {
|
||||||
|
wxMpService.switchoverTo(appId);
|
||||||
|
if ("wxa49093339a5a822b".equals(appId)) {
|
||||||
|
domain = "http://oae.nat300.top/vertical";
|
||||||
|
} else {
|
||||||
|
domain += "/vertical-console";
|
||||||
|
}
|
||||||
|
StringBuilder accessTokenUrl = new StringBuilder(domain).append("/wx/oauth/" + appId + "/getAccessToken?redirectUrl=").append(URIUtil.encodeURIComponent(domain + redirectUrl));
|
||||||
|
String oauth2Url = wxMpService.oauth2buildAuthorizationUrl(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.oauth2getAccessToken(code);
|
||||||
|
boolean valid = wxMpService.oauth2validateAccessToken(oAuth2AccessToken);
|
||||||
|
if (!valid) {
|
||||||
|
throw new Exception("无权限");
|
||||||
|
}
|
||||||
|
|
||||||
|
WxMpUser wxMpUser =wxMpService.getUserService().userInfo(oAuth2AccessToken.getOpenId());
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
package com.rymcu.vertical.wx.open.config;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="https://github.com/007gzs">007</a>
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ConfigurationProperties(prefix = "wx.open")
|
||||||
|
public class WxOpenProperties {
|
||||||
|
/**
|
||||||
|
* 设置微信三方平台的appid
|
||||||
|
*/
|
||||||
|
private String componentAppId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置微信三方平台的app secret
|
||||||
|
*/
|
||||||
|
private String componentSecret;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置微信三方平台的token
|
||||||
|
*/
|
||||||
|
private String componentToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置微信三方平台的EncodingAESKey
|
||||||
|
*/
|
||||||
|
private String componentAesKey;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return ToStringBuilder.reflectionToString(this,
|
||||||
|
ToStringStyle.MULTI_LINE_STYLE);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,110 @@
|
|||||||
|
package com.rymcu.vertical.wx.open.controller;
|
||||||
|
|
||||||
|
import com.rymcu.vertical.wx.open.handler.WxOpenServiceHandler;
|
||||||
|
import me.chanjar.weixin.common.error.WxErrorException;
|
||||||
|
import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage;
|
||||||
|
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
|
||||||
|
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
|
||||||
|
import me.chanjar.weixin.open.bean.message.WxOpenXmlMessage;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="https://github.com/007gzs">007</a>
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/notify")
|
||||||
|
public class WxOpenNotifyController {
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||||
|
@Autowired
|
||||||
|
protected WxOpenServiceHandler wxOpenService;
|
||||||
|
|
||||||
|
@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)) {
|
||||||
|
try {
|
||||||
|
if (StringUtils.equals(inMessage.getMsgType(), "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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
package com.rymcu.vertical.wx.open.handler;
|
||||||
|
|
||||||
|
import com.rymcu.vertical.core.service.props.DynProps4FilesService;
|
||||||
|
import com.rymcu.vertical.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.core.env.Environment;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import redis.clients.jedis.Jedis;
|
||||||
|
import redis.clients.jedis.JedisPool;
|
||||||
|
import redis.clients.jedis.JedisPoolConfig;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class WxOpenServiceHandler extends WxOpenServiceImpl {
|
||||||
|
|
||||||
|
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private WxOpenProperties wxOpenProperties;
|
||||||
|
@Resource
|
||||||
|
private WxOpenMessageRouter wxOpenMessageRouter;
|
||||||
|
@Resource
|
||||||
|
private DynProps4FilesService dynProps4Files;
|
||||||
|
@Resource
|
||||||
|
private Environment env;
|
||||||
|
private static JedisPool pool;
|
||||||
|
|
||||||
|
@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) {
|
||||||
|
JedisPoolConfig config = new JedisPoolConfig();
|
||||||
|
config.setMaxIdle(dynProps4Files.getInt("REDIS_MAX_IDLE", JedisPoolConfig.DEFAULT_MAX_IDLE));
|
||||||
|
config.setMaxTotal(dynProps4Files.getInt("REDIS_MAX_TOTAL", JedisPoolConfig.DEFAULT_MAX_TOTAL));
|
||||||
|
config.setMaxWaitMillis(dynProps4Files.getLong("REDIS_MAX_WAIT", JedisPoolConfig.DEFAULT_MAX_WAIT_MILLIS));
|
||||||
|
config.setTestOnBorrow(true);
|
||||||
|
pool = new JedisPool(config, env.getProperty("spring.redis.host"),
|
||||||
|
dynProps4Files.getInt("REDIS_PORT", 6379), dynProps4Files.getInt(
|
||||||
|
"REDIS_MAX_WAIT", 1000), dynProps4Files.getProperty("REDIS_PASSWORD", env.getProperty("spring.redis.password")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WxOpenMessageRouter getWxOpenMessageRouter() {
|
||||||
|
return wxOpenMessageRouter;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user