通用接口开放平台设计与实现——(39)API服务之简单粗暴实现

前面我们基于netty组件实现了消息服务,接下来,我们开始说一说API服务

先来回顾下API服务的整体设计。

API服务是通用接口平台的主体部分,对外暴露Restful风格的数据接口,其他应用系统通过调用API服务,一方面,可以查询权限范围内的业务数据,另一方面,可以将自身系统产生的数据推送至接口平台。

API服务分为服务技术框架和具体业务功能接口两部分,技术框架部分负责统一调度、数据验证、身份认证、安全控制、日志记录等职责,具体业务功能接口负责实际的业务接口功能处理,总体处理流程如下图所示:
通用接口开放平台设计与实现——(39)API服务之简单粗暴实现_第1张图片

基于该总体设计,我们可以简单粗暴,用1个controller来解决

/**
 * api服务 控制器
 *
 * @author wqliu
 * @date 2021-8-19 13:56
 **/
@RestController
@RequestMapping("/api")
@Slf4j
public class ApiRestController {

    /**
     * 有效时间
     */
    private static final int VALID_TIME_SPAN = 10;
    @Autowired
    private ApiServiceService apiServiceService;

    @Autowired
    private ApiAppService apiAppService;

    @Autowired
    private ApiServicePermissionService apiServicePermissionService;

    @Autowired
    private ApiServiceLogService apiServiceLogService;

    @PostMapping("/rest")
    @AllowAll
    public ResponseEntity<ApiResponse> post(@Validated @RequestBody ApiRequest apiRequest) {
        //记录收到请求时间
        LocalDateTime receiveTime = LocalDateTime.now();

        //定义返回
        ApiResponse apiResponse = new ApiResponse();
        try {
            //验证数据
            //TODO:方便测试,临时取消验证
            // validateData(apiRequest);
            //分发服务
            ServiceHandler handler = dispatchService(apiRequest);
            //业务处理
            String responseData = handler.handle(apiRequest.getData());


            //执行成功
            apiResponse.setData(responseData);
            apiResponse.setExecuteResult(ApiServiceExecuteResultEnum.SUCCESS.name());
        } catch (CustomException ex) {
            //自定义异常处理
            apiResponse.setExecuteResult(ApiServiceExecuteResultEnum.ERROR.name());
            apiResponse.setErrorCode("S00");
            apiResponse.setErrorMessage(ex.getMessage());
        } catch (ApiException ex) {
            //自定义异常处理
            apiResponse.setExecuteResult(ApiServiceExecuteResultEnum.ERROR.name());
            apiResponse.setErrorCode(ex.getErrorCode());
            apiResponse.setErrorMessage(ex.getMessage());
        } catch (Exception ex) {
            //非预期异常处理
            apiResponse.setExecuteResult(ApiServiceExecuteResultEnum.ERROR.name());
            apiResponse.setErrorCode("S99");
            apiResponse.setErrorMessage("未定义异常:" + ex.getMessage());
        } finally {
            //记录请求响应时间
            LocalDateTime responseTime = LocalDateTime.now();
            //记录日志
            recordLog(apiRequest, apiResponse, receiveTime, responseTime);
        }

        return new ResponseEntity<ApiResponse>(apiResponse, HttpStatus.OK);
    }

    /**
     * 记录日志
     *
     * @param apiRequest
     * @param apiResponse
     * @param receiveTime
     */
    private void recordLog(ApiRequest apiRequest, ApiResponse apiResponse, LocalDateTime receiveTime, LocalDateTime responseTime) {
        ApiServiceLog apiServiceLog = new ApiServiceLog();
        apiServiceLog.setAppCode(apiRequest.getAppCode());
        apiServiceLog.setServiceCode(apiRequest.getServiceCode());
        apiServiceLog.setRequestTime(DateUtils.toLocalDateTime(apiRequest.getRequestTime()));
        apiServiceLog.setReceiveTime(receiveTime);
        apiServiceLog.setRequestBusinessData(apiRequest.getData());
        apiServiceLog.setExecuteResult(apiResponse.getExecuteResult());
        apiServiceLog.setErrorCode(apiResponse.getErrorCode());
        apiServiceLog.setErrorMessage(apiResponse.getErrorMessage());
        apiServiceLog.setResponseTime(responseTime);
        apiServiceLog.setResponseBusinessData(apiResponse.getData());
        //计算执行时间
        apiServiceLog.setExecutionTime(Duration.between(receiveTime, responseTime).toMillis());
        //保存
        apiServiceLogService.add(apiServiceLog);

    }

    /**
     * 根据服务代码进行服务分发
     *
     * @param apiRequest
     * @return
     */
    private ServiceHandler dispatchService(ApiRequest apiRequest) {
        String serviceCode = apiRequest.getServiceCode();
        String handlerClass = apiServiceService.lambdaQuery().eq(ApiService::getCode, serviceCode)
                .list().get(0).getHandler();
        try {
            ServiceHandler handler = (ServiceHandler) Class.forName(handlerClass).newInstance();
            return handler;
        } catch (Exception e) {
            throw new ApiException("S60", "未找到该服务对应的处理器");
        }


    }

    //region 数据验证

    /**
     * 数据验证
     *
     * @param apiRequest
     */
    private void validateData(ApiRequest apiRequest) {
        //验证参数
        validateParameter(apiRequest);
        //验证应用
        validateApp(apiRequest);
        //验证服务
        validateService(apiRequest);
        //验证权限
        validatePermission(apiRequest);
        //验证时效
        validateTimeLimitation(apiRequest);
        //验证签名
        validateSign(apiRequest);

    }


    /**
     * 验证参数
     *
     * @param apiRequest api请求
     */
    private void validateParameter(ApiRequest apiRequest) {
        //参数验证
        //验证请求时间
        String requestTime = apiRequest.getRequestTime();
        Calendar validate = TimeValidator.getInstance().validate(requestTime, DateConstant.DATE_FORMAT_FULL);
        if (validate == null) {
            throw new ApiException("S01", "请求时间格式不符合要求");
        }
    }

    /**
     * 验证应用
     *
     * @param apiRequest api请求
     */
    private void validateApp(ApiRequest apiRequest) {
        //获取应用代码
        String appCode = apiRequest.getAppCode();
        //验证
        List<ApiApp> list = apiAppService.lambdaQuery().eq(ApiApp::getCode, appCode).list();
        if (CollectionUtils.isEmpty(list)) {
            throw new ApiException("S10", "应用代码不存在");
        }
        if (list.get(0).getStatus().equals(StatusEnum.DEAD.name())) {
            throw new ApiException("S11", "应用已停用");
        }
    }

    /**
     * 验证服务
     *
     * @param apiRequest api请求
     */
    private void validateService(ApiRequest apiRequest) {
        //获取服务代码
        String serviceCode = apiRequest.getServiceCode();
        //验证
        List<ApiService> list = apiServiceService.lambdaQuery().eq(ApiService::getCode, serviceCode).list();
        if (CollectionUtils.isEmpty(list)) {
            throw new ApiException("S20", "服务不存在");
        }
        if (list.get(0).getStatus().equals(StatusEnum.DEAD.name())) {
            throw new ApiException("S21", "服务已停用");
        }
    }

    /**
     * 验证权限
     *
     * @param apiRequest api请求
     */
    private void validatePermission(ApiRequest apiRequest) {

        //获取应用标识
        String appCode = apiRequest.getAppCode();
        String appId = apiAppService.lambdaQuery().eq(ApiApp::getCode, appCode).list().get(0).getId();
        //获取服务标识
        String serviceCode = apiRequest.getServiceCode();
        String serviceId = apiServiceService.lambdaQuery().eq(ApiService::getCode, serviceCode).list().get(0).getId();

        //验证
        List<ApiServicePermission> list = apiServicePermissionService.lambdaQuery()
                .eq(ApiServicePermission::getAppId, appId)
                .eq(ApiServicePermission::getServiceId, serviceId)
                .list();
        if (CollectionUtils.isEmpty(list)) {
            throw new ApiException("S30", "无权限");
        }
    }

    /**
     * 验证时效
     *
     * @param apiRequest api请求
     */
    private void validateTimeLimitation(ApiRequest apiRequest) {
        //获取请求时间
        String requestTimeString = apiRequest.getRequestTime();
        //转换时间格式
        LocalDateTime requestTime = DateUtils.toLocalDateTime(requestTimeString);
        //获取当前时间
        LocalDateTime now = LocalDateTime.now();
        //获取时间差值
        Duration duration = Duration.between(requestTime, now);
        if (Math.abs(duration.toMinutes()) > VALID_TIME_SPAN) {
            throw new ApiException("S40", "请求时间超出合理范围");
        }

    }

    /**
     * 验证签名
     *
     * @param apiRequest api请求
     */
    private void validateSign(ApiRequest apiRequest) {
        //参数进入map,并自动排序
        TreeMap<String, String> requestDataMap = new TreeMap<>();
        requestDataMap.put("appCode", apiRequest.getAppCode());
        requestDataMap.put("data", apiRequest.getData());
        requestDataMap.put("requestTime", apiRequest.getRequestTime());
        requestDataMap.put("serviceCode", apiRequest.getServiceCode());
        requestDataMap.put("signMethod", apiRequest.getSignMethod());
        //获取密钥
        String appSecret = apiAppService.lambdaQuery().eq(ApiApp::getCode, apiRequest.getAppCode()).list().get(0).getSecret();

        //拼装参数与密钥
        StringBuffer sb = new StringBuffer();
        sb.append(appSecret);
        Iterator<String> iterator = requestDataMap.keySet().iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();
            sb.append(key).append("=").append(requestDataMap.get(key));
        }
        sb.append(appSecret);
        String param = sb.toString();
        // 进行签名
        String sign = DigestUtils.md5Hex(param);
        log.info("签名:{}", sign);
        // 签名比对
        if (!sign.equals(apiRequest.getSign())) {
            throw new ApiException("S50", "签名验证失败");
        }
    }
    //endregion


}

虽然功能是可以实现,但是缺点也很明显,这个类接近300行,包含了众多的业务逻辑,灵活性和扩展性明显是个短板,我们是不是可以借鉴netty优秀的设计思路,采用职责链的设计模式,来实现接口处理器的灵活装配和数据处理呢?

接下来我们将进行这样的改造。

你可能感兴趣的:(接口开放平台设计与实现,接口平台,实战,restful,后端,api)