Swagger2 自定义注解 :解决一个简单的model类 适用于controller的多个方法

  1. 自定义注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author wupeng
 * @date 2019/8/26 9:58
 * @desc 不需要的DTO属性的值 【ignoreProperties:igp】
 *
 */
@Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiIgp {
    String value(); //对象属性值
}

---------------------------------------------------------------------------
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author wupeng
 * @date 2019/8/26 9:58
 * @desc 需要的DTO属性的值 【containProperties:cp】
 *
 */
@Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Apicp {
    String value(); //对象属性值
}

2. model

/**
 * @author wupeng
 * @date 2019/11/1 15:43
 * @desc
 */
@Data
@ApiModel("医院基础信息")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public class HospitalBaseInfoDTO extends WebBaseDTO implements Serializable {
    private static final long serialVersionUID = 1L;

    @ApiModelProperty( "组织机构代码")
    private String zzjgdm;

    @ApiModelProperty("组织科室代码")
    private String zzksid;
    @ApiModelProperty("科室详细信息:1返回科室介绍等大数据 否则不返回")
    private String ksxxxx;

    @ApiModelProperty("职工代码")
    private String zzzgid;
    @ApiModelProperty("工号")
    private String zzzggh;
    @ApiModelProperty("1返回介绍等大数据,否则不返回")
    private String zgxxxx;

    @ApiModelProperty("收费项目代码")
    private Integer sfxmid;
    @ApiModelProperty("药品产地代码")
    private String ypcdid;
    @ApiModelProperty("组织药品类型:1 西 2 中成4中草")
    private String zzyplx;

    @ApiModelProperty("诊疗项目序号")
    private Integer zlxmid;
    @ApiModelProperty("诊疗项目类别")
    private String zlxmlb;

    @ApiModelProperty("医疗分组序号")
    private String yzfzid;
    @ApiModelProperty("病人类别序号")
    private String brlbid;

    @ApiModelProperty("疾病代码序号")
    private String jbdmid;

    @ApiModelProperty("手术房间序号")
    private String ssfjid;
    @ApiModelProperty("手术名称序号")
    private String ssmcid;
    @ApiModelProperty("组织手术名称")
    private String zzssmc;

   
}

3. swagger配置

 

import cn.hutool.core.util.IdUtil;
import com.alibaba.ttl.internal.javassist.*;
import com.alibaba.ttl.internal.javassist.bytecode.AnnotationsAttribute;
import com.alibaba.ttl.internal.javassist.bytecode.ConstPool;
import com.alibaba.ttl.internal.javassist.bytecode.annotation.Annotation;
import com.alibaba.ttl.internal.javassist.bytecode.annotation.StringMemberValue;
import com.fasterxml.classmate.TypeResolver;
import com.google.common.base.Optional;
import com.rubikstack.ms.api.common.anno.ApiIgp;
import com.rubikstack.ms.api.common.anno.Apicp;
import io.micrometer.core.instrument.util.StringUtils;
import io.swagger.annotations.ApiModelProperty;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
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.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author wupeng
 * @date 2019/8/26 9:59
 * @desc 读取自定义忽略的dto属性并动态生成model
 */
@Configuration
@Order   //plugin加载顺序,默认是最后加载
public class SwaggerModelReader implements ParameterBuilderPlugin {
    @Autowired
    private TypeResolver typeResolver;

    @Override
    public void apply(ParameterContext parameterContext) {
        ResolvedMethodParameter methodParameter = parameterContext.resolvedMethodParameter();
        Optional<ApiIgp> apiIgp = methodParameter.findAnnotation(ApiIgp.class);
        Optional<Apicp> apicp = methodParameter.findAnnotation(Apicp.class);
        if (apiIgp.isPresent() || apicp.isPresent()) {
            Class originClass = parameterContext.resolvedMethodParameter().getParameterType().getErasedType();
            String name = originClass.getSimpleName() + "Model" + IdUtil.objectId();  //model 名称
            String properties = null;
            Integer annoType = 0;
            if (apiIgp.isPresent()){
                properties = apiIgp.get().value();
            }else {
                properties = apicp.get().value();
                annoType = 1;
            }
            try {
                parameterContext.getDocumentationContext()
                        .getAdditionalModels()
                        .add(typeResolver.resolve(createRefModelIgp(properties, name, originClass,annoType)));  //像documentContext的Models中添加我们新生成的Class
            } catch (NotFoundException e) {
                e.printStackTrace();
            }

            parameterContext.parameterBuilder()  //修改model参数的ModelRef为我们动态生成的class
                    .parameterType("body")
                    .modelRef(new ModelRef(name))
                    .name(name);
        }
    }


    /**
     * 根据propertys中的值动态生成含有Swagger注解的javaBeen
     */
    private Class createRefModelIgp(String propertys, String name, Class origin, Integer annoType) throws NotFoundException {
        ClassPool pool = ClassPool.getDefault();
        CtClass ctClass = pool.makeClass(origin.getPackage().getName()+"."+name);
        try {
            Field[] fields = origin.getDeclaredFields();
            List<Field> fieldList = Arrays.asList(fields);
            List<String> dealProperties = Arrays.asList(propertys.replace(" ","").split(","));//去掉空格并用逗号分割
            List<Field> dealFileds = fieldList.stream().filter(
                    s -> annoType == 0 ?  (!(dealProperties.contains(s.getName()))) : dealProperties.contains(s.getName())
            ).collect(Collectors.toList());
            createCtFileds(dealFileds,ctClass);
            return ctClass.toClass();

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

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

    public void createCtFileds(List<Field> dealFileds, CtClass ctClass) throws CannotCompileException, NotFoundException {
        for (Field field : dealFileds) {
            CtField ctField = new CtField(ClassPool.getDefault().get(field.getType().getName()), field.getName(), ctClass);
            ctField.setModifiers(Modifier.PUBLIC);
            ApiModelProperty annotation = field.getAnnotation(ApiModelProperty.class);
            String apiModelPropertyValue = java.util.Optional.ofNullable(annotation).map(s -> s.value()).orElse("");
            if (StringUtils.isNotBlank(apiModelPropertyValue)) { //添加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(apiModelPropertyValue, constPool));
                attr.addAnnotation(ann);
                ctField.getFieldInfo().addAttribute(attr);
            }
            ctClass.addField(ctField);
        }
    }
}

4.使用示例

    @ApiOperation("医院信息")
    @PostMapping("hospitalInfo")
    public R hospitalInfo(@Apicp("zzjgdm")
                              @RequestBody HospitalBaseInfoDTO hospitalBaseInfoDto){
        hospitalBaseInfoDto.setTransId(HeaderEnums.HospitalInfo.TRANSID.getCode());
        hisApiService.hospitalInfo(hospitalBaseInfoDto);
        return R.ok().put("data", hospitalBaseInfoDto);
    }

    @ApiOperation("科室信息")
    @PostMapping("deptInfo")
    public R deptInfo(@Apicp("zzjgdm,zzksid,ksxxxx")
                          @RequestBody HospitalBaseInfoDTO hospitalBaseInfoDto){
        hospitalBaseInfoDto.setTransId(HeaderEnums.DeptInfo.TRANSID.getCode());
        hisApiService.hospitalInfo(hospitalBaseInfoDto);
        return R.ok().put("data", hospitalBaseInfoDto);
    }

5.总结: 

     通过ParameterBuilderPlugin  将之前得model 通过自定义注解标识 ,将DTO中得属性通过jassite 动态通过反射动态的对属性进行删减生成新 得类做为swagger 得model~

发布了192 篇原创文章 · 获赞 45 · 访问量 33万+

猜你喜欢

转载自blog.csdn.net/flymoringbird/article/details/102919322