前端下拉列表后端处理方式

在实际项目开发中经常会遇到前端下拉列表和后端交互的方式,这样的有两种实现解决方案。第一种是前后端约定好,前端写死,不好的地方就是发生变动,前后端都要重新发版上线,耦合性太高;还有一种就是全权委托给后端处理,下拉列表数据也是后端处理好给到前端,如果发生变动只需要后端发版即可。对于灵活性、可维护性肯定是第二种更好一点,这里就会涉及到后端如何存储这些下拉列表数据,数据库存储还是枚举?

数据库存储还是枚举

这个问题其实很简单,看项目的需求,这样说法很敷衍,但是事实也是这样的,如果这些下拉列表项经常变,数据库维护会更好点,方便维护,这个时候如果用枚举就会出现修改需要重新上线的问题,另外这种方式在使用过程中会出现频繁的访问数据库获取和比对列表键值的问题,当然这里就可以使用缓存来解决,对于集群或者分布式系统就需要使用非关系型数据库来协助完成,扯多了,总的来说,这种方式复杂度高,技术要求高。

相反对于不经常变或者就是固定的下拉列表,使用枚举就很好。但是这里存在一个问题,后端不可能针对每个枚举类给出一个接口,提供下拉列表的返回,这里必须要考虑使用一个接口兼容,那怎么去做?

关于使用数据库的方式就不多做解释,本文主题是基于枚举方式解决方案展开说明。

后端单个接口提供所有枚举列表实现

下面以订单状态来模拟,前端需要根据订单不同状态来查询订单列表。

枚举定义

  • 普通的枚举:正常的一个订单状态的定义,里面有三个值,分别是未支付、已支付、已发货。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.itcrud.common.enums;
//订单状态
public enum StatusEnum {
UNPAID(1,"未支付"),
PAID(2,"已支付"),
DELIVERED(3,"已发货");

private int code;
private String name;

public StatusEnum(){}
public StatusEnum(int code,String name){
this.code = code;
this.name = name;
}
public int getCode(){
return this.code;
}
public String getName(){
return this.name;
}
}
  • 枚举列表集合:这个里面会列出需要返回给前端的枚举列表。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.itcrud.common.enums;
//枚举列表集合
public enum EnumListEnum {

E01("E01","com.itcrud.common.enums.StatusEnum","订单状态");

private String code;
private String path;
private String desc;

public EnumListEnum(){}
public EnumListEnum(String code,String path,String desc){
this.code = code;
this.path = path;
this.desc = desc;
}

public static EnumListEnum getByCode(String code){
for(EnumListEnum element : EnumListEnum.values()){
if(element.getCode().equals(code)) return element;
}
return null;
}

public String getCode(){
return this.code;
}
public String getPath(){
return this.path;
}
public String getDesc(){
return this.desc;
}
}

核心处理服务

处理逻辑代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* enumCode是前端获取列表传入的值,指定所需要获取的列表
* 如果传入的是"E01",获取的就是订单状态的列表
*/
public List<EnumListVO> enumList(String enumCode){
EnumListEnum element = EnumListEnum.getByCode(enumCode);
try{
Class<Enum> enumDemo = (Class<Enum>) Class.forName(element.getPath());
Method nameMethod = enumDemo.getMethod("getName");
Method codeMethod = enumDemo.getMethod("getCode");
Enum[] elements = enumDemo.getEnumConstants();
List<EnumListVO> enums = Lists.newArrayList();//EnumListVO是返回给前端数据封装的对象
for (Enum element : elements) {
enums.add(new EnumListVO((int) codeMethod.invoke(element),
(String) nameMethod.invoke(element)));
}
return enums;
}catch(Exception ex){
//异常处理
}
}

处理逻辑很简单思路如下:

  • 通过前端指定的enumCode在枚举列表集合中找到对应的枚举类全限定类名
  • 根据全限定类名获取对应枚举类的Class对象,反射获取里面的getCodegetName方法
  • 使用Class对象调用getEnumConstants()方法获取里面所有枚举对象(每个枚举项就是一个对象)
  • 遍历所有枚举对象,使用之前获取的getCodegetName方法,获取对应的值和名称,值是前后端交互使用,名称是用来给用户展示
  • 将遍历的结果封装返回(封装结构根据实际需求来)

后续枚举项或新枚举类操作

  • 添加、修改、删除枚举项

    这个很简单,在枚举类里面直接操作枚举项即可,这个时候前端完全无感知的,页面刷新,一切都是最新,无需跟后端一起发版,解决约定写死的耦合性问题

  • 添加枚举类

    首先是添加具体的枚举类,然后就是在枚举列表集合中添加对应的枚举类配置。如下:

    1
    E02("E02","com.itcrud.common.enums.NewEnum","新增枚举");

    前端在调用获取列表接口时,将传入的参数变为”E02”即可。

    这里在上线的时候前后端都需要一起发版,对于前后端来说都有新加的内容,并非耦合性问题,对于数据库维护也一样,新增了下拉列表,前端必然有改动,需要发版。

总结

  • 一个枚举列表集合配合一个接口就可以完成需求;
  • 使用需要注意,枚举的键值命名都是要用codename,否则反射获取不到对应的值,这是一个不好的地方,但是基本使用枚举都可以满足这个要求,只是统一名称定义规范问题而已,可以忽略;
  • 修改枚举类中的枚举项,前端无需做任何变动,只涉及后端项目发版,解决约定写死的耦合性问题;
  • 最后需要说明的是上面所有代码都是手敲的,没有放在编辑器里面验证语法,逻辑理解就好,直接复制报错也是正常的。

微信公众号


本文作者:IT-CRUD
原文地址:http://blog.itcrud.com/blogs/2020/07/enum-select-list
版权归作者所有,转载请注明出处

支付宝 微信

如果文章对你有帮助,欢迎点击上方按钮打赏作者