范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

利用注解反射消除重复代码,妙

  1.1 案例场景
  假设银行提供了一些 API 接口,对参数的序列化有点特殊,不使用 JSON,而是需要我们把参数依次拼在一起构成一个大字符串:
  1)按照银行提供的API文档顺序,将所有的参数构成定长的数据,并且拼接在一起作为一整个字符串
  2)因为每一种参数都有固定长度,未达到长度需要进行填充处理 字符串类型参数不满长度部分要以下划线右填充,即字符串内容靠左 数字类型的参数不满长度部分以0左填充,即实际数字靠右 货币类型的表示需要把金额向下舍入2位到分,以分为单位,作为数字类型同样进行左填充 参数做MD5 操作作为签名 1.2 初步代码实现public class BankService {      //创建用户方法     public static String createUser(String name, String identity, String mobile, int age) throws IOException {         StringBuilder stringBuilder = new StringBuilder();         //字符串靠左,多余的地方填充_         stringBuilder.append(String.format("%-10s", name).replace(" ", "_"));         //字符串靠左,多余的地方填充_         stringBuilder.append(String.format("%-18s", identity).replace(" ", "_"));         //数字靠右,多余的地方用0填充         stringBuilder.append(String.format("%05d", age));         //字符串靠左,多余的地方用_填充         stringBuilder.append(String.format("%-11s", mobile).replace(" ", "_"));         //最后加上MD5作为签名         stringBuilder.append(DigestUtils.md2Hex(stringBuilder.toString()));         return Request.Post("http://localhost:45678/reflection/bank/createUser")                 .bodyString(stringBuilder.toString(), ContentType.APPLICATION_JSON)                 .execute().returnContent().asString();     }      //支付方法     public static String pay(long userId, BigDecimal amount) throws IOException {         StringBuilder stringBuilder = new StringBuilder();         //数字靠右,多余的地方用0填充         stringBuilder.append(String.format("%020d", userId));         //金额向下舍入2位到分,以分为单位,作为数字靠右,多余的地方用0填充         stringBuilder.append(String.format("%010d", amount.setScale(2, RoundingMode.DOWN).multiply(new BigDecimal("100")).longValue()));         //最后加上MD5作为签名         stringBuilder.append(DigestUtils.md2Hex(stringBuilder.toString()));         return Request.Post("http://localhost:45678/reflection/bank/pay")                 .bodyString(stringBuilder.toString(), ContentType.APPLICATION_JSON)                 .execute().returnContent().asString();     } }
  这样做能够基本满足需求,但是存在一些问题: 处理逻辑互相之间有重复,稍有不慎就会出现Bug 处理流程中字符串拼接、加签和发请求的逻辑,在所有方法重复 实际方法的入参的参数类型和顺序,不一定和接口要求一致,容易出错 代码层面参数硬编码,无法清晰进行核对 1.3 使用接口和反射优化代码1.3.1 实现定义了所有接口参数的POJO类@Data public class CreateUserAPI {     private String name;     private String identity;     private String mobile;     private int age; } 1.3.2 定义注解本身@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Inherited public @interface BankAPI {     String desc() default "";     String url() default ""; }   @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) @Documented @Inherited public @interface BankAPIField {     int order() default -1;     int length() default -1;     String type() default ""; } 1.3.3 反射配合注解实现动态的接口参数组装private static String remoteCall(AbstractAPI api) throws IOException {     //从BankAPI注解获取请求地址     BankAPI bankAPI = api.getClass().getAnnotation(BankAPI.class);     bankAPI.url();     StringBuilder stringBuilder = new StringBuilder();     Arrays.stream(api.getClass().getDeclaredFields()) //获得所有字段             .filter(field -> field.isAnnotationPresent(BankAPIField.class)) //查找标记了注解的字段             .sorted(Comparator.comparingInt(a -> a.getAnnotation(BankAPIField.class).order())) //根据注解中的order对字段排序             .peek(field -> field.setAccessible(true)) //设置可以访问私有字段             .forEach(field -> {                 //获得注解                 BankAPIField bankAPIField = field.getAnnotation(BankAPIField.class);                 Object value = "";                 try {                     //反射获取字段值                     value = field.get(api);                 } catch (IllegalAccessException e) {                     e.printStackTrace();                 }                 //根据字段类型以正确的填充方式格式化字符串                 switch (bankAPIField.type()) {                     case "S": {                         stringBuilder.append(String.format("%-" + bankAPIField.length() + "s", value.toString()).replace(" ", "_"));                         break;                     }                     case "N": {                         stringBuilder.append(String.format("%" + bankAPIField.length() + "s", value.toString()).replace(" ", "0"));                         break;                     }                     case "M": {                         if (!(value instanceof BigDecimal))                             throw new RuntimeException(String.format("{} 的 {} 必须是BigDecimal", api, field));                         stringBuilder.append(String.format("%0" + bankAPIField.length() + "d", ((BigDecimal) value).setScale(2, RoundingMode.DOWN).multiply(new BigDecimal("100")).longValue()));                         break;                     }                     default:                         break;                 }             });     //签名逻辑    stringBuilder.append(DigestUtils.md2Hex(stringBuilder.toString()));     String param = stringBuilder.toString();     long begin = System.currentTimeMillis();     //发请求     String result = Request.Post("http://localhost:45678/reflection" + bankAPI.url())             .bodyString(param, ContentType.APPLICATION_JSON)             .execute().returnContent().asString();     log.info("调用银行API {} url:{} 参数:{} 耗时:{}ms", bankAPI.desc(), bankAPI.url(), param, System.currentTimeMillis() - begin);     return result; }
  通过反射来动态获得class的信息,并在runtime的时候完成组装过程。
  这样做的好处是开发的时候会方便直观很多,然后将逻辑与细节隐藏起来,并且集中放到了一个方法当中,减少了重复,以及维护当中bug的出现。 1.3.4 在代码中的应用@BankAPI(url = "/bank/createUser", desc = "创建用户接口") @Data public class CreateUserAPI extends AbstractAPI {     @BankAPIField(order = 1, type = "S", length = 10)     private String name;     @BankAPIField(order = 2, type = "S", length = 18)     private String identity;     @BankAPIField(order = 4, type = "S", length = 11) //注意这里的order需要按照API表格中的顺序     private String mobile;     @BankAPIField(order = 3, type = "N", length = 5)     private int age; }    @BankAPI(url = "/bank/pay", desc = "支付接口") @Data public class PayAPI extends AbstractAPI {     @BankAPIField(order = 1, type = "N", length = 20)     private long userId;     @BankAPIField(order = 2, type = "M", length = 10)     private BigDecimal amount; }

农业掀起上链潮区块链等数字技术正成为乡村振兴新动力本报记者李冰目前区块链等数字技术已经广泛应用于农业全链条环节。近日,由中国宏观经济研究院课题组撰写的数字技术赋能乡村产业发展报告(下简称报告)指出,长期以来困扰乡村产业发展的难点堵宇信科技在数字人民币第二第三第四环节都有参与王方圆中国证券报中证网中证网讯(记者王方圆)1月24日晚间,宇信科技在深交所互动易平台透露,数字人民币有四个环节,第一个是发行环节,由央行负责第二个是数字人民币运营,包括国有大型银数科日报丨阿里回应优酷股东变更商汤人工智能计算中心启动运营01丨阿里回应优酷股东变更内部正常调整1月24日,阿里文娱回应优酷股东变更一事称,系内部正常调整,阿里通过旗下阿里文娱全资子公司上海全土豆网络科技有限公司继续持股优酷。此前,媒体报吉林大学化学学院刘小孔教授团队在太阳光热除冰领域取得重要进展来源吉网日前,吉林大学化学学院超分子结构与材料国家重点实验室刘小孔教授研究团队在太阳光热除冰领域取得重要进展,近日,该研究成果被美国化学学会旗下的化学与工程新闻杂志(Chemica微单拍摄镜头和摄影技巧方面的一些干货知识分享,三天成为高手对于喜欢影像的朋友来说,仅仅有一台能够满足自己需求的好微单机身是远远不够的,还必须懂得一些摄影技巧以及如何选择符合拍摄要求的镜头,只有这三方面都具备一定的基础,才能真正拍出令人羡慕国内首家,玲珑自修复静音一体轮胎问世导读兼具防爆安全与静音舒适,玲珑推出国内首款自修复静音一体轮胎。玲珑轮胎又一次实现技术突破,将自修复功能与静音棉功能通过先进工艺复合在一起,实现防爆安全与静音舒适相结合,成为国内首小米12UItra渲染图再曝!设计惊喜,影像是重头戏?小米12UItra算是当下很多用户最为期待的一款机型之一,上一代的小米11UItra的确让不少用户为之惊喜,近日,有博主更是曝光了一组关于小米12UItra的渲染图,其究竟会有哪些小米MIX5MIXFold2屏幕参数曝光素质前所未有1月24日早,数码博主数码闲聊站在微博曝光了小米两款高分屏骁龙8旗舰的消息,很大可能暗指的是小米MIX5以及小米MIXFold2。配置如下小米MIX56。7英寸2K屏幕,支持120小米Max5曝光,7。2英寸大屏加持,售价将是最大惊喜似乎是从去年开始,手机市场有了小屏旗舰的风向,也有手机厂商推出了小屏手机,但效果都非常的一般,销量平平无奇。就拿苹果来说,在爆料将会有iPhone12mini的时候,大家的呼声非常你以为的亮度可能不适合孩子,这款智能灯能输出因人而异的亮度现在导致近视的原因很多,除了数码产品外,灯光环境和用眼习惯都是潜在的导致近视的因素,比如做作业的环境光线过亮或过暗,就会对孩子的视力造成影响。所以,很多家长都会给孩子选择一款护眼的比特币的价格近期波动明显,属于正常现象吗?根据欧易OKX数据显示,今日比特币的价格是35,107。50美元,比特币的价格还在呈小幅度下跌状态,大家要保证好良好的心理状态,要明白比特币的价格跌跌涨涨是很正常的现象。在比特币期
未来之星!小米手机拿下欧洲第二!一季度出货量将近五千万部现在国内手机厂商都在扩展国外市场,因为现在是5g时代,不管是国内用户,还是海外用户,都在尽量更换5g手机。在欧洲智能手机配置一般,但是价钱很高。而国内手机品牌比如小米手机就以高配置瑞典先排除华为,后脚爱立信却拟参与中国5G!我国瑞应纠正错误环球时报5月10日的报道指出,在近日我国四大电信运营商中国电信联通移动广电组织的5G设备测试,除了华为中兴通讯诺基亚等企业以外,瑞典电信设备供应商爱立信也参与其中。不过,消息人士却携手共赢德勤中国华为展现出别样的生态聚合力毋庸置疑,当前数字化转型趋势正在不断加快,可以看到,在越来越多的行业当中,由数字化转型而带来的变革机遇逐渐增多,如果我们从客户视角来看,从过去单纯的产品购买需求已经转变成将产品解决有哪些冷门却文艺的手机app?有调君给大家推荐一些文艺且实用的APP,希望给大家的生活带来更多乐趣ZEROiOSAndroid五一小长假,肯定少不了发微博朋友圈,每个有想法的调友一定会仔细斟酌字字珠玑,并且不断数科日报货拉拉启动造车华为鸿蒙商标申请被驳回01货拉拉启动造车项目,已开始招募新能源货车制造人才货拉拉开始启动造车项目,以实现物流链条闭环和车的数智化,目前已开始招募新能源货车制造方面的人才,包括新能源货车整车产品专家等职位到底是选择iPhone11还是iPhone12,这里给你个明确的答案身边经常有不少同事问我,到底是选择iPhone11好,还是iPhone12?如果是去年的话,我可能会很肯定地回答,选择iPhone11,主要是iPhone11价格更便宜,性价比高。懒到家的超市代购从零售商家的后台到前台一逛超市就发愁的人有福了,今后也许会有人情愿替你逛,然后送货上门。互联网的触角正在以惊人的速度渗透到商业的每个旮旯。关于传统商超来说,每个细节都存在革新的也许。即买送得到营业执照开支付宝数字人民币入口在哪数字人民币怎么申请开通支付使用介绍5月8日,数字人民币App更新,钱包运营机构中的网商银行(支付宝)已呈现可用状态。那么支付宝数字人民币在哪里呢?下面给大家介绍支付宝数字人民币位置。支付宝数字人民币位置打开支付宝A狗币升天,屎币出道!不务正业的马斯克,还能忽悠多久?益学堂寄语全心全意为股民服务是创办益学的初衷,构建属于自己的知识体系和思维框架是塑造投资能力的起点。一hr前有川普推特治国,后有马斯克推特带货。这个马斯克,真是往越来越荒诞的方向走在得物买的货,得物却鉴定为假货小丑到底是谁?花朵财经原创得物App是一家可以做真假鉴别的平台。年轻人喜欢把买到的球鞋潮服箱包手表等物品拿到得物App上进行交易鉴定。就是把物品的各项细节拍照上传,由得物App平台首款搭载鸿蒙OS华为WATCHGT2Pro已上架高德地图鸿蒙版App5月9日,华为鸿蒙系统2。0第二批公测已经上线,相信大部分网友的华为手机都已经被推送了鸿蒙系统,那么鸿蒙系统不仅仅是手机适用,前段时间华为卖车热潮中的新能源汽车也是预装了万物互联的