场景
没有业务场景的示例都是在耍流氓
今天领导让做下 企业微信 的对接工作(应该不少人都有在做)
之前就写过一两个接口,就简单写了下
逻辑
以获取群聊信息为例:
- 根据
corpid
,secret(应用密钥)
获取access_token
,即获取应用的授权,不同应用secret
不同 access_token
的获取是不能频繁去获取的,否则可能会被 IP 限制,因此我们把token
保存到Redis
中,每次先从Redis
中获取,没有或者 token 过期 再去提交请求获取access_token
- 调用获取群聊信息的接口
- 判断企业微信的返回值
errcode
,是否有密钥过期 - 如果密钥过期,获取
access_token
再次 调用获取群聊信息的接口
反面教材
所有接口都是这种套娃式的逻辑,只有一个字形容 龊
@Resource
private AppchatService appchatService;
/**
* 获取群聊
* @param chatid
* @return
*/
@GetMapping(value = "/get/{chatid}")
public ErrorMsg get(@PathVariable("chatid") String chatid) {
// 获取 token
String accessToken = tokenService.getToken(wechatInfo.getAppchatSecret());
ErrorMsg msg = appchatService.get(accessToken, chatid);
// 如果发生错误,可能是密钥过期,尝试更新密钥再获取
if (msg.getErrorCode().equals(ErrorMsg.ACCESS_LIMITED.getErrorCode())) {
accessToken = tokenService.updateToken(wechatInfo.getAppchatSecret());
msg = appchatService.get(accessToken, chatid);
}
return msg;
}
get 方法的实现
@Override
public ErrorMsg get(String accessToken, String chatid) {
if (StringUtils.isBlank(chatid)) {
return ErrorMsg.ARGS_ERROR.setNewErrorMsg("群聊 id 不能为空");
}
String url = wechatInfo.getIp() + "/cgi-bin/appchat/get?access_token=" + accessToken + "&chatid=" + chatid;
String json = RestTemplateUtil.get(url, null);
AppchatResult result = JsonUtil.toBean(json, AppchatResult.class);
if (!"0".equals(result.getErrcode())) {
return ErrorMsg.ACCESS_LIMITED.setNewErrorMsg(result.getErrmsg());
}
return ErrorMsg.SUCCESS.setNewData(result);
}
其他例子
函数式编程优化代码
定义函数式接口
这个接口就是我们被代理的函数的抽象,其中自定义的 apply 方法就是去执行方法
@FunctionalInterface: 用于定义接口为函数式接口,接口下有且仅有一个抽象方法
参数: 可以看到 apply
方法中后面的参数只有一个,就是 accessToken
因为 只有这个参数,我们需要动态修改
/**
* 函数式,接口执行
*/
@FunctionalInterface
public interface ApplyFunction {
ErrorMsg apply(String accessToken);
}
对前文中的逻辑进行封装
/**
* 执行操作
* @author: linjinp
* @create: 2020-06-18 11:19
**/
@Component
public class OperatorFunction {
@Resource
private TokenService tokenService;
public ErrorMsg doOperate(String secret, ApplyFunction function) {
// 获取 token
String accessToken = tokenService.getToken(secret);
// 执行代理的函数
ErrorMsg msg = function.apply(accessToken);
// 如果发生错误,可能是密钥过期,尝试更新密钥再获取
if (msg.getErrorCode().equals(ErrorMsg.ACCESS_LIMITED.getErrorCode())) {
accessToken = tokenService.updateToken(secret);
msg = function.apply(accessToken);
}
return msg;
}
}
函数式接口调用
accessToken: 这个参数需要变动,因此这里的 val
即前文中函数式接口的参数
chatid: 这个参数是固定的,不需要变动,因此直接传就行了,不需要通过函数式接口
/**
* 获取群聊
* @param chatid
* @return
*/
@GetMapping(value = "/get/{chatid}")
public ErrorMsg get(@PathVariable("chatid") String chatid) {
String secret = wechatInfo.getAppchatSecret();
return operatorFunction.doOperate(secret, (val) -> appchatService.get(val, chatid));
}
调用示例
开始调用函数式接口
以读取用户信息接口为例,这里 secret
为 null
情况下,getToken
会给 secret
一个默认值,因此不需要管
请求成功,如果不成功,就会更新 token
再请求一次