利用 JDK8 函數式編程,讓你的代碼更加優雅

場景

沒有業務場景的示例都是在耍流氓

今天領導讓做下 企業微信 的對接工作(應該不少人都有在做)

之前就寫過一兩個接口,就簡單寫了下

邏輯

以獲取羣聊信息爲例:

  1. 根據 corpidsecret(應用密鑰) 獲取 access_token,即獲取應用的授權,不同應用 secret 不同
  2. access_token 的獲取是不能頻繁去獲取的,否則可能會被 IP 限制,因此我們把 token 保存到 Redis 中,每次先從 Redis 中獲取,沒有或者 token 過期 再去提交請求獲取 access_token
  3. 調用獲取羣聊信息的接口
  4. 判斷企業微信的返回值 errcode,是否有密鑰過期
  5. 如果密鑰過期,獲取 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));
}

調用示例

開始調用函數式接口

以讀取用戶信息接口爲例,這裏 secretnull 情況下,getToken 會給 secret 一個默認值,因此不需要管
在這裏插入圖片描述
請求成功,如果不成功,就會更新 token 再請求一次
在這裏插入圖片描述

優化後的代碼

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章