这里主要介绍下MybatisPlus的枚举配置以及枚举使用的规范
枚举使用规范
- 前后端交互直接使用枚举值, 如”SAVED”, 而不应该使用int/String类型, 如1.”1”,”已保存”等
- 实体类中的枚举应直接使用枚举类型, 而不是int常量
(在
- 方法传参同上, 应直接使用枚举类型
MybatisPlus配置
官方文档: https://baomidou.com/guide/enum.html#jackson
定义顶层枚举接口继承IEnum接口, 重写getValue()方法
/*** 枚举顶层接口** @author xinzhang* @date 2020/8/14 16:15*/public interface CaptionEnum extends IEnum<Integer> {/*** 说明文字** @return string*/String caption();}
后续定义枚举都需要实现顶层接口 ```java /**
- 性别 *
- @author xinzhang
@date 2020/8/19 16:15 */ public enum Gender implements CaptionEnum { MALE(“男”, 0), FEMALE(“女”, 1);
private final String caption; private final int value;
Gender(String caption, int value) { this.caption = caption; this.value = value; }
@Override public String caption() { return this.caption; }
@Overridepublic Integer getValue() {return this.value;}
}
2. 配置枚举文件夹路径示例: application.yml```javamybatis-plus:type-enums-package: top.xinzhang0618.buge.enums
这俩配置完后即定义好了枚举类型在代码与数据库之间的交互
枚举统一访问接口
系统中的枚举, 应该提供统一访问的接口, 前端根据接口封装枚举选择器
补充: 对于数据字典, 同样也应该提供统一访问的接口
EnumController
package top.xinzhang0618.buge.service.controller;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import top.xinzhang0618.buge.core.Assert;import top.xinzhang0618.buge.core.enums.CaptionEnum;import top.xinzhang0618.buge.core.util.StringUtils;import top.xinzhang0618.buge.service.exception.RestException;import top.xinzhang0618.buge.vo.EnumVO;import java.lang.reflect.Method;import java.util.*;import java.util.concurrent.ConcurrentHashMap;/*** 枚举控制器** @author xinzhang* @date 2020/8/25 16:57*/@RestController@RequestMapping("/enum")public class EnumController {private static final Map<Class<?>, List<EnumVO>> ENUM_CACHE = new ConcurrentHashMap<>();private static final String ENUM_PACKAGE_PREFIX = "top.xinzhang0618.buge.enums.";private static final String VALUES = "values";@GetMapping("/{name}")public List<EnumVO> list(@PathVariable("name") String enumName) {List<EnumVO> list;try {Class<?> aClass = Class.forName(ENUM_PACKAGE_PREFIX + enumName);list = ENUM_CACHE.computeIfAbsent(aClass, v -> new ArrayList<>());if (!Assert.isEmpty(list)) {return list;}Method method = aClass.getMethod(VALUES);CaptionEnum[] captionEnums = (CaptionEnum[]) method.invoke(null);Arrays.stream(captionEnums).forEach(c -> list.add(new EnumVO(c)));} catch (Exception e) {throw new RestException(StringUtils.format("enum: {0} not found!", enumName));}return list;}}
20210816更新, 优化EnumController, 结合spring的包扫描, 使enumPackage支持通配符以及子文件夹
/*** 枚举控制器** @author xinzhang* @date 2020/8/25 16:57*/@RestController@RequestMapping("/enum")public class EnumController {private static final Map<Class<?>, List<EnumVO>> ENUM_CACHE = new ConcurrentHashMap<>();/*** 枚举包, 支持在该包下建立子包, 支持通配符*/private static final String ENUM_PACKAGE = "top.xinzhang0618.buge";private static final ResourcePatternResolver RESOURCE_PATTERN_RESOLVER = new PathMatchingResourcePatternResolver();private static final MetadataReaderFactory METADATA_READER_FACTORY = new CachingMetadataReaderFactory();/*** 查询枚举值列表* @param enumName 枚举名不能重复* @return*/@GetMapping("/{name}")public List<EnumVO> list(@PathVariable("name") String enumName) {List<EnumVO> list;try {Resource resource = RESOURCE_PATTERN_RESOLVER.getResource(ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(ENUM_PACKAGE) + "/**/" + enumName + ".class");ClassMetadata classMetadata = METADATA_READER_FACTORY.getMetadataReader(resource).getClassMetadata();Class<?> aClass = Class.forName(classMetadata.getClassName());list = ENUM_CACHE.computeIfAbsent(aClass, v -> new ArrayList<>());if (!Assert.isEmpty(list)) {return list;}Method method = aClass.getMethod("values");CaptionEnum[] captionEnums = (CaptionEnum[]) method.invoke(null);Arrays.stream(captionEnums).forEach(c -> list.add(new EnumVO(c)));} catch (Exception e) {throw new RestException(StringUtils.format("enum: {0} not found!", enumName));}return list;}}
EnumVO
@Getter@Setterpublic class EnumVO {private String title;private String caption;private Integer value;public EnumVO(CaptionEnum captionEnum) {this.setCaption(captionEnum.caption());this.setValue(captionEnum.getValue());this.setTitle(captionEnum.toString());}}
接口示例:
GET http://39.106.55.179:30001/enum/ImageType{"code": 0,"msg": "","result": [{"caption": "系统图标","title": "SYSTEM_ICON","value": 1},{"caption": "活动图","title": "ACTIVITY_IMAGE","value": 2},{"caption": "二维码","title": "QR_CODE","value": 3}],"successs": true}
前端
前端统一封装枚举选择器,vue+ant Design 示例代码如下:
api.js
import { AxiosWrapper } from "@/lib/axios.wrapper";export class EnumApi {static enumMap = new Map();static enumPending = new Map();static async getEnum(enumName) {if (this.enumMap.has(enumName)) {return new Promise(resolve => {return resolve(this.enumMap.get(enumName));});} else {let promise;if (this.enumPending.has(enumName)) {promise = this.enumPending.get(enumName);} else {promise = AxiosWrapper.get(`/enum/${enumName}`);this.enumPending.set(enumName, promise);}let data = await promise;const valueMap = new Map();for (const item of data) {valueMap.set(item.title, item);}this.enumMap.set(enumName, valueMap);return new Promise(resolve => {return resolve(valueMap);});}}}
enum.selector.vue
<template><a-selectv-if="multiple"v-model="selectedValue"mode="multiple"style="width: 100%"><a-select-optionv-for="item in map.values()":key="item.value":value="item.title">{{ item.caption }}</a-select-option></a-select><a-radio-group v-else v-model="selectedValue"><a-radio-buttonv-for="item in map.values()":key="item.value":value="item.title">{{ item.caption }}</a-radio-button></a-radio-group></template><script>import { Selector } from "@/lib/mixins";import { EnumApi } from "./api";export default {mixins: [Selector],props: {enumName: {type: String,required: true},notShow: {type: String,default: null}},data() {return {map: new Map()};},created() {this.init();},methods: {async init() {EnumApi.getEnum(this.enumName).then(data => {if (data) {const dataMap = new Map();data.forEach(element => {if (element.title !== this.notShow) {dataMap.set(element.title, element);}});this.map = dataMap;}});}}};</script>
enum.text.vue
<template><span>{{ text }}</span></template><script>import { EnumApi } from "./api";export default {props: {enumName: {type: String,required: true},value: String},data() {return {text: "",valueMap: null};},watch: {value(val) {this.mapText(val);}},created() {this.init();},methods: {async init() {this.valueMap = await EnumApi.getEnum(this.enumName);this.mapText(this.value);},mapText(value) {if (this.valueMap && value) {this.text = this.valueMap.get(value).caption;} else {this.text = "";}}}};</script>
使用示例:
选择器
<a-col :span="6"><ty-search-item label="投放状态"><ty-enum-selectorv-model="searchQuery.publishStatus"multipleenumName="PublishStatus"@change="searchPublish"></ty-enum-selector></ty-search-item></a-col>
列表字段转换
<template v-slot:publishType="record"><ty-enum-textenum-name="PublishType":value="record.publishType"></ty-enum-text></template>
