Java属性上添加注解,标记其参数别名

小旋风
• 阅读 1788

背景

  在开发过程中,如果第三方接口参数的命名遵循一定的规范,我方在封装请求体时会比较方便和整洁,通常不需要过多的注释。但是如果第三方接口的参数命名非常随意呢?我们知道,如果是POST 请求,我们可以使用 JSONField 。但如果是让我们自己不依赖 fastjson 来完成一个GET请求的字符串拼接呢?

比如:

/api/addUser?NAME=xiaoguaiguai&agenumber=78&sex_flag=0&ji_Guan=东北那旮

  它揉合了多种命名规则并且还包含拼音,这个时候你应该如何保证自己的代码是整洁的呢?

1.定义属性注解

  由于属性对应的参数名称非常随意,我们准备手动记录它,这样呢,我们就需要一个注解:

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(value={ElementType.FIELD})
@Documented
@Inherited
public @interface ThirdApiParamName {

    /**
     * 参数名称
     *
     * @return
     */
    String value();

}

2. 对应参数信息体添加属性注解

  注解使用时非常简单,比如我们有一个UserAddDTO.class,直接进行标记。

@Data
public class UserAddDTO{

    /**
     * 用户名称
     */
    @ThirdApiParamName("NAME")
    private String name;
    /**
     * 用户年龄
     */
    @ThirdApiParamName("agenumber")
    private int age;
    /**
     * 性别标志
     * 0:女
     * 1:男
     */
    @ThirdApiParamName("sex_flag")
    private int sexFlag;
    /**
     * 籍贯
     */
    @ThirdApiParamName("ji_Guan")
    private String nativePlace;
}

  这样写有什么好处呢?假如另外一个人,从日志看到了打印的请求的 url 字符串,发现了一个诡异的参数叫agenumber,他就开始Ctrl+Shift+F搜索,正好发现了这个类,一看你的注释,他就能明白:啊,原来是年龄,他把两个单词写一块了。

3.Java反射解析注解

  下面我们使用反射机制,获取到对应的属性上的注解中填写的值以及属性的值,进行拼接。这一部分我们可以写在工具类里,当然如果你DDD,你可以有自己的考量,我这里只给出函数体:

public static String fulfilledUrlWithParams(String urlPrefix, Object paramObject) {
        try {
            Class<?> aClass = paramObject.getClass();
            Field[] declaredFields = aClass.getDeclaredFields();
            StringBuilder stringBuffer = new StringBuilder(urlPrefix);
            stringBuffer.append("?");
            StringJoiner paramStringJoiner = new StringJoiner("&");
            for (Field declaredField : declaredFields) {
                // 对应每个属性,获取它对应的参数的名称
                declaredField.setAccessible(true);
                Object valueObj = declaredField.get(paramObject);
                if (valueObj == null || StringUtils.isBlank(valueObj.toString())) {
                    continue;
                }
                ThirdApiParamName paramName= declaredField.getAnnotation(ThirdApiParamName.class);
                if (paramName== null) {
                    continue;
                }
                paramStringJoiner.add(paramName.value() + "=" + valueObj);
            }
            stringBuffer.append(paramStringJoiner.toString());
            return stringBuffer.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

  这样,我们就把一个毫无命名规律的第三方接口参数规范化了。这样,我们在封装好了整个请求服务后,开发组内部就是用我们自己写的服务了,而不是各自去面对第三方混乱的接口参数。

  其实这个设计并不难想到,只要你熟悉门面模式、代理模式、适配器模式,你会很自然想到要添加一个中间层,以屏蔽一些麻烦的细节。其实,编程中涉及到设计相关的内容,大部分都是中间层的艺术。

思考题

  接下来,留一个思考题给每一位读者:

在你的项目中,如果是遇到同事之间的接口调用,对方参数命名不规范,你应该怎么做呢?

  欢迎你在评论区留言,和其他读者进行讨论。

点赞
收藏
评论区
推荐文章
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Easter79 Easter79
4年前
tar命令的exclude参数
用tar命令可以在Linux底下进行打包操作,如果要排除某些特定的目录或者文件可以用exclude参数,通常比较好用的有以下几个\excludevcs,这个是将版本控制系统的文件予以排除。\excludepath/to/my/name,这个是将某个路径下的文件夹或者文件予以排除,这个参数有两点需要注意一是如果是文件夹,文件夹名称的末尾
Irene181 Irene181
4年前
浅析Python函数的参数
一、前言Python的函数定义非常简单,但灵活度却非常大。除了正常定义的必选参数外,还可以使用默认参数、可变参数和关键字参数,使得函数定义出来的接口,不但能处理复杂的参数,还可以简化调用者的代码。二、可变参数在Python函数中,还可以定义可变参数。顾名思义,可变参数就是传入的参数个数是可变的,可以是1个、2个到任意个,还可以是0个。案例:请计算a2
Easter79 Easter79
4年前
SpringMVC(五):@RequestMapping下使用@RequestParam绑定请求参数值
在处理方法入参使用@RequestParam可以把请求参数传递给请求方法,@RequestParam包含的属性值:\value:参数名称\required:是否必须,默认为true,表示请求参数中必须包含对应的参数,否则抛出异常。\defaultValue:当请求参数缺少或者有请求参数但值为空时,值采用该设置值。示
Wesley13 Wesley13
4年前
mysql中时间比较的实现
MySql中时间比较的实现unix\_timestamp()unix\_timestamp函数可以接受一个参数,也可以不使用参数。它的返回值是一个无符号的整数。不使用参数,它返回自1970年1月1日0时0分0秒到现在所经过的秒数,如果使用参数,参数的类型为时间类型或者时间类型的字符串表示,则是从1970010100:00:0
Stella981 Stella981
4年前
SpringBoot2 学习10 Controller接收参数的方式
地址传值@PathVariable获取路径参数。即url/{id}这种形式。?传值@RequestParam获取查询参数。即url?name这种形式用注解@RequestParam绑定请求参数到方法入参当请求参数username不存在时会有异常发生,可以通过设置属性requiredfalse解决,例如:@R
Stella981 Stella981
4年前
SpringBoot(20)
  我们在写单元测试的时候,除了接口直接抛异常而导致该单元测试失败外,还有种是业务上的错误也代表着该单元测试失败。好比我们在测试接口的时候,  该接口返回是1代表成功,如果是0那就代表是失败的,这个时候可以考虑使用断言。  一、原理我们知道,我们可以通过断言来校验测试用例的返回值和实际期望值进行比较,以此来判断测试是否通过。那我们先来看下如果失败的情
Easter79 Easter79
4年前
SpringBoot2 学习10 Controller接收参数的方式
地址传值@PathVariable获取路径参数。即url/{id}这种形式。?传值@RequestParam获取查询参数。即url?name这种形式用注解@RequestParam绑定请求参数到方法入参当请求参数username不存在时会有异常发生,可以通过设置属性requiredfalse解决,例如:@R
liam liam
2年前
掌握 Swagger enum 的最佳实践指南
enum是规范中用来定义枚举类型的一种方式。它允许开发者在API文档中明确列出该接口的参数、返回值或请求体中可接受的枚举值。通过使用Swaggerenum,开发者可以更清晰地描述API的输入和输出,提高API文档的可读性和可维护性。enum使用场景在以下情
四、飞鹅后端管理系统API接口文档
接口列表1.服务健康检查请求方法:GET请求URL:/api/health请求参数无返回结果json"code":1,"message":"success"2.用户登录请求方法:POST请求URL:/api/admin/access/login请求参数(f
五、飞鹅官网API接口文档
接口列表1.获取网站信息请求方法:GET请求URL:/api/site/getSiteInfo请求参数无返回结果json"code":1,"data":"id":1,//id"title":"SampleSiteName",//网站名称"intro":"T