赞
踩
本功能在 Swagger 2.7.0 和 2.9.2 版本 测试通过 ,保证可正常使用,
有问题联系471801687@qq.com
关于Swagger2本身不支持Map/JSONObject传参 生成文档,在网上找了很多,大多是自定义注解,借助第三方插件动态生成类,或者重写Swagger2的多数文件,显得很复杂,而且要看很多代码,跟踪才能了解并修改为自己的,而且还时好时坏,但是这些资料又给我带来了新的灵感。
大体思路,
1、新建一个静态Map,存储自己新建的model变量(不需要创建实体类)
2、自定义注解,实现配置参数信息
3、继承Swagger的部分builder类,根据注解 创建自己的 model 塞入 静态Map
4、添加Swagger Aop切面,将静态Map 合并到 Swagger的model中返回
下面是实现代码
- import com.cloud.utils.util.baseenum.DataType;
-
- import java.lang.annotation.ElementType;
- import java.lang.annotation.Retention;
- import java.lang.annotation.RetentionPolicy;
- import java.lang.annotation.Target;
-
- /**
- * @author: fengyuan
- * @date 2021-6-3 17:23:28
- * @Description TODO Swagger2配置
- */
- @Target(ElementType.ANNOTATION_TYPE)
- @Retention(RetentionPolicy.RUNTIME)
- public @interface PropFy2 {
-
- String name(); // key
-
- String eg() default "";// 示例
-
- DataType type() default DataType.String; // 支持string、int、double
-
- String desc() default "";// 参数描述
-
- boolean required() default false; // 是否必传
-
- }
- import com.cloud.utils.util.baseenum.DataType;
-
- import java.lang.annotation.ElementType;
- import java.lang.annotation.Retention;
- import java.lang.annotation.RetentionPolicy;
- import java.lang.annotation.Target;
-
- /**
- * @author: fengyuan
- * @date 2021-6-3 17:23:28
- * @Description TODO Swagger2配置
- */
- @Target(ElementType.ANNOTATION_TYPE)
- @Retention(RetentionPolicy.RUNTIME)
- public @interface PropFy {
-
- String name(); // key
-
- String eg() default "";// 示例
-
- DataType type() default DataType.String; // 支持string、int、double
-
- String desc() default "";// 参数描述
-
- boolean required() default false; // 是否必传
-
- PropFy2[] map() default {};
-
- }
- import java.lang.annotation.ElementType;
- import java.lang.annotation.Retention;
- import java.lang.annotation.RetentionPolicy;
- import java.lang.annotation.Target;
-
- /**
- * @author: fengyuan
- * @date 2021-6-3 17:23:28
- * @Description TODO Swagger2配置
- */
- @Target({ElementType.METHOD})
- @Retention(RetentionPolicy.RUNTIME)
- public @interface ResObjFY {
-
- PropFy[] value() default {}; //请求属性值
-
- }
- import java.lang.annotation.ElementType;
- import java.lang.annotation.Retention;
- import java.lang.annotation.RetentionPolicy;
- import java.lang.annotation.Target;
-
- /**
- * @author: fengyuan
- * @date 2021-6-3 17:23:28
- * @Description TODO Swagger2配置
- */
- @Target({ElementType.PARAMETER})
- @Retention(RetentionPolicy.RUNTIME)
- public @interface ReqObjFy {
-
- PropFy[] value(); //对象属性值
-
- }
- //随便找个地方
- public static Map<String, Model> modelMap = new HashMap<>();
- //此为创建Model的方法,深度支持2级
- import com.cloud.utils.util.baseenum.DataType;
- import com.cloud.utils.utilabstract.BasePubFun;
- import io.swagger.models.ModelImpl;
- import io.swagger.models.properties.*;
- import org.apache.commons.lang3.StringUtils;
-
- import java.util.LinkedHashMap;
- import java.util.Map;
-
- /**
- * @author: fengyuan
- * @date 2021-6-3 15:17:49
- * @Description TODO Swagger2配置公共方法
- */
- public class SwaggerFun {
-
- public static String createModelRst(String name, PropFy[] pros) {
-
- createModel(name, pros);
-
- Map<String, Property> proMap = new LinkedHashMap<>();
-
- Property code = new StringProperty();
- code.setName("code");
- code.setDescription("状态'10000'成功,其他失败");
- code.setExample((Object) "10000");
- proMap.put("code", code);
-
- Property msg = new StringProperty();
- msg.setName("msg");
- msg.setDescription("提示");
- proMap.put("msg", msg);
-
- Property msgext = new StringProperty();
- msgext.setName("msgext");
- msgext.setDescription("详情");
- proMap.put("msgext", msgext);
-
- Property result = new RefProperty(name);
- result.setName("result");
- result.setDescription("结果集");
- proMap.put("result", result);
-
- Property success = new BooleanProperty();
- success.setName("success");
- success.setDescription("状态 true成功 false失败");
- proMap.put("success", success);
-
- //创建model
- String rstName = BasePubFun.format("RstData<{}>", name);
- ModelImpl model = new ModelImpl();
- model.setName(rstName);
- model.setProperties(proMap);
- model.setType("object");
- SwaggerFy.modelMap.put(rstName, model);
- return model.getName();
- }
-
- public static void createModel(String name, PropFy[] pros) {
-
- Map<String, Property> proMap = new LinkedHashMap<>();
- for (PropFy pro : pros) {
- Property property = null;
- try {
- if (DataType.String.equals(pro.type())) {
- property = new StringProperty();
- property.setExample(StringUtils.isBlank(pro.eg()) ? "" : (Object) pro.eg());
- } else if (DataType.Long.equals(pro.type())) {
- property = new LongProperty();
- property.setExample(StringUtils.isBlank(pro.eg()) ? 0L : Long.valueOf(pro.eg()));
- } else if (DataType.Integer.equals(pro.type())) {
- property = new IntegerProperty();
- property.setExample(StringUtils.isBlank(pro.eg()) ? 0 : Integer.valueOf(pro.eg()));
- } else if (DataType.Date.equals(pro.type())) {
- property = new DateProperty();
- property.setExample(StringUtils.isBlank(pro.eg()) ? "" : Boolean.valueOf(pro.eg()));
- } else if (DataType.Boolean.equals(pro.type())) {
- property = new BooleanProperty();
- property.setExample(StringUtils.isBlank(pro.eg()) ? "" : Boolean.valueOf(pro.eg()));
- } else if (DataType.Map.equals(pro.type())) {
- String tempName = name + "_" + pro.name();
- createModel(tempName, pro.map());
- property = new RefProperty(tempName);
- } else {
- property = new StringProperty();
- property.setExample((Object) pro.eg());
- }
- } catch (Exception e) {
- }
- property.setDescription(pro.desc());
- property.setRequired(pro.required());
- property.setName(pro.name());
- proMap.put(pro.name(), property);
- }
- ModelImpl model = new ModelImpl();
- model.setName(name);
- model.setProperties(proMap);
- model.setType("object");
- SwaggerFy.modelMap.put(name, model);
- }
-
- private static void createModel(String name, PropFy2[] pros) {
- Map<String, Property> proMap = new LinkedHashMap<>();
- for (PropFy2 pro : pros) {
- Property property = null;
- if (DataType.String.equals(pro.type())) {
- property = new StringProperty();
- property.setExample(StringUtils.isBlank(pro.eg()) ? "" : (Object) pro.eg());
- } else if (DataType.Long.equals(pro.type())) {
- property = new LongProperty();
- property.setExample(StringUtils.isBlank(pro.eg()) ? 0L : Long.valueOf(pro.eg()));
- } else if (DataType.Integer.equals(pro.type())) {
- property = new IntegerProperty();
- property.setExample(StringUtils.isBlank(pro.eg()) ? 0 : Integer.valueOf(pro.eg()));
- } else if (DataType.Date.equals(pro.type())) {
- property = new DateProperty();
- property.setExample(StringUtils.isBlank(pro.eg()) ? "" : Boolean.valueOf(pro.eg()));
- } else if (DataType.Boolean.equals(pro.type())) {
- property = new BooleanProperty();
- property.setExample(!StringUtils.isBlank(pro.eg()) && Boolean.valueOf(pro.eg()));
- }
- property.setDescription(pro.desc());
- property.setRequired(pro.required());
- property.setName(pro.name());
- proMap.put(pro.name(), property);
- }
- ModelImpl model = new ModelImpl();
- model.setName(name);
- model.setProperties(proMap);
- model.setType("object");
- SwaggerFy.modelMap.put(name, model);
- }
-
- }
- import com.alibaba.fastjson.JSONObject;
- import com.google.common.base.Optional;
- import org.springframework.core.annotation.Order;
- import org.springframework.stereotype.Component;
- import springfox.documentation.schema.ModelRef;
- import springfox.documentation.service.ResolvedMethodParameter;
- import springfox.documentation.spi.DocumentationType;
- import springfox.documentation.spi.service.ParameterBuilderPlugin;
- import springfox.documentation.spi.service.contexts.ParameterContext;
-
- import java.util.Map;
-
- /**
- * @author: fengyuan
- * @date 2021-6-3 15:17:49
- * @Description TODO Swagger2配置
- */
- @Component
- @Order // plugin加载顺序,默认是最后加载
- public class ParamReqPlugin implements ParameterBuilderPlugin {
-
- @Override
- public void apply(ParameterContext parameterContext) {
- ResolvedMethodParameter methodParameter = parameterContext.resolvedMethodParameter();
- // 判断是否需要修改对象ModelRef,这里我判断的是Map类型和JSONObject类型需要重新修改ModelRef对象
- if (!methodParameter.getParameterType().canCreateSubtype(Map.class) && methodParameter.getParameterType().canCreateSubtype(JSONObject.class)) {
- return;
- }
- Optional<ReqObjFy> optional = methodParameter.findAnnotation(ReqObjFy.class);
- if (!optional.isPresent()) {
- return;
- }
- String name = parameterContext.getOperationContext().requestMappingPattern().replace("/", "_").substring(1);
- SwaggerFun.createModel(name, optional.get().value());
- parameterContext.parameterBuilder().parameterType("body").modelRef(new ModelRef(name)).name(name);
- }
-
- @Override
- public boolean supports(DocumentationType delimiter) {
- return true;
- }
-
- }
- import com.cloud.utils.dto.RstData;
- import com.fasterxml.classmate.ResolvedType;
- import com.google.common.base.Optional;
- import org.springframework.core.annotation.Order;
- import org.springframework.stereotype.Component;
- import springfox.documentation.builders.ResponseMessageBuilder;
- import springfox.documentation.schema.ModelRef;
- import springfox.documentation.service.ResponseMessage;
- import springfox.documentation.spi.DocumentationType;
- import springfox.documentation.spi.service.OperationBuilderPlugin;
- import springfox.documentation.spi.service.contexts.OperationContext;
-
- import java.util.HashSet;
-
- /**
- * @author: fengyuan
- * @date 2021-6-3 15:17:49
- * @Description TODO Swagger2配置
- */
- @Component
- @Order // plugin加载顺序,默认是最后加载
- public class ParamResPlugin implements OperationBuilderPlugin {
-
- @Override
- public void apply(OperationContext operationContext) {
- ResolvedType returnType = operationContext.getReturnType();
- // 判断是否需要修改对象ModelRef,这里我判断的是RstData类型需要重新修改ModelRef对象
- if (!returnType.canCreateSubtype(RstData.class)) {
- return;
- }
- Optional<ResObjFY> optional = operationContext.findAnnotation(ResObjFY.class);
- if (!optional.isPresent()) {
- return;
- }
- String name = operationContext.requestMappingPattern().replace("/", "_").substring(1) + "_rst";
- String rstName = SwaggerFun.createModelRst(name, optional.get().value());
- ResponseMessage responseMessage = new ResponseMessageBuilder()
- .code(200).responseModel(new ModelRef(rstName))
- .build();
- HashSet<ResponseMessage> responseMessages = new HashSet<>();
- responseMessages.add(responseMessage);
- operationContext.operationBuilder().responseMessages(responseMessages);
- }
-
- @Override
- public boolean supports(DocumentationType delimiter) {
- return true;
- }
- }
-
- import io.swagger.models.Swagger;
- import org.aspectj.lang.ProceedingJoinPoint;
- import org.aspectj.lang.annotation.Around;
- import org.aspectj.lang.annotation.Aspect;
- import org.aspectj.lang.annotation.Pointcut;
- import org.springframework.stereotype.Component;
-
- /**
- * @author: fengyuan
- * @date 2021-6-3 17:23:28
- * @Description TODO Swagger2配置
- */
- @Aspect
- @Component
- public class SwaggerAop {
-
- @Pointcut(value = "execution(public * springfox.documentation.swagger2.mappers.ServiceModelToSwagger2MapperImpl.mapDocumentation(..))")
- public void point() {
- }
-
- @Around("point()")
- public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
- Swagger swagger = (Swagger) proceedingJoinPoint.proceed();
- swagger.getDefinitions().putAll(SwaggerFy.modelMap);
- return swagger;
- }
-
- }
- @PostMapping(value = "demo")
- @ApiOperation("请求参数配置方式,支持二级")
- @ResObjFY({
- @PropFy(name = "id", eg = "123", desc = "主键", type = DataType.Long, required = true),
- @PropFy(name = "row", desc = "具体数据", type = DataType.Map, map = {
- @PropFy2(name = "idCard", eg = "610126198911111111", desc = "身份证号", type = DataType.String, required = true),
- @PropFy2(name = "name", eg = "张三", desc = "姓名", required = true),
- @PropFy2(name = "sex", eg = "1", desc = "性别 1男 2女", type = DataType.Integer),
- })
- })
- public RstData demo(
- @ReqObjFy({
- @PropFy(name = "id", eg = "123", desc = "主键", type = DataType.Long, required = true),
- @PropFy(name = "row", desc = "具体数据", type = DataType.Map, map = {
- @PropFy2(name = "idCard", eg = "610126198911111111", desc = "身份证号", type = DataType.String, required = true),
- @PropFy2(name = "name", eg = "张三", desc = "姓名", required = true),
- @PropFy2(name = "sex", eg = "1", desc = "性别 1男 2女", type = DataType.Integer),
- })
- })
- @RequestBody Map<String, Object> params) {
- return RstData.success(params);
- }
效果图
2.7.0
2.9.2
下面为Swagger扩展Ui的依赖及效果图 <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>swagger-bootstrap-ui</artifactId> <version>1.9.6</version> </dependency>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。