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~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章