Swagger 按照枚举类自定义展示

18 篇文章 1 订阅
9 篇文章 0 订阅

场景

Spring项目中,使用swagger去自动生成接口文档.
当存在一个enum枚举时,会有很多VO和param的DTO去引用它.
如果修改这个enum,相关联的很多DTO和其他文件的注释description就需要关联修改,
否则就会造成前后端掌握的枚举值不一致的情况.

话不多说,直接上代码.

1. 实现.

package cn.king.core.configuration;

import cn.king.core.enums.BusinessEnum;
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.stereotype.Component;
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;

/**
 * 对Swagger展示进行修改 ,支持将枚举变量的描述按照枚举类定义展示
 * <p>
 * 个性化处理 对应的枚举需实现cn.king.core.enums.BusinessEnum.class
 *
 * @Description
 * @Author HHJ
 * @Date 2020-12-28 11:55
 * @see ApiModelProperty
 */
@Slf4j
//(纳入spring容器)
//@Primary
//@Component
public class SwaggerEnumDisplayConfig implements ModelPropertyBuilderPlugin {
    /**
     * 自定义 notes前缀CLASS
     */
    public static final String CLASS = "";
    /**
     * 自定义 组装时的分隔符
     */
    public static final String DELIMITER = ", ";
    /**
     * 自定义 BUSINESS_ENUM_CLASS
     */
    public static final Class<BusinessEnum> BUSINESS_ENUM_CLASS = cn.king.core.enums.BusinessEnum.class;
    /**
     * 固定
     */
    public static final String DESCRIPTION = "description";

    @Override
    public void apply(ModelPropertyContext context) {
        // 获取当前字段的类型
        final Class<?> fieldType = context.getBeanPropertyDefinition().get().getField().getRawType();
        // 为枚举字段设置注释
        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 属性没有值,直接返回
        String notes = (annotation.get()).notes();
        if (!annotation.isPresent() || StringUtils.isBlank(notes)) {
            return;
        }
        // 个性化处理
        if (!handle(notes)) {
            return;
        }
        // @ApiModelProperties中的notes指定的class类型
        Class<?> clzz;
        try {
            clzz = Class.forName(notes);
        } catch (ClassNotFoundException e) {
            // 如果指定的类型无法转化,直接忽略
            return;
        }
        //不是一个 BusinessEnum 类型的Enum,则返回
        if (!isBusinessEnum(clzz)) {
            return;
        }

        // 如果对应的class是一个BusinessEnum修饰的枚举类,获取其中的枚举值
        Object[] subItemRecords = clzz.getEnumConstants();

        // 循环枚举值
        List<String> displayValues = Arrays.stream(subItemRecords)
                .filter(Objects::nonNull)
                .map(item -> getString(item))
                .filter(Objects::nonNull)
                .collect(Collectors.toList());

        // 组装最终的描述
        String joinText = " (" + String.join(DELIMITER, displayValues) + ")";
        try {
            Field mField = ModelPropertyBuilder.class.getDeclaredField(DESCRIPTION);
            mField.setAccessible(true);
            joinText = mField.get(context.getBuilder()) + joinText;
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        // 设置描述
        context.getBuilder().description(joinText).type(context.getResolver().resolve(fieldType));
    }

    /**
     * 个性化处理
     *
     * @param notes
     * @return
     */
    private boolean handle(String notes) {
        // 自定义处理
        if (!notes.toLowerCase().startsWith(CLASS)) {
            return false;
        }
        return true;
    }

    /**
     * 是否支持将对象自定义组装
     *
     * @param item
     * @return
     */
    private String getString(Object item) {
        BusinessEnum value = (BusinessEnum) item;
        return value.getCode() + ":" + value.getMessage();
    }

    /**
     * 是否支持isBusinessEnum
     * 可以自己定义
     *
     * @param clzz
     * @return
     */
    private boolean isBusinessEnum(Class<?> clzz) {
        if (!Enum.class.isAssignableFrom(clzz)) {
            return false;
        }
        Class<?>[] interfacesArray = clzz.getInterfaces();
        for (Class<?> item : interfacesArray) {
            //判断对应的class是一个BusinessEnum修饰的枚举类
            if (item == BUSINESS_ENUM_CLASS) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean supports(DocumentationType documentationType) {
        return true;
    }
}

2.个性化依赖.对应的枚举需实现cn.king.core.enums.BusinessEnum.class

package cn.king.core.enums;

/**
 * @description:
 * @author: Admin
 * @create: 2020-12-27 13:39
 **/
public interface BusinessEnum {
    /**
     * getCode
     *
     * @return
     */
    int getCode();

    /**
     * getMessage
     *
     * @return
     */
    String getMessage();
}

3.应用.例如有业务枚举如下:

package cn.king.model.enums;

import cn.king.core.enums.BusinessEnum;
import lombok.Getter;

/**
 * 短信类型枚举
 *
 * @Description
 * @Author HHJ
 * @Date 2020-12-28 17:18
 */
@Getter
public enum SmsFeaturesTypeEnum implements BusinessEnum {

    USER_LOGIN(1, "1", "用户登录"),
    USER_REGISTER(2, "2", "用户注册"),
    ADMIN_LOGIN(3, "3", "管理员登录"),
    ADMIN_REGISTER(4, "4", "管理员注册"),
    USER_UPDATE_PWD(5, "5", "用户找回密码"),
    USER_WECHAT_BIND(6, "6", "微信绑定"),
    SMS_CODE_7(7, "7", "其他7"),
    SMS_CODE_8(8, "8", "其他8"),
    SMS_CODE_9(9, "9", "其他9"),
    other(10, "10", "其他"),
    ;

    private int code;
    private String features;
    private String message;

    SmsFeaturesTypeEnum(int code, String features, String message) {
        this.code = code;
        this.features = features;
        this.message = message;
    }

    public static SmsFeaturesTypeEnum getByFeatures(String features) {
        SmsFeaturesTypeEnum[] values = values();
        int length = values.length;
        for (int i = 0; i < length; ++i) {
            SmsFeaturesTypeEnum value = values[i];
            if (value.getFeatures().equals(features)) {
                return value;
            }
        }

        return null;
    }

    public static SmsFeaturesTypeEnum getByCode(int code) {
        SmsFeaturesTypeEnum[] values = values();
        int length = values.length;
        for (int i = 0; i < length; ++i) {
            SmsFeaturesTypeEnum value = values[i];
            if (value.getCode() == code) {
                return value;
            }
        }

        return null;
    }

    public static boolean isValid(int code) {
        return getByCode(code) != null;
    }

    public static boolean isFeatures(String features) {
        return getByFeatures(features) != null;
    }
}

4.效果展示.Swagger接口文档 红色部分是根据枚举自定义添加的内容.

参考文档

https://juejin.cn/post/6844903845697421319

https://blog.csdn.net/sgambler/article/details/103524840

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Swagger可以通过使用自定义注解来描述枚举类的字段,从而在生成接口文档时展示枚举类的内容。一种常用的方式是使用@ApiModel和@ApiModelProperty注解来描述枚举类及其字段。 首先,使用@ApiModel注解来描述枚举类本身,可以指定枚举类的名称和描述信息。例如: ```java @ApiModel(value = "OperateType", description = "操作类型") public enum OperateType { // 枚举值 @ApiModelProperty(value = "新增操作", example = "ADD") ADD, @ApiModelProperty(value = "更新操作", example = "UPDATE") UPDATE, @ApiModelProperty(value = "删除操作", example = "DELETE") DELETE } ``` 在枚举值上使用@ApiModelProperty注解来描述每个枚举值,可以指定其值的含义、示例值等信息。例如,上面的示例中给出了三个枚举值和对应的描述信息。 这样,在生成的Swagger文档中,枚举类的字段描述会被展示出来,并且可以查看每个枚举值的含义和示例值。 需要注意的是,使用自定义注解来扩展Swagger的能力需要在项目中引入Swagger的相关依赖,并配置相应的注解处理器。 希望这个解答对你有帮助!如果还有其他问题,请随时提问。123 #### 引用[.reference_title] - *1* *2* *3* [Java中自定义扩展Swagger的能力,自动通过枚举类生成参数取值含义描述的实现策略](https://blog.csdn.net/Q54665642ljf/article/details/127171761)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值