引言

原文出处Swagger2 对于JSONObject参数在API文档中展现具体参数以及参数阐明
相似的 Swagger2 对于Map参数在API文档中展现具体参数以及参数阐明
原理就不再做阐明,读者能够查看该文章即可。作者稍作了些扭转,也是花了很多工夫整顿,接下来咱们只负责搬砖就好,话不多说间接看代码。

代码实现

自定义注解类 ApiJsonObject2

package com.mybatis.plus.swagger;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * @Author wulongbo * @Date 2020/9/14 17:20 * @Version 1.0 */@Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public @interface ApiJsonObject2 {    ApiJsonProperty2[] value(); //对象属性值 ApiJsonResult result() default @ApiJsonResult({}); String name() default "";}

自定义注解类ApiJsonProperty2

package com.mybatis.plus.swagger;import io.swagger.annotations.Example;import io.swagger.annotations.ExampleProperty;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * @Author wulongbo * @Date 2020/9/14 17:23 * @Version 1.0 */@Target(ElementType.ANNOTATION_TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface ApiJsonProperty2 {    String name(); String defaultValue() default ""; String description() default ""; String allowableValues() default ""; boolean required() default false; String access() default ""; boolean allowMultiple() default false; Class<?> type() default String.class ; String paramType() default ""; String example() default ""; Example examples() default @Example(value = @ExampleProperty(mediaType = "", value = "")); String format() default ""; boolean readOnly() default false; String collectionFormat() default "";}

自定义注解类 ApiJsonResult

package com.mybatis.plus.swagger;/** * Created by yueh on 2018/9/7. */import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target(ElementType.ANNOTATION_TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface ApiJsonResult {    String[] value(); String name() default ""; String type() default CommonData.RESULT_TYPE_NORMAL_FINAL;}

ApiListingJsonScanner

package com.mybatis.plus.swagger;/** * Created by yueh on 2018/9/12. */import com.google.common.annotations.VisibleForTesting;import com.google.common.base.Optional;import com.google.common.base.*;import com.google.common.collect.FluentIterable;import com.google.common.collect.Iterables;import com.google.common.collect.LinkedListMultimap;import com.google.common.collect.Multimap;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Primary;import org.springframework.core.annotation.AnnotationUtils;import org.springframework.stereotype.Component;import org.springframework.web.bind.annotation.RequestMapping;import springfox.documentation.PathProvider;import springfox.documentation.builders.ApiListingBuilder;import springfox.documentation.schema.Model;import springfox.documentation.service.*;import springfox.documentation.spi.service.contexts.ApiListingContext;import springfox.documentation.spi.service.contexts.DocumentationContext;import springfox.documentation.spi.service.contexts.RequestMappingContext;import springfox.documentation.spring.web.paths.PathMappingAdjuster;import springfox.documentation.spring.web.plugins.Docket;import springfox.documentation.spring.web.plugins.DocumentationPluginsManager;import springfox.documentation.spring.web.scanners.ApiDescriptionReader;import springfox.documentation.spring.web.scanners.ApiListingScanner;import springfox.documentation.spring.web.scanners.ApiListingScanningContext;import springfox.documentation.spring.web.scanners.ApiModelReader;import java.util.*;import static com.google.common.base.Predicates.and;import static com.google.common.collect.FluentIterable.from;import static com.google.common.collect.Lists.newArrayList;import static com.google.common.collect.Sets.newHashSet;import static java.util.stream.Collectors.toList;import static springfox.documentation.builders.BuilderDefaults.nullToEmptyList;import static springfox.documentation.spi.service.contexts.Orderings.methodComparator;import static springfox.documentation.spi.service.contexts.Orderings.resourceGroupComparator;@Component@Primarypublic class ApiListingJsonScanner extends ApiListingScanner {    private final ApiDescriptionReader apiDescriptionReader; private final ApiModelReader apiModelReader; private final DocumentationPluginsManager pluginsManager; public static final String ROOT = "/"; @Autowired public ApiListingJsonScanner(            ApiDescriptionReader apiDescriptionReader, ApiModelReader apiModelReader, DocumentationPluginsManager pluginsManager) {        super(apiDescriptionReader,apiModelReader,pluginsManager); this.apiDescriptionReader = apiDescriptionReader; this.apiModelReader = apiModelReader; this.pluginsManager = pluginsManager; }    static Optional<String> longestCommonPath(List<ApiDescription> apiDescriptions) {        List<String> commons = newArrayList(); if (null == apiDescriptions || apiDescriptions.isEmpty()) {            return Optional.absent(); }        List<String> firstWords = urlParts(apiDescriptions.get(0)); for (int position = 0; position < firstWords.size(); position++) {            String word = firstWords.get(position); boolean allContain = true; for (int i = 1; i < apiDescriptions.size(); i++) {                List<String> words = urlParts(apiDescriptions.get(i)); if (words.size() < position + 1 || !words.get(position).equals(word)) {                    allContain = false; break; }            }            if (allContain) {                commons.add(word); }        }        Joiner joiner = Joiner.on("/").skipNulls(); return Optional.of("/" + joiner.join(commons)); }    static List<String> urlParts(ApiDescription apiDescription) {        return Splitter.on('/')                .omitEmptyStrings()                .trimResults()                .splitToList(apiDescription.getPath()); }    public Multimap<String, ApiListing> scan(ApiListingScanningContext context) {        final Multimap<String, ApiListing> apiListingMap = LinkedListMultimap.create(); int position = 0; Map<ResourceGroup, List<RequestMappingContext>> requestMappingsByResourceGroup                = context.getRequestMappingsByResourceGroup(); Collection<ApiDescription> additionalListings = pluginsManager.additionalListings(context); Set<ResourceGroup> allResourceGroups = FluentIterable.from(collectResourceGroups(additionalListings))                .append(requestMappingsByResourceGroup.keySet())                .toSet(); List<SecurityReference> securityReferences = newArrayList(); for (final ResourceGroup resourceGroup : sortedByName(allResourceGroups)) {            DocumentationContext documentationContext = context.getDocumentationContext(); Set<String> produces = new LinkedHashSet<String>(documentationContext.getProduces()); Set<String> consumes = new LinkedHashSet<String>(documentationContext.getConsumes()); String host = documentationContext.getHost(); Set<String> protocols = new LinkedHashSet<String>(documentationContext.getProtocols()); Set<ApiDescription> apiDescriptions = newHashSet(); Map<String, Model> models = new LinkedHashMap<String, Model>(); List<RequestMappingContext> requestMappings = nullToEmptyList(requestMappingsByResourceGroup.get(resourceGroup)); for (RequestMappingContext each : sortedByMethods(requestMappings)) {//url Map<String, Model> knownModels = new HashMap<>(); models.putAll(apiModelReader.read(each.withKnownModels(models))); apiDescriptions.addAll(apiDescriptionReader.read(each)); }            // models.putAll(ModelCache.getInstance().getKnownModels()); List<ApiDescription> additional = from(additionalListings)                    .filter(and(                                    belongsTo(resourceGroup.getGroupName()), onlySelectedApis(documentationContext)))                    .toList(); apiDescriptions.addAll(additional); List<ApiDescription> sortedApis = FluentIterable.from(apiDescriptions)                    .toSortedList(documentationContext.getApiDescriptionOrdering()); Optional<String> o = longestCommonPath(sortedApis); String resourcePath = new ResourcePathProvider(resourceGroup)                    .resourcePath()                    .or(o)                    .orNull(); PathProvider pathProvider = documentationContext.getPathProvider(); String basePath = pathProvider.getApplicationBasePath(); PathAdjuster adjuster = new PathMappingAdjuster(documentationContext); ApiListingBuilder apiListingBuilder = new ApiListingBuilder(context.apiDescriptionOrdering())                    .apiVersion(documentationContext.getApiInfo().getVersion())                    .basePath(adjuster.adjustedPath(basePath))                    .resourcePath(resourcePath)                    .produces(produces)                    .consumes(consumes)                    .host(host)                    .protocols(protocols)                    .securityReferences(securityReferences)                    .apis(sortedApis)                    .models(models)                    .position(position++)                    .availableTags(documentationContext.getTags()); ApiListingContext apiListingContext = new ApiListingContext(                    context.getDocumentationType(), resourceGroup, apiListingBuilder); apiListingMap.put(resourceGroup.getGroupName(), pluginsManager.apiListing(apiListingContext)); }        return apiListingMap; }    private Predicate<ApiDescription> onlySelectedApis(final DocumentationContext context) {        return new Predicate<ApiDescription>() {            @Override public boolean apply(ApiDescription input) {                return context.getApiSelector().getPathSelector().apply(input.getPath()); }        }; }    private Iterable<RequestMappingContext> sortedByMethods(List<RequestMappingContext> contexts) {        return contexts.stream().sorted(methodComparator()).collect(toList()); }    static Iterable<ResourceGroup> collectResourceGroups(Collection<ApiDescription> apiDescriptions) {        return from(apiDescriptions)                .transform(toResourceGroups()); }    static Iterable<ResourceGroup> sortedByName(Set<ResourceGroup> resourceGroups) {        return from(resourceGroups).toSortedList(resourceGroupComparator()); }    static Predicate<ApiDescription> belongsTo(final String groupName) {        return new Predicate<ApiDescription>() {            @Override public boolean apply(ApiDescription input) {                return !input.getGroupName().isPresent()                        || groupName.equals(input.getGroupName().get()); }        }; }    private static Function<ApiDescription, ResourceGroup> toResourceGroups() {        return new Function<ApiDescription, ResourceGroup>() {            @Override public ResourceGroup apply(ApiDescription input) {                return new ResourceGroup(                        input.getGroupName().or(Docket.DEFAULT_GROUP_NAME), null); }        }; }    class ResourcePathProvider {        private final ResourceGroup resourceGroup; ResourcePathProvider(ResourceGroup resourceGroup) {            this.resourceGroup = resourceGroup; }        public Optional<String> resourcePath() {            return Optional.fromNullable(                    Strings.emptyToNull(controllerClass()                            .transform(resourcePathExtractor())                            .or(""))); }        private Function<Class<?>, String> resourcePathExtractor() {            return new Function<Class<?>, String>() {                @Override public String apply(Class<?> input) {                    String path = Iterables.getFirst(Arrays.asList(paths(input)), ""); if (Strings.isNullOrEmpty(path)) {                        return ""; }                    if (path.startsWith("/")) {                        return path; }                    return "/" + path; }            }; }        @VisibleForTesting String[] paths(Class<?> controller) {            RequestMapping annotation                    = AnnotationUtils.findAnnotation(controller, RequestMapping.class); if (annotation != null) {                return annotation.path(); }            return new String[]{}; }        private Optional<? extends Class<?>> controllerClass() {            return resourceGroup.getControllerClass(); }    }}

自定义注解类 ApiSingleParam

package com.mybatis.plus.swagger;/** * Created by yueh on 2018/9/7.  */import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target({ElementType.FIELD})@Retention(RetentionPolicy.RUNTIME)public @interface ApiSingleParam { Sring name() default ""; String value() default ""; Class<?> type() default String.class; String example() default ""; boolean allowMultiple() default false;}

CommonData

package com.mybatis.plus.swagger;/** * Created by yueh on 2018/9/18.  */ public class CommonData { private static String RESULT_TYPE_NORMAL = "normal"; private static String RESULT_TYPE_PAGE = "page"; private static String RESULT_TYPE_LIST = "list"; private static String RESULT_TYPE_OTHER = "other"; private static String JSON_ERROR_CODE = "errorCode"; private static String JSON_ERROR_MSG = "errorMsg"; private static String JSON_START_PAGE_NUM = "startPageNum"; private static String JSON_PAGE_SIZE = "pageSize"; private static String JSON_PAGE_COUNT = "pageCount"; private static String JSON_TOTAL_COUNT = "totalCount"; public static final String RESULT_TYPE_NORMAL_FINAL = "normal"; public static String getResultTypeNormal() {        return RESULT_TYPE_NORMAL; }    public static void setResultTypeNormal(String resultTypeNormal) {        RESULT_TYPE_NORMAL = resultTypeNormal; }    public static String getResultTypePage() {        return RESULT_TYPE_PAGE; }    public static void setResultTypePage(String resultTypePage) {        RESULT_TYPE_PAGE = resultTypePage; }    public static String getResultTypeList() {        return RESULT_TYPE_LIST; }    public static void setResultTypeList(String resultTypeList) {        RESULT_TYPE_LIST = resultTypeList; }    public static String getResultTypeOther() {        return RESULT_TYPE_OTHER; }    public static void setResultTypeOther(String resultTypeOther) {        RESULT_TYPE_OTHER = resultTypeOther; }    public static String getJsonErrorCode() {        return JSON_ERROR_CODE; }    public static void setJsonErrorCode(String jsonErrorCode) {        JSON_ERROR_CODE = jsonErrorCode; }    public static String getJsonErrorMsg() {        return JSON_ERROR_MSG; }    public static void setJsonErrorMsg(String jsonErrorMsg) {        JSON_ERROR_MSG = jsonErrorMsg; }    public static String getJsonStartPageNum() {        return JSON_START_PAGE_NUM; }    public static void setJsonStartPageNum(String jsonStartPageNum) {        JSON_START_PAGE_NUM = jsonStartPageNum; }    public static String getJsonPageSize() {        return JSON_PAGE_SIZE; }    public static void setJsonPageSize(String jsonPageSize) {        JSON_PAGE_SIZE = jsonPageSize; }    public static String getJsonPageCount() {        return JSON_PAGE_COUNT; }    public static void setJsonPageCount(String jsonPageCount) {        JSON_PAGE_COUNT = jsonPageCount; }    public static String getJsonTotalCount() {        return JSON_TOTAL_COUNT; }    public static void setJsonTotalCount(String jsonTotalCount) {        JSON_TOTAL_COUNT = jsonTotalCount; }}

全局字符串 GlobalString

package com.mybatis.plus.swagger;/** * @Author wulongbo * @Date 2020/9/14 17:34 * @Version 1.0 */ public class GlobalString {    @ApiSingleParam(value = "姓名", example = "isWulongbo")    public static final String JSON_NAME = "name"; @ApiSingleParam(value = "年龄", example = "25")    public static final String JSON_AGE = "age"; @ApiSingleParam(value = "邮箱", example = "1191935532@qq.com")    public static final String JSON_EMAIL = "email"; @ApiSingleParam(value = "错误码", example = "0", type = Integer.class)    public static final String JSON_ERROR_CODE = "errorCode"; @ApiSingleParam(value = "错误信息", example = "OK")    public static final String JSON_ERROR_MSG = "errorMsg";}

ModelCache

package com.mybatis.plus.swagger;import com.fasterxml.classmate.ResolvedType;import com.fasterxml.classmate.TypeResolver;import com.google.common.base.Function;import org.springframework.plugin.core.OrderAwarePluginRegistry;import org.springframework.plugin.core.PluginRegistry;import springfox.documentation.schema.*;import springfox.documentation.spi.DocumentationType;import springfox.documentation.spi.schema.TypeNameProviderPlugin;import springfox.documentation.spi.schema.contexts.ModelContext;import springfox.documentation.spi.service.contexts.DocumentationContext;import java.lang.reflect.Field;import java.util.*;import static com.google.common.base.Strings.isNullOrEmpty;import static com.google.common.collect.Lists.newArrayList;import static com.mybatis.plus.swagger.CommonData.*;import static org.springframework.util.ObjectUtils.isEmpty;import static springfox.documentation.schema.Collections.collectionElementType;import static springfox.documentation.spi.schema.contexts.ModelContext.inputParam;/** * Created by yueh on 2018/9/13. */public class ModelCache {    private Map<String, Model> knownModels = new HashMap<>(); private DocumentationContext context; private Function<ResolvedType, ? extends ModelReference> factory; private TypeResolver typeResolver = new TypeResolver(); private Map<String, ApiSingleParam> paramMap = new HashMap<>(); private Class<?> cls; private ModelCache() {    }    public static ModelCache getInstance() {        return ModelCacheSub.instance; }    public ModelCache setParamMap(Map<String, ApiSingleParam> paramMap) {        this.paramMap = paramMap; return getInstance(); }    public ModelCache setParamClass(Class<?> cls) {        this.cls = cls; return getInstance(); }    public Class<?> getParamClass() {        return cls; }    public ModelCache setFactory(Function<ResolvedType, ? extends ModelReference> factory) {        this.factory = factory; return getInstance(); }    public void setContext(DocumentationContext context) {        this.context = context; }    public DocumentationContext getContext() {        return context; }    public Map<String, Model> getKnownModels() {        return knownModels; }    public ModelCache addModel(ApiJsonObject2 jsonObj) {        String modelName = jsonObj.name(); knownModels.put(modelName, new Model(modelName, modelName, new TypeResolver().resolve(String.class), "com.mybatis.plus.swagger.CommonData", toPropertyMap(jsonObj.value()), "POST参数", "", "", newArrayList(), null, null )); String resultName = jsonObj.name() + "-" + "result"; knownModels.put(resultName, new Model(resultName, resultName, new TypeResolver().resolve(String.class), "com.mybatis.plus.swagger.CommonData", toResultMap(jsonObj.result(), resultName), "返回模型", "", "", newArrayList(), null, null )); return ModelCacheSub.instance; }    public Map<String, ModelProperty> toResultMap(ApiJsonResult jsonResult, String groupName) {//        System.out.println("--- toResultMap ---"); List<String> values = Arrays.asList(jsonResult.value()); List<String> outer = new ArrayList<>(); if (!getResultTypeOther().equals(jsonResult.type())) {            outer.add(getJsonErrorCode()); outer.add(getJsonErrorMsg()); if (!getResultTypeNormal().equals(jsonResult.type())) {                //model String subModelName = groupName + "-" + jsonResult.name(); knownModels.put(subModelName, new Model(subModelName, subModelName, new TypeResolver().resolve(String.class), "com.mybatis.plus.swagger.CommonData", transResultMap(values), "返回模型", "", "", newArrayList(), null, null )); //prop Map<String, ModelProperty> propertyMap = new HashMap<>();//                outer.add(jsonResult.name()); ResolvedType type = new TypeResolver().resolve(List.class); ModelProperty mp = new ModelProperty(                        jsonResult.name(), type, "", 0, false, false, true, false, "", null, "", null, "", null, newArrayList()                );// new AllowableRangeValues("1", "2000"),//.allowableValues(new AllowableListValues(["ABC", "ONE", "TWO"], "string")) mp.updateModelRef(getModelRef()); ResolvedType collectionElementType = collectionElementType(type); try {                    Field f = ModelProperty.class.getDeclaredField("modelRef"); f.setAccessible(true); f.set(mp, new ModelRef("List", new ModelRef(subModelName))); } catch (Exception e) {                    e.printStackTrace(); }                propertyMap.put(jsonResult.name(), mp); if (getResultTypePage().equals(jsonResult.type())) {                    outer.add(getJsonStartPageNum()); outer.add(getJsonPageSize()); outer.add(getJsonTotalCount()); }                propertyMap.putAll(transResultMap(outer)); return propertyMap; }            outer.addAll(values); return transResultMap(outer); }        return transResultMap(values); }    public Map<String, ModelProperty> transResultMap(List<String> values) {        Map<String, ModelProperty> propertyMap = new HashMap<>(); for (String resultName : values) {            ApiSingleParam param = paramMap.get(resultName); if (isEmpty(param)) {                continue; }            Class<?> type = param.type(); if (!isEmpty(param)) {                type = param.type(); } else if (isEmpty(type)) {                type = String.class; }            boolean allowMultiple = param.allowMultiple(); if (!isEmpty(param)) {                allowMultiple = param.allowMultiple(); }            ResolvedType resolvedType = null; if (allowMultiple) {                resolvedType = new TypeResolver().resolve(List.class, type); } else {                resolvedType = new TypeResolver().resolve(type); }            ModelProperty mp = new ModelProperty(                    resultName, resolvedType, param.type().getName(), 0, false, false, true, false, param.value(), null, param.example(), null, "", null, newArrayList()            );// new AllowableRangeValues("1", "2000"),//.allowableValues(new AllowableListValues(["ABC", "ONE", "TWO"], "string")) mp.updateModelRef(getModelRef()); propertyMap.put(resultName, mp); }        return propertyMap; }    public Map<String, ModelProperty> toPropertyMap(ApiJsonProperty2[] jsonProp) {//        System.out.println("--- toPropertyMap ---"); Map<String, ModelProperty> propertyMap = new HashMap<String, ModelProperty>(); for (ApiJsonProperty2 property : jsonProp) {            String propertyName = property.name(); ApiSingleParam param = paramMap.get(propertyName); String description = property.description(); if (isNullOrEmpty(description) && !isEmpty(param)) {                description = param.value(); }            String example = property.description(); if (isNullOrEmpty(example) && !isEmpty(param)) {                example = param.example(); }            Class<?> type = property.type(); if (!isEmpty(param)) {                type = param.type(); } else if (isEmpty(type)) {                type = String.class; }            boolean allowMultiple = property.allowMultiple(); if (!isEmpty(param)) {                allowMultiple = param.allowMultiple(); }            ResolvedType resolvedType = null; if (allowMultiple) {                resolvedType = new TypeResolver().resolve(List.class, type); } else {                resolvedType = new TypeResolver().resolve(type); }//            System.out.println("----- example: " + example);//            System.out.println("----- description: " + description); ModelProperty mp = new ModelProperty(                    propertyName, resolvedType, type.toString(), 0, property.required(), false, property.readOnly(), null, description, null, example, null, property.defaultValue(), null, newArrayList()            );// new AllowableRangeValues("1", "2000"),//.allowableValues(new AllowableListValues(["ABC", "ONE", "TWO"], "string")) mp.updateModelRef(getModelRef()); propertyMap.put(property.name(), mp); }        return propertyMap; }    private static class ModelCacheSub {        private static ModelCache instance = new ModelCache(); }    private Function<ResolvedType, ? extends ModelReference> getModelRef() {        Function<ResolvedType, ? extends ModelReference> factory = getFactory();//        ModelReference stringModel = factory.apply(typeResolver.resolve(List.class, String.class)); return factory; }    public Function<ResolvedType, ? extends ModelReference> getFactory() {        if (factory == null) {            List<DefaultTypeNameProvider> providers = newArrayList(); providers.add(new DefaultTypeNameProvider()); PluginRegistry<TypeNameProviderPlugin, DocumentationType> modelNameRegistry =                    OrderAwarePluginRegistry.create(providers); TypeNameExtractor typeNameExtractor = new TypeNameExtractor(                    typeResolver, modelNameRegistry, new JacksonEnumTypeDeterminer()); ModelContext modelContext = inputParam(                    context.getGroupName(), String.class, context.getDocumentationType(), context.getAlternateTypeProvider(), context.getGenericsNamingStrategy(), context.getIgnorableParameterTypes()); factory = ResolvedTypes.modelRefFactory(modelContext, typeNameExtractor); }        return factory; }}

留神:在 ModelCache 类中 CommonData的门路肯定要改为你实在的我的项目门路

ParametersReader

package com.mybatis.plus.swagger;import com.fasterxml.classmate.ResolvedType;import com.fasterxml.classmate.TypeResolver;import com.google.common.base.Function;import com.google.common.base.Optional;import com.google.common.collect.Lists;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.core.Ordered;import org.springframework.core.annotation.Order;import org.springframework.stereotype.Component;import springfox.documentation.builders.ParameterBuilder;import springfox.documentation.schema.ModelReference;import springfox.documentation.schema.ResolvedTypes;import springfox.documentation.schema.TypeNameExtractor;import springfox.documentation.service.Parameter;import springfox.documentation.service.ResolvedMethodParameter;import springfox.documentation.spi.DocumentationType;import springfox.documentation.spi.schema.contexts.ModelContext;import springfox.documentation.spi.service.OperationBuilderPlugin;import springfox.documentation.spi.service.contexts.OperationContext;import springfox.documentation.spi.service.contexts.ParameterContext;import springfox.documentation.spring.web.DescriptionResolver;import java.lang.reflect.Field;import java.util.HashMap;import java.util.List;import java.util.Map;import static springfox.documentation.spi.schema.contexts.ModelContext.inputParam;import static springfox.documentation.swagger.common.SwaggerPluginSupport.pluginDoesApply;/** * Created by yueh on 2018/9/10.  */@Component@Order(Ordered.HIGHEST_PRECEDENCE)public class ParametersReader implements OperationBuilderPlugin {    private final DescriptionResolver descriptions; private final TypeNameExtractor nameExtractor; private final TypeResolver resolver; @Autowired public ParametersReader(DescriptionResolver descriptions, TypeNameExtractor nameExtractor, TypeResolver resolver) {        this.nameExtractor = nameExtractor; this.resolver = resolver; this.descriptions = descriptions; }    @Override public void apply(OperationContext context) {        context.operationBuilder().parameters(readParameters(context)); }    @Override public boolean supports(DocumentationType delimiter) {        return pluginDoesApply(delimiter); }    private List<Parameter> readParameters(OperationContext context) {        List<Parameter> parameters = Lists.newArrayList(); List<ResolvedMethodParameter> methodParameters = context.getParameters(); Map<String, ApiSingleParam> paramMap = new HashMap<>(); Field[] fields = ModelCache.getInstance().getParamClass().getDeclaredFields(); String type = new String(); for (Field field : fields) {            if (field.isAnnotationPresent(ApiSingleParam.class)) {                ApiSingleParam param = field.getAnnotation(ApiSingleParam.class); try {                    String name = (String) field.get(type); paramMap.put(name, param); } catch (Exception e) {                }            }        }        for (ResolvedMethodParameter methodParameter : methodParameters) {            ParameterContext parameterContext = new ParameterContext(methodParameter, new ParameterBuilder(), context.getDocumentationContext(), context.getGenericsNamingStrategy(), context); Function<ResolvedType, ? extends ModelReference> factory = createModelRefFactory(parameterContext); Optional<ApiJsonObject2> annotation = context.findAnnotation(ApiJsonObject2.class); if (annotation.isPresent()) {                ModelCache.getInstance().setFactory(factory)                        .setParamMap(paramMap)                        .addModel(annotation.get()); }        }        return parameters; }    private Function<ResolvedType, ? extends ModelReference> createModelRefFactory(ParameterContext context) {        ModelContext modelContext = inputParam(                context.getGroupName(), context.resolvedMethodParameter().getParameterType(), context.getDocumentationType(), context.getAlternateTypeProvider(), context.getGenericNamingStrategy(), context.getIgnorableParameterTypes()); return ResolvedTypes.modelRefFactory(modelContext, nameExtractor); }}

OK!贴完代码后的目录构造如下:

因为咱们之前 mybatis-plus 我的项目没有引入json依赖
pom.xml 文件引入fastjson

<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --><dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.70</version></dependency>

封装返回值

新建一个 base 文件夹,贴入罕用的封装类
BaseApiService

package com.mybatis.plus.base;import lombok.Data;import org.springframework.stereotype.Component;@Data@Componentpublic class BaseApiService<T> {   public BaseResponse<T> setResultError(Integer code, String msg) {      return setResult(code, msg, null); }   // 返回谬误,能够传msg public BaseResponse<T> setResultError(String msg) {      return setResult(PageCodeEnum.HTTP_RES_500.getCode(), msg, null); }   // 返回胜利,能够传data值 public BaseResponse<T> setResultSuccess(T data) {      return setResult(PageCodeEnum.HTTP_RES_200.getCode(), PageCodeEnum.HTTP_RES_200.getMsg(), data); }   // 返回胜利,沒有data值 public BaseResponse<T> setResultSuccess() {      return setResult(PageCodeEnum.HTTP_RES_200.getCode(), PageCodeEnum.HTTP_RES_200.getMsg(), null); }   // 返回胜利,沒有data值 public BaseResponse<T> setResultSuccess(String msg) {      return setResult(PageCodeEnum.HTTP_RES_200.getCode(), msg, null); }   // 通用封装 public BaseResponse<T> setResult(Integer code, String msg, T data) {      return new BaseResponse<T>(code, msg, data); }   //调用数据库封装 public Boolean toDaoResult(int result){      return result>0?true:false; }}

BaseResponse

package com.mybatis.plus.base;import lombok.Data;@Datapublic class BaseResponse<T> {   /** * 返回码 */ private Integer code; /** * 音讯(最好用简写,不占用宽带) */ private String msg; /** * 数据 */ private T data; public BaseResponse() {   }   public BaseResponse(Integer code, String msg, T data) {      super(); this.code = code; this.msg = msg; this.data = data; }   /** * 未登录返回后果 */ public static <T>   BaseResponse<T> unauthorized(T data) {      return new BaseResponse<T>(ResultCode.UNAUTHORIZED.getCode(), ResultCode.UNAUTHORIZED.getMessage(), data); }   /** * 未受权返回后果 */ public static <T>   BaseResponse<T> forbidden(T data) {      return new BaseResponse<T>(ResultCode.FORBIDDEN.getCode(), ResultCode.FORBIDDEN.getMessage(), data); }}

IErrorCode

package com.mybatis.plus.base;/** * 封装API的错误码 */public interface IErrorCode {    Integer getCode(); String getMessage();}

PageCodeEnum

package com.mybatis.plus.base;/** * @Author wulongbo * @Date 2020/9/14 15:38 * @Version 1.0 */public enum PageCodeEnum {    // 公共 HTTP_RES_200(200,"success"), HTTP_RES_500(500,"fail"), SUCCESS(200, "胜利"), UNKNOWN_ERROR(9998,"未知异样"), SYSTEM_ERROR(9999, "零碎异样"), INSUFFICIENT_PERMISSION(4003, "权限有余"), WARN(9000, "失败"), REQUEST_PARAMETER_ERROR(1002, "申请参数谬误"), // 分页 PAGE_CURRENTPAGE_EMPTY(5000, "以后页码不能为空!"), PAGE_PAGESIZE_EMPTY(5001, "每页显示的条数不能为空!"); private Integer code; private String msg; // 构造方法,留神:构造方法不能为public,因为enum并不能够被实例化 private PageCodeEnum(Integer code, String msg) {        this.code = code; this.msg = msg; }    //不须要定义set办法,避免批改 public Integer getCode() {        return code; }    public String getMsg() {        return msg; }}

ResultCode

package com.mybatis.plus.base;/** * 枚举了一些罕用API操作码 */public enum ResultCode implements IErrorCode {    SUCCESS(200, "操作胜利"), FAILED(500, "操作失败"), VALIDATE_FAILED(404, "参数检验失败"), UNAUTHORIZED(401, "暂未登录或token曾经过期"), FORBIDDEN(403, "没有相干权限"); private Integer code; private String message; private ResultCode(Integer code, String message) {        this.code = code; this.message = message; }    public Integer getCode() {        return code; }    public String getMessage() {        return message; }}

OK!目录构造如下:

当初咱们在 UserController 中退出咱们自定义的注解

package com.mybatis.plus.controller;import com.alibaba.fastjson.JSONObject;import com.mybatis.plus.base.BaseApiService;import com.mybatis.plus.base.BaseResponse;import com.mybatis.plus.base.PageCodeEnum;import com.mybatis.plus.entity.User;import com.mybatis.plus.service.IUserService;import com.mybatis.plus.swagger.ApiJsonObject2;import com.mybatis.plus.swagger.ApiJsonProperty2;import com.mybatis.plus.swagger.ApiJsonResult;import com.mybatis.plus.swagger.GlobalString;import io.swagger.annotations.*;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;/** * <p> * 前端控制器 * </p> * * @author wulongbo * @since 2020-11-09 */@RestController@RequestMapping("/user")@CrossOriginpublic class UserController extends BaseApiService {    @Autowired private IUserService iUserService; @ApiOperation(value="增加用户信息", notes="增加用户信息")    @ApiImplicitParams({            @ApiImplicitParam(paramType = "query", name = "name", dataType = "String", required = true, value = "姓名"), @ApiImplicitParam(paramType = "query", name = "age", dataType = "int", required = true, value = "年龄"), @ApiImplicitParam(paramType = "query", name = "email", dataType = "String", required = true, value = "邮箱") })    @PostMapping("/addUser")    public boolean addUser(String name,Integer age,String email) {        try {            User user=new User(); user.setName(name); user.setAge(age); user.setEmail(email); iUserService.recordJob(user); }catch (Exception e){            return false; }        return true; }    @ApiOperation(value="删除用户信息", notes="删除用户信息")    @ApiImplicitParams({            @ApiImplicitParam(paramType = "query", name = "id", dataType = "long", required = true, value = "用户id")})    @PostMapping("/delUser")    public boolean delUser(Long id) {        try {            User user=new User(); user.setId(id); iUserService.delJob(user); }catch (Exception e){            return false; }        return true; }    /** * JSONObject参数增加用户信息 * @param json * @return */ @ApiOperation(value="JSONObject参数增加用户信息", notes="JSONObject参数增加用户信息")    @ApiJsonObject2(name = "addUserByJson", value = {            @ApiJsonProperty2(name = GlobalString.JSON_NAME), @ApiJsonProperty2(name = GlobalString.JSON_AGE), @ApiJsonProperty2(name = GlobalString.JSON_EMAIL)}, result = @ApiJsonResult({}))    @ApiImplicitParam(name = "json", required = true, dataType = "addUserByJson")    @ApiResponses({@ApiResponse(code = 200, message = "OK", reference = "addUserByJson")})    @RequestMapping(value = "/addUserByJson", method = RequestMethod.POST, consumes ="application/json", produces = "application/json")    public BaseResponse<JSONObject> addUserByJson(@RequestBody String json){        JSONObject jsonObject=JSONObject.parseObject(json); String name=jsonObject.getString("name"); // 姓名 Integer age=jsonObject.getInteger("age");// 年龄 String email=jsonObject.getString("email");// 邮箱 try {            User user=new User(); user.setName(name); user.setAge(age); user.setEmail(email); iUserService.recordJob(user); }catch (Exception e){            return setResultError(PageCodeEnum.HTTP_RES_500.getMsg()); }        return setResultSuccess(PageCodeEnum.HTTP_RES_200); }    }

启动 MybatisPlusApplication 并拜访 http://localhost:8080/swagger-ui.html

好!接下来咱们看看swagger文档会有什么不同!

GlobalString 中的参数主动读取到了 swagger 中,咱们间接执行接口拜访:

并查看数据库是否有新增记录:

完满!至此咱们swagger再也不必手填参数数值了,间接丢给前端,你get到了吗!