javassist solve Swagger2 a DTO for multiple interfaces

background: 

    Recently received a mission boss, with a DTO applied to multiple interfaces, via an interface on the notes do not need to have to solve the hide on the property and then swagger.

result:

Applied to a DTO two interfaces

 

Code

   step one

1.引入pom
      <!-- swagger2 -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>

2.springBoot  开启
    @SpringBootApplication
    @EnableAsync
    @EnableSwagger2 //开启swagger
    public class RenrenApplication   {
	    public static void main(String[] args) {
		    SpringApplication.run(RenrenApplication.class, args);
	    }

    }

Step Two

1.自定义注解 

@Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiIgp {
        String[] value(); //对象属性值
}


2. 实现parameterBuilderPlugin 
ps: 注意这里用的是alibaba 的javassist 的包最好



@Component
@Order   //plugin加载顺序,默认是最后加载
public class MapApiReader implements ParameterBuilderPlugin {
    @Autowired
    private TypeResolver typeResolver;

    @Override
    public void apply(ParameterContext parameterContext) {
        ResolvedMethodParameter methodParameter = parameterContext.resolvedMethodParameter();
        Class originClass = parameterContext.resolvedMethodParameter().getParameterType().getErasedType();


            Optional<ApiIgp> optional = methodParameter.findAnnotation(ApiIgp.class);
            if (optional.isPresent()) {
                Random random = new Random();
                String name = originClass.getSimpleName() + "Model" + random.nextInt(100);  //model 名称
                String[] properties = optional.get().value();
                try {
                    parameterContext.getDocumentationContext()
                            .getAdditionalModels()
                            .add(typeResolver.resolve(createRefModelIgp(properties, originClass.getPackage()+"."+name, originClass)));  //像documentContext的Models中添加我们新生成的Class
                } catch (Exception e) {
                    e.printStackTrace();
                }
                parameterContext.parameterBuilder()  //修改Map参数的ModelRef为我们动态生成的class
                        .parameterType("body")
                        .modelRef(new ModelRef(name))
                        .name(name);
        }

    }

    private Class createRefModelIgp(String[] propertys, String name, Class origin) throws NotFoundException {
        ClassPool pool = ClassPool.getDefault();
        CtClass ctClass = pool.makeClass( name);
        try {
            Field[] fields = origin.getDeclaredFields();
            List<Field> fieldList = Arrays.asList(fields);
            List<String> ignorePropertys = Arrays.asList(propertys);
            List<Field> dealFileds = fieldList.stream().filter(s -> !ignorePropertys.contains(s.getName())).collect(Collectors.toList());
            for (Field field : dealFileds) {
                CtField ctField = new CtField(ClassPool.getDefault().get(field.getType().getName()), field.getName(), ctClass);
                ctField.setModifiers(Modifier.PUBLIC);
                ApiModelProperty ampAnno = origin.getDeclaredField(field.getName()).getAnnotation(ApiModelProperty.class);
                String attributes = java.util.Optional.ofNullable(ampAnno).map(s->s.value()).orElse("");
                if (StringUtils.isNotBlank(attributes) ){ //添加model属性说明
                    ConstPool constPool = ctClass.getClassFile().getConstPool();
                    AnnotationsAttribute attr = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag);
                    Annotation ann = new Annotation(ApiModelProperty.class.getName(), constPool);
                    ann.addMemberValue("value", new StringMemberValue(attributes, constPool));
                    attr.addAnnotation(ann);
                    ctField.getFieldInfo().addAttribute(attr);
                }
                ctClass.addField(ctField);
            }
            return ctClass.toClass();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }




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

Step three: 

 

public class AppCustomController {
    @Autowired
    private UserService userService;


    @PostMapping("test1")
    @ApiOperation("form测试1")
    public R custom(@RequestBody RegisterForm form){
        return R.ok();
    }

    @PostMapping("test2")
    @ApiOperation("form测试2")
    public R test2(@ApiIgp ({"name","addr"})  // 这里把你不需要的DTO属性中的值填写上
                       @RequestBody RegisterForm form){
        return R.ok();
    }
}

to sum up

  I am here incorporated by javassist this class swagger scalable plug-ins to solve this problem, by custom annotation property values ​​do not need to remove the swagger page. This will only affect the display of the page, it will not affect the received parameters.

expand

  Of course, here you can also handle custom MapApiReader class to "being with" this problem, you need to keep the property, or that each request is unity plus a property description can be done.

ps (here javassist best use alibaba exception does not affect the whole swagger)

He published 192 original articles · won praise 45 · views 330 000 +

Guess you like

Origin blog.csdn.net/flymoringbird/article/details/100103893
dto