找回密码
 立即注册
首页 业界区 安全 聚合系统设计:利用泛型来重构三方服务的底层调用 ...

聚合系统设计:利用泛型来重构三方服务的底层调用

梁宁 3 天前
三方服务API接口响应说明

我司通道服务里调用的一个三方服务商,其响应结构如下:
字段名类型描述codeint业务响应的 code 码(非 HTTP 状态码)messagestring返回值的状态描述dataobj业务数据,具体字段参考各 API 接口返回值这个标准化响应格式,大家都比较熟悉。正常响应时,code=200,并将数据结果放到data里。非正常响应时,code是非200的错误码,data为空。

  • 示例
错误响应示例:
  1. {"code": 400, "message": "手机号格式不正确"}
复制代码
  1. {"code":404,"data":null,"message":"订单不存在"}
复制代码
正确响应示例:
  1. {
  2.   "code": 200,
  3.   "data": {
  4.     "orderId": "ORD20250720001",
  5.     "status": "已支付",
  6.     "amount": 299.00
  7.   },
  8.   "message": "订单查询成功"
  9. }
复制代码
  1. {"code":200,"message":"用户签约成功"}
复制代码
与之对应,我们程序里定义了相应的模型类:
  1. @Data
  2. public class SanHeCommonResponse<T> implements Serializable {
  3.     /** 业务响应的code 码(非HTTP 状态码) */
  4.     private Integer code;
  5.     /** 返回值的状态描述 */
  6.     private String message;
  7.    
  8.     /** 业务数据,具体的字段内容参考各个API 接口的返回值 */
  9.     private T data;
  10.     // 判断响应是否成功(code为200时表示成功)
  11.     public boolean isSuccess(){
  12.         return code == 200;
  13.     }
  14. }
复制代码
三方服务底层调用封装——execute方法及实现

三方服务API对接层中,我们将数据加密/签名、http通信、验签/数据解密等通用性功能封装在底层,见下面的execute方法如下。注意,后面我们重点要谈针对这个方法的重构。
  1. /**
  2. * 安**宇服务商接口通信(含请求及响应)封装
  3. */
  4. public static SanHeCommonResponse execute(NewSanHeApiEnum apiEnum, String token) {
  5.     SanHeCommonRequest requestBody = new SanHeCommonRequest();
  6.     requestBody.setNonceStr(RandomUtil.randomString(10));
  7.     requestBody.setData...
  8.     JSONObject requestParams = JSON.parseObject(JSON.toJSONString(requestBody));
  9.     HttpEntity<Object> requestEntity;
  10.     HttpHeaders headers = new HttpHeaders();
  11.     headers.add("x-access-token", token);
  12.     requestEntity = new HttpEntity<>(requestParams, headers);
  13.     RestTemplate restTemplate = new RestTemplate();
  14.     String body;
  15.     try {
  16.         url = url.concat(apiEnum.getUrl());
  17.         ResponseEntity<String> response = restTemplate.exchange(API_URL, HttpMethod.POST, requestEntity, String.class);
  18.         body = response.getBody();
  19.     } catch (Exception ex) {
  20.         log.error("安**宇接口调用异常:", ex);
  21.         throw BizException.build("接口调用异常");
  22.     }
  23.     SanHeCommonResponse sanHeCommonResponse = JSON.parseObject(body, SanHeCommonResponse.class);
  24.     if (!sanHeCommonResponse.isSuccess()) {
  25.         throw BizException.build(sanHeCommonResponse.getCode(), sanHeCommonResponse.getMessage());
  26.     }
  27.     return sanHeCommonResponse;
  28. }
复制代码


execute方法返回值重构

OOP程序设计的一个重要思想是明确对象的职责。
针对这种三方服务对接的需求场景,我们需要把握好一个设计理念:将三方服务调用涉及的数据加密/签名、http通信、验签/数据解密等通用性功能封装在底层,使上层的接口处理方法专注于接口数据的逻辑处理。
这个execute方法在返回值方面存在的问题是:调用方需要通过SanHeCommonResponse.data获取并转换为实际业务数据,这增加了编码成本。
  1. SanHeCommonResponse response = execute(API_ORDER, token);
  2. if (!response.isSuccess()) {
  3.     throw new BizException("查询失败");
  4. }
  5. OrderResponse data = JSON.parseObject(response.getData().toString(), OrderResponse.class);
复制代码
针对返回值方面的这个问题,重构结果如下:
  1. /**
  2. * 安**宇服务商接口通信(含请求及响应)封装
  3. */
  4. public static <T> T SanHeCommonResponse execute(NewSanHeApiEnum apiEnum, String token, Class<T> clazz) {
  5.     ...
  6.    
  7.     SanHeCommonResponse<JSONObject> sanHeCommonResponse = JSON.parseObject(body, new TypeReference<SanHeCommonResponse<JSONObject>>(){});//用`new TypeReference<SanHeCommonResponse<JSONObject>>(){}`来解析带有泛型的响应, 避免IDE类型转换警告。
  8.     if (!sanHeCommonResponse.isSuccess()) {
  9.         throw BizException.build(sanHeCommonResponse.getCode(), sanHeCommonResponse.getMessage());
  10.     }
  11.     return Optional.ofNullable(sanHeCommonResponse.getData())
  12.             .orElse(new JSONObject())
  13.             .toJavaObject(clazz);
  14. }
复制代码
这时,上层调用直接一行代码搞定:
  1. OrderResponse data = execute(API_ORDER, token, OrderResponse.class);
复制代码


重构的目的是使方法更通用,能够直接返回业务数据对象,而不是整个SanHeCommonResponse对象。通过使用泛型,让调用者可以指定期望返回的业务数据类型,将类型安全性提前至编译期,有效增强程序健壮性。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册