-
自定義註解
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~