ef 在此上下文中只支持基本类型或枚举类型_架构实战(3)——优雅的使用枚举

本人负责一个项目上线了,非常开心。这个项目是To C的,未来应用的访问压力较大,并且要求高可用性,提供7*24小时的不间断服务。根据项目的业务需求以及团队情况,采用Spring Cloud微服务架构。把用到的技术,和解决的技术问题,做一个总结。

在Java应用程序的开发中,枚举是经常被用到的功能,常常被用来约束几个特定的值,例如状态、类型、性别等。在我们的应用中,也大量应用了枚举,并且做了一些的改进,以期能够更优雅的使用枚举。

在Java中,枚举是用enum关键字来定义的。对其使用的过程中,做了更强的约束,定义了所有枚举必须实现的接口,BaseEnum,要求必须满足有value和desc两个值。value表示真实的值,desc表示其描述。

53fc7544cad5721677b4efc0ce52d53a.png

用法非常简单,实现BaseEnum接口,并指定value和desc的类型就可以了。以性别的枚举为例:

355ebc9364bcce2b5f6e2f5eab160039.png

优雅的使用枚举,需要解决四个问题:

一、枚举型数据的存储和读取,能够把value存储到表中的字段,并且在读取数据的时候,能够正确映射到实体类(entity)的属性。

二、枚举型数据的能够在前端被简单的使用。数据要通过json的方式输出到前端,前端如何才能更简单有效的使用枚举,至关重要。

三、枚举型数据的接收。前端或者其他调用方,通过枚举值调用服务,服务能够正确的接收到枚举。

四、枚举型数据的缓存,能够正确的从redis中读写。能够解决上述4个问题,就能保证枚举在服务内部、服务之间以及前后端之间正确传递,就像使用Integer、String一样简单的使用枚举值。

一、枚举型数据的存储和读取。

数据库的读写是采用MyBatis框架实现的,并且应用了一个插件,是baomidou。这个插件确实非常值得推荐,对entity的CURD提供了默认支持。更重要的是,也提供了对枚举的支持,只需要实现IEnum接口就可以了。getValue的值,就是存储到数据库字段的值。

2f76720569474bb90489b58161b8ba45.png

再来看一下我定义的BaseEnum接口,是继承了IEnum接口的,也就是说,实现BaseEnum接口的枚举,都默认实现了IEnum接口。

如果没有用到baomidou插件怎么办?MyBatis提供了对类型的扩充机制,下一节《优雅的使用字典》中详细描述。

二、枚举值的前端应用。前端对枚举值的应用,无外乎展示和编辑/选取两种场景。

展示场景非常简单,在页面上正确展示描述(desc值)就可以了。比较一般的做法就是,给前端返回value值,前端根据value值替换desc进行展示。这样做前端工作量有点儿大,如果后端的枚举值有变动,前端的代码需要同步进行调整。我的解决方案就是,在输出给前端数据的时候,把value和desc两个字段同时写在json文档中。前端的同学拿到数据直接使用即可,避免了转换的过程。

810ca8828fd4dd4843163dcb0e755a16.png

输出结果如上所示,性别(gender)字段在json中变成了两个字段,约定好xxTitle就是这个字段的描述(desc)值。

是怎么做到的呢?这就要感谢jackson了。jackson提供了对序列化的扩展能力,可以实现自定义的序列化。并且在配置中,使用jackson作为默认的消息转换器。看到这里,应该算是打开了一扇大门,通过这种方法,可以自定义特定类型数据的实例化。我把关键代码粘贴出来。

63725c3e6236903ca91a39b240cdb7f5.png
f91b392d46c53f6468640233d4178fc9.png

再来看一下编辑/选取的场景。我截图了微信公众号的后台,看下状态字段,有3种状态,这里就可以用枚举来实现。最直接的方法,就是前后端的工程师同时定义枚举,并约定好取值,看似非常简单。随着枚举值的增多,前后端需要保持一致,任何变动都要事先沟通,后端工程师做了修改,前端工程师必须同步修改。事情就这样变得越来越烦琐复杂。

e33521b73e9cc6d3af3039ccfbaa25df.png

有没有简单容易一些的方法呢?我的解决方案是给前端提供一个接口,输出所有的枚举定义,前端只需根据枚举的编码,选用适当的枚举就可以了。看下效果:

cd5bc3c7d3e020cda25575119d20a64b.png

怎么实现的呢?这里的实现逻辑类似于MapperScan,即定义好扫描的package,在这个package中的所有枚举,组成一个list,然后定义controller,输出这个list就可以了。具体的代码逻辑有些复杂,这里就不展开了。

三、枚举型数据的接收。在java程序接收参数的时候,对于Post提交的json字符串,是采用了jackson提供的逆序列化能力。并且呢,jackson默认就提供了对枚举的支持,并不需要自定义逆序列化方式。具体就是@JsonCreator注解。

64300ede8c0744dc79bf2aaf0758f059.png

对于Get提交的数据,或者post form提交的数据,该如何处理呢?我的方案是,自定义自己的@FormParam注解,此注解可以把get参数、post form参数以及json字符串,组装在一起,通过jackson转换成特定的VO。这样就完美解决了传入参数中枚举值的转换。

四、枚举型数据的缓存。数据的缓存,是存储到redis的。通过上面的介绍,已经知道jackson对枚举的序列化、逆序列化都有了很好的支持。缓存也是一样的道理,只要解决这两个过程就好了。存储和读取数据的时候,统一约定好用如下定义的ObjectMapper就可以了。

64c1d7f90517e4263919fb786785019e.png

通过上面的介绍,在整个应用过程中,枚举类型的数据就像Integer、String等一样,被优雅的使用。在这个过程中,解决问题的核心出发点,是序列化和逆序列化。我这里采用了jackson作为json的序列化工具包,如果采用其他工具包,也应有类似的解决方案。

后续的内容可能有:

  1. 优雅的使用字典
  2. 自实现的接口代理
  3. 读写分离
  4. 分布式ID
  5. 使用缓存
  6. 使用队列
  7. 使用retry
  8. eureka安全模式
  9. 。。。
e9237d271817571a83762ae4b7301834.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值