-
自定义注解
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~