mirror of
https://gitee.com/gz-yami/mall4j.git
synced 2026-03-22 09:17:16 +08:00
使用spring doc代替spring fox,openapi 3.0规范
This commit is contained in:
@@ -1,17 +1,29 @@
|
||||
package com.yami.shop.common.config;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.yami.shop.common.util.PageParam;
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import org.apache.commons.lang3.reflect.FieldUtils;
|
||||
import org.springdoc.api.annotations.ParameterObject;
|
||||
import org.springdoc.core.DelegatingMethodParameter;
|
||||
import org.springdoc.core.GenericParameterService;
|
||||
import org.springdoc.core.PropertyResolverUtils;
|
||||
import org.springdoc.core.SpringDocUtils;
|
||||
import org.springdoc.core.customizers.DelegatingMethodParameterCustomizer;
|
||||
import org.springdoc.core.providers.ObjectMapperProvider;
|
||||
import org.springdoc.core.providers.WebConversionServiceProvider;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
|
||||
import springfox.documentation.spring.web.plugins.WebFluxRequestHandlerProvider;
|
||||
import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider;
|
||||
import org.springframework.core.MethodParameter;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* @author FrozenWatermelon
|
||||
@@ -20,36 +32,68 @@ import java.util.stream.Collectors;
|
||||
@Configuration
|
||||
public class Swagger2Config {
|
||||
|
||||
static {
|
||||
SpringDocUtils.getConfig().addAnnotationsToIgnore(JsonIgnore.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public static BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
|
||||
return new BeanPostProcessor() {
|
||||
public GenericParameterService parameterBuilder(PropertyResolverUtils propertyResolverUtils, Optional<WebConversionServiceProvider> optionalWebConversionServiceProvider, ObjectMapperProvider objectMapperProvider) {
|
||||
return new GenericParameterService(propertyResolverUtils, delegatingMethodParameterCustomizer(),
|
||||
optionalWebConversionServiceProvider,objectMapperProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider) {
|
||||
customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
|
||||
}
|
||||
return bean;
|
||||
// 解决@ParameterObject和@Hidden, JsonIgnore同时使用不生效的问题
|
||||
private Optional<DelegatingMethodParameterCustomizer> delegatingMethodParameterCustomizer() { // NOSONAR
|
||||
return Optional.of((originalMethodParam, methodParam) -> {
|
||||
// 这个方法类拥有的注解
|
||||
Annotation[] annotations = originalMethodParam.getParameterType().getAnnotations();
|
||||
boolean typeContainParameterObject = false;
|
||||
if (annotations.length > 0) {
|
||||
List<? extends Class<? extends Annotation>> annotationTypes = Arrays.stream(annotations).map(Annotation::annotationType).collect(Collectors.toList());
|
||||
typeContainParameterObject = annotationTypes.contains(ParameterObject.class);
|
||||
}
|
||||
|
||||
private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) {
|
||||
List<T> copy = mappings.stream()
|
||||
.filter(mapping -> mapping.getPatternParser() == null)
|
||||
.collect(Collectors.toList());
|
||||
mappings.clear();
|
||||
mappings.addAll(copy);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {
|
||||
if (typeContainParameterObject
|
||||
|| (originalMethodParam.hasParameterAnnotations() && originalMethodParam.hasParameterAnnotation(ParameterObject.class))) {
|
||||
try {
|
||||
Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
|
||||
field.setAccessible(true);
|
||||
return (List<RequestMappingInfoHandlerMapping>) field.get(bean);
|
||||
} catch (IllegalArgumentException | IllegalAccessException e) {
|
||||
throw new IllegalStateException(e);
|
||||
if (isParameterIgnore(originalMethodParam, methodParam)) {
|
||||
Field field = FieldUtils.getDeclaredField(DelegatingMethodParameter.class, "additionalParameterAnnotations", true);
|
||||
try {
|
||||
field.set(methodParam, new Annotation[] {new Hidden() { // NOSONAR
|
||||
@Override
|
||||
public Class<? extends Annotation> annotationType() {
|
||||
return Hidden.class;
|
||||
}}
|
||||
});
|
||||
} catch (IllegalArgumentException|IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
} catch (NoSuchFieldException | SecurityException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isParameterIgnore(MethodParameter originalMethodParam, MethodParameter methodParam) throws NoSuchFieldException, SecurityException {
|
||||
String parameterName = StrUtil.isBlank(methodParam.getParameterName())? "":methodParam.getParameterName();
|
||||
String fieldName = parameterName.indexOf('.') == -1 ? parameterName : parameterName.substring(0, parameterName.indexOf('.'));
|
||||
// 解决mybatis-plus返回的查询参数污染的问题
|
||||
if (originalMethodParam.getParameterType().isAssignableFrom(PageParam.class)) {
|
||||
if ("searchCount".equals(fieldName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Field declaredField;
|
||||
try {
|
||||
declaredField = originalMethodParam.getParameterType().getDeclaredField(fieldName);
|
||||
} catch (NoSuchFieldException e) {
|
||||
e.printStackTrace();
|
||||
declaredField = originalMethodParam.getParameterType().getSuperclass().getDeclaredField(fieldName);
|
||||
}
|
||||
return Stream.of(declaredField.getAnnotations())
|
||||
.filter(annot -> Arrays.asList(Hidden.class, JsonIgnore.class).contains(annot.annotationType())).count() > 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
|
||||
*
|
||||
* https://www.mall4j.com/
|
||||
*
|
||||
* 未经允许,不可做商业用途!
|
||||
*
|
||||
* 版权所有,侵权必究!
|
||||
*/
|
||||
|
||||
package com.yami.shop.common.serializer.springfox;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import springfox.documentation.spring.web.json.JacksonModuleRegistrar;
|
||||
import springfox.documentation.spring.web.json.JsonSerializer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author LGH
|
||||
*/
|
||||
@Configuration
|
||||
public class SpringFoxJsonSerializerConfig {
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public JsonSerializer yamiSpringfoxJsonSerializer(List<JacksonModuleRegistrar> moduleRegistrars) {
|
||||
return new SpringfoxJsonSerializer(moduleRegistrars);
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
|
||||
*
|
||||
* https://www.mall4j.com/
|
||||
*
|
||||
* 未经允许,不可做商业用途!
|
||||
*
|
||||
* 版权所有,侵权必究!
|
||||
*/
|
||||
|
||||
package com.yami.shop.common.serializer.springfox;
|
||||
|
||||
import io.swagger.models.Operation;
|
||||
import io.swagger.models.Swagger;
|
||||
import io.swagger.models.parameters.Parameter;
|
||||
import springfox.documentation.spring.web.json.JacksonModuleRegistrar;
|
||||
import springfox.documentation.spring.web.json.Json;
|
||||
import springfox.documentation.spring.web.json.JsonSerializer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 自定义Swagger 的序列化,去除分页参数中的records值
|
||||
* @author LGH
|
||||
*/
|
||||
public class SpringfoxJsonSerializer extends JsonSerializer {
|
||||
|
||||
public SpringfoxJsonSerializer(List<JacksonModuleRegistrar> modules) {
|
||||
super(modules);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Json toJson(Object toSerialize) {
|
||||
if (!(toSerialize instanceof Swagger)) {
|
||||
return super.toJson(toSerialize);
|
||||
}
|
||||
Swagger swagger = (Swagger)toSerialize;
|
||||
|
||||
swagger.getPaths().forEach((key, path) ->{
|
||||
Operation get = path.getGet();
|
||||
if (get != null) {
|
||||
|
||||
List<Parameter> parameters = get.getParameters();
|
||||
if (parameters != null) {
|
||||
parameters.removeIf(parameter -> parameter.getName().startsWith("records[0]."));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return super.toJson(swagger);
|
||||
// return super.toJson(toSerialize);
|
||||
}
|
||||
}
|
||||
@@ -11,42 +11,56 @@
|
||||
package com.yami.shop.common.util;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import org.springdoc.api.annotations.ParameterObject;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@Schema
|
||||
@ParameterObject
|
||||
public class PageParam<T> extends Page<T> {
|
||||
|
||||
/**
|
||||
* 查询数据列表
|
||||
*/
|
||||
@ApiParam(hidden = true)
|
||||
private List<T> records;
|
||||
/**
|
||||
* 总数
|
||||
*/
|
||||
@ApiParam(hidden = true)
|
||||
private long total = 0;
|
||||
|
||||
/**
|
||||
* 每页显示条数,默认 10
|
||||
*/
|
||||
@ApiParam(value = "每页大小,默认10",required = false, defaultValue = "10")
|
||||
@Schema(description = "每页大小,默认10")
|
||||
private long size = 10;
|
||||
|
||||
/**
|
||||
* 当前页
|
||||
*/
|
||||
@ApiParam(value = "当前页,默认1",required = false,defaultValue = "1")
|
||||
@Schema(description = "当前页,默认1")
|
||||
private long current = 1;
|
||||
|
||||
/**
|
||||
* 查询数据列表
|
||||
*/
|
||||
@Hidden
|
||||
private List<T> records;
|
||||
/**
|
||||
* 总数
|
||||
*/
|
||||
@Hidden
|
||||
private long total = 0;
|
||||
|
||||
|
||||
/**
|
||||
* 是否进行 count 查询
|
||||
*/
|
||||
@ApiParam(hidden = true)
|
||||
@JsonIgnore
|
||||
private boolean isSearchCount = true;
|
||||
|
||||
@JsonIgnore
|
||||
private String countId;
|
||||
@JsonIgnore
|
||||
private Long maxLimit;
|
||||
@JsonIgnore
|
||||
private boolean optimizeCountSql;
|
||||
|
||||
@Override
|
||||
@ApiParam(hidden = true)
|
||||
public List<T> getRecords() {
|
||||
return this.records;
|
||||
}
|
||||
@@ -68,7 +82,7 @@ public class PageParam<T> extends Page<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
@ApiParam(hidden = true)
|
||||
@JsonIgnore
|
||||
public boolean getSearchCount() {
|
||||
if (total < 0) {
|
||||
return false;
|
||||
@@ -77,7 +91,6 @@ public class PageParam<T> extends Page<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
@ApiParam(hidden = true)
|
||||
public boolean isSearchCount() {
|
||||
if (total < 0) {
|
||||
return false;
|
||||
@@ -98,7 +111,11 @@ public class PageParam<T> extends Page<T> {
|
||||
|
||||
@Override
|
||||
public Page<T> setSize(long size) {
|
||||
this.size = size;
|
||||
if (size > 100) {
|
||||
this.size = 100;
|
||||
} else {
|
||||
this.size = size;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -112,4 +129,24 @@ public class PageParam<T> extends Page<T> {
|
||||
this.current = current;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
@Deprecated
|
||||
public String getCountId() {
|
||||
return this.countId;
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
@Deprecated
|
||||
public Long getMaxLimit() {
|
||||
return this.maxLimit;
|
||||
}
|
||||
|
||||
|
||||
/** @deprecated */
|
||||
@Deprecated
|
||||
public boolean isOptimizeCountSql() {
|
||||
return this.optimizeCountSql;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user