美文网首页
在Swagger中显示枚举值

在Swagger中显示枚举值

作者: AC编程 | 来源:发表于2022-11-06 10:25 被阅读0次

    一、实现代码

    1.1 自定义注解
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface SwaggerDisplayEnum {
    
        String valueName() default "value";
    
        String descName() default "desc";
    }
    
    1.2 Swagger配置拦截自定义注解
    import com.fasterxml.classmate.ResolvedType;
    import com.google.common.base.Optional;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.context.annotation.Primary;
    import org.springframework.core.annotation.AnnotationUtils;
    import springfox.documentation.builders.ModelPropertyBuilder;
    import springfox.documentation.schema.Annotations;
    import springfox.documentation.spi.DocumentationType;
    import springfox.documentation.spi.schema.ModelPropertyBuilderPlugin;
    import springfox.documentation.spi.schema.contexts.ModelPropertyContext;
    import springfox.documentation.swagger.schema.ApiModelProperties;
    
    import java.lang.reflect.Field;
    import java.util.Arrays;
    import java.util.List;
    import java.util.Objects;
    import java.util.stream.Collectors;
    
    /**
     * @author Alan Chen
     * @description
     * @date 2022/11/1
     */
    //@Component
    @Primary
    @Slf4j
    public class SwaggerDisplayConfig implements ModelPropertyBuilderPlugin {
    
        @Override
        public void apply(ModelPropertyContext context) {
            //获取当前字段的类型
            final Class fieldType = context.getBeanPropertyDefinition().get().getField().getRawType();
    
            //为枚举字段设置注释
            descForEnumFields(context, fieldType);
        }
    
        /**
         * 为枚举字段设置注释
         */
        private void descForEnumFields(ModelPropertyContext context, Class fieldType) {
            Optional<ApiModelProperty> annotation = Optional.absent();
    
            if (context.getAnnotatedElement().isPresent()) {
                annotation = annotation
                        .or(ApiModelProperties.findApiModePropertyAnnotation(context.getAnnotatedElement().get()));
            }
            if (context.getBeanPropertyDefinition().isPresent()) {
                annotation = annotation.or(Annotations.findPropertyAnnotation(
                        context.getBeanPropertyDefinition().get(),
                        ApiModelProperty.class));
            }
    
            //没有@ApiModelProperty 或者 notes 属性没有值,直接返回
            if (!annotation.isPresent() || StringUtils.isBlank((annotation.get()).notes())) {
                return;
            }
    
            //@ApiModelProperties中的notes指定的class类型
            Class rawPrimaryType;
            try {
                rawPrimaryType = Class.forName((annotation.get()).notes());
            } catch (ClassNotFoundException e) {
                //如果指定的类型无法转化,直接忽略
                return;
            }
    
            //如果对应的class是一个@SwaggerDisplayEnum修饰的枚举类,获取其中的枚举值
            Object[] subItemRecords = null;
            SwaggerDisplayEnum swaggerDisplayEnum = AnnotationUtils
                    .findAnnotation(rawPrimaryType, SwaggerDisplayEnum.class);
            if (null != swaggerDisplayEnum && Enum.class.isAssignableFrom(rawPrimaryType)) {
                subItemRecords = rawPrimaryType.getEnumConstants();
            }
            if (null == subItemRecords) {
                return;
            }
    
    
            final List<String> displayValues = Arrays.stream(subItemRecords).filter(Objects::nonNull).map(item -> {
                return item.toString() ;
            }).filter(Objects::nonNull).collect(Collectors.toList());
    
            String joinText = " (" + String.join("; ", displayValues) + ")";
            try {
                Field mField = ModelPropertyBuilder.class.getDeclaredField("description");
                mField.setAccessible(true);
                joinText = mField.get(context.getBuilder()) + joinText;
            } catch (Exception e) {
                log.error(e.getMessage());
            }
    
            final ResolvedType resolvedType = context.getResolver().resolve(fieldType);
            context.getBuilder().description(joinText).type(resolvedType);
        }
    
        @Override
        public boolean supports(DocumentationType documentationType) {
            return true;
        }
    }
    
    
    1.3 枚举类
    /**
     * 活动报名状态
     *
     * @author AlanChen
     */
    @SwaggerDisplayEnum
    @Getter
    @AllArgsConstructor
    @ApiModel(description = "活动报名状态")
    public enum AttendStateEnum {
        WAIT_PAY("WAIT_PAY", "待支付"),
        UNUSED("UNUSED", "待使用"),
        USED("USED", "已使用"),
        REFUND("REFUND", "已退款"),
        CANCELED("CANCELED", "已取消"),
        AFTER_SALE("AFTER_SALE", "售后"),
        EXPIRED("EXPIRED", "已过期"),
        WASTE("WASTE", "超时未支付-作废"),
        ;
    
        @EnumValue
        @JsonValue
        private String code;
        private String name;
    
        /**
         * 解析
         *
         * @param type
         * @return
         */
        public static AttendStateEnum parse(String type) {
            return parse(type, null);
        }
    
        /**
         * 解析
         *
         * @param type
         * @param dau
         * @return
         */
        public static AttendStateEnum parse(String type, AttendStateEnum dau) {
            if (null != type && !type.isEmpty()) {
                try {
                    return AttendStateEnum.valueOf(type.toUpperCase());
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                }
            }
            return dau;
        }
    
        @Override
        public String toString() {
            return this.code+":"+this.name;
        }
    

    重点:重写toString()方法。

    如果请求参数里用枚举,则传的值会有问题,会转换成toString()的值,即:USED:使用,因此不能在请求参数里用枚举,而只在返回值中用枚举。

    二、使用

    2.1 使用场景1
    2.1.1 代码
    @Data
    @JsonIgnoreProperties(ignoreUnknown = true)
    @ApiModel(description = "报名")
    public class ActivityAttendDTO {
    
        @ApiModelProperty(value = "报名ID")
        private Long id;
    
        @ApiModelProperty(value = "活动ID")
        private String activityId;
    
        @ApiModelProperty(value = "活动名称")
        private String activityName;
    
        @ApiModelProperty(value = "报名状态")
        private AttendStateEnum attendState;
    
       // 其他字段省略
    }
    
    @Data
    public class ActivityAttendMemberPageQry {
    
        @ApiModelProperty(value = "用户ID")
        private Long memberId;
    
        @ApiModelProperty(value = "状态(传null查全部)")
        private AttendStateEnum attendState;
    }
    
    2.1.2 效果
    查询条件 返回结果
    2.2 使用场景2

    在对应属性上的@ApiModelProperty中,notes写明对应的枚举类的路径

    @Data
    @JsonIgnoreProperties(ignoreUnknown = true)
    @ApiModel(description = "报名")
    public class ActivityAttendDTO {
    
        @ApiModelProperty(value = "报名ID")
        private Long id;
    
        @ApiModelProperty(value = "活动ID")
        private String activityId;
    
        @ApiModelProperty(value = "活动名称")
        private String activityName;
    
        @ApiModelProperty(value = "报名状态",notes = "com.alanchen.enums.AttendStateEnum" )
        private String attendState;
    
       // 其他字段省略
    }
    

    相关文章

      网友评论

          本文标题:在Swagger中显示枚举值

          本文链接:https://www.haomeiwen.com/subject/lrybtdtx.html