Commit 837337c6 by qiuweili123

add dubbo swagger

parent 5970f716
...@@ -44,18 +44,6 @@ ...@@ -44,18 +44,6 @@
<artifactId>commons-lang3</artifactId> <artifactId>commons-lang3</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId> <groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId> <artifactId>fastjson</artifactId>
</dependency> </dependency>
......
...@@ -26,6 +26,7 @@ public class ApolloContextInitializer implements ApplicationContextInitializer<C ...@@ -26,6 +26,7 @@ public class ApolloContextInitializer implements ApplicationContextInitializer<C
if (!StringUtils.isEmpty(appId)) { if (!StringUtils.isEmpty(appId)) {
System.setProperty("app.id", appId); System.setProperty("app.id", appId);
System.setProperty("apollo.cacheDir", cacheDir); System.setProperty("apollo.cacheDir", cacheDir);
System.setProperty("apollo.bootstrap.enabled","true");
System.setProperty("apollo.bootstrap.eagerLoad.enabled","true"); System.setProperty("apollo.bootstrap.eagerLoad.enabled","true");
} }
} }
......
...@@ -34,7 +34,8 @@ ...@@ -34,7 +34,8 @@
<properties> <properties>
<java.version>1.8</java.version> <java.version>1.8</java.version>
<dubbo.version>2.7.1</dubbo.version> <dubbo-starter.version>2.7.1</dubbo-starter.version>
<dubbo.version>2.7.2</dubbo.version>
<matrix.version>1.0.1-DEV-SNAPSHOT</matrix.version> <matrix.version>1.0.1-DEV-SNAPSHOT</matrix.version>
</properties> </properties>
...@@ -169,16 +170,31 @@ ...@@ -169,16 +170,31 @@
<artifactId>guava</artifactId> <artifactId>guava</artifactId>
<version>20.0</version> <version>20.0</version>
</dependency> </dependency>
<!--spring boot-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.6.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Aapche Dubbo --> <!-- Aapche Dubbo -->
<dependency> <dependency>
<groupId>org.apache.dubbo</groupId> <groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId> <artifactId>dubbo-dependencies-bom</artifactId>
<version>${dubbo.version}</version> <version>${dubbo.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo-starter.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.dubbo</groupId> <groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId> <artifactId>dubbo</artifactId>
<version>2.7.2</version> <version>${dubbo.version}</version>
<exclusions> <exclusions>
<exclusion> <exclusion>
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
...@@ -226,11 +242,7 @@ ...@@ -226,11 +242,7 @@
<artifactId>swagger-bootstrap-ui</artifactId> <artifactId>swagger-bootstrap-ui</artifactId>
<version>1.9.3</version> <version>1.9.3</version>
</dependency> </dependency>
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>swagger-dubbo</artifactId>
<version>2.0.1</version>
</dependency>
<!--spring cloud--> <!--spring cloud-->
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
......
...@@ -29,10 +29,26 @@ ...@@ -29,10 +29,26 @@
<groupId>org.apache.dubbo</groupId> <groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId> <artifactId>dubbo-spring-boot-starter</artifactId>
</dependency> </dependency>
<!--swagger2-->
<dependency> <dependency>
<groupId>com.deepoove</groupId> <groupId>io.springfox</groupId>
<artifactId>swagger-dubbo</artifactId> <artifactId>springfox-swagger2</artifactId>
</dependency> </dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-core</artifactId>
<version>1.5.22</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>
\ No newline at end of file
package com.secoo.mall.config; package com.secoo.mall.common.config;
import com.deepoove.swagger.dubbo.annotations.EnableDubboSwagger;
import com.github.xiaoymin.swaggerbootstrapui.annotations.EnableSwaggerBootstrapUI; import com.github.xiaoymin.swaggerbootstrapui.annotations.EnableSwaggerBootstrapUI;
import com.secoo.mall.common.core.condition.ProdEnvCondition; import com.secoo.mall.common.core.condition.ProdEnvCondition;
import com.secoo.mall.dubbo.swagger.annotations.EnableDubboSwagger;
import com.secoo.mall.web.annotation.ApiController; import com.secoo.mall.web.annotation.ApiController;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
...@@ -16,6 +16,8 @@ import springfox.documentation.spi.DocumentationType; ...@@ -16,6 +16,8 @@ import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2; import springfox.documentation.swagger2.annotations.EnableSwagger2;
;
@Configuration @Configuration
@EnableSwagger2 @EnableSwagger2
@EnableSwaggerBootstrapUI @EnableSwaggerBootstrapUI
...@@ -57,4 +59,5 @@ public class SwaggerConfig { ...@@ -57,4 +59,5 @@ public class SwaggerConfig {
.description("更多内容请关注:http://apims.siku.cn") .description("更多内容请关注:http://apims.siku.cn")
.build(); .build();
} }
} }
\ No newline at end of file
...@@ -38,6 +38,9 @@ public class ProtocolExceptionHandler { ...@@ -38,6 +38,9 @@ public class ProtocolExceptionHandler {
private String getMsg(BusinessException e) { private String getMsg(BusinessException e) {
if (messageSource == null) {
return e.getMsg();
}
return messageSource.getMessage(e.getMsg(), e.getArgs(), LocaleContextHolder.getLocale()); return messageSource.getMessage(e.getMsg(), e.getArgs(), LocaleContextHolder.getLocale());
} }
} }
package com.secoo.mall.dubbo.filter; package com.secoo.mall.dubbo.filter;
import com.secoo.mall.common.core.exception.BusinessException;
import com.secoo.mall.common.core.exception.ParameterException;
import com.secoo.mall.common.core.exception.SystemInternalException; import com.secoo.mall.common.core.exception.SystemInternalException;
import com.secoo.mall.common.handler.ProtocolExceptionHandler; import com.secoo.mall.common.handler.ProtocolExceptionHandler;
import com.secoo.mall.common.util.response.ResponseUtil; import com.secoo.mall.common.util.response.ResponseUtil;
...@@ -15,7 +17,7 @@ import org.springframework.web.method.annotation.ExceptionHandlerMethodResolver; ...@@ -15,7 +17,7 @@ import org.springframework.web.method.annotation.ExceptionHandlerMethodResolver;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@Activate( @Activate(
group = {CommonConstants.PROVIDER} group = {CommonConstants.PROVIDER}, order = 1000
) )
public class DefaultExceptionFilter extends ExceptionFilter implements Filter { public class DefaultExceptionFilter extends ExceptionFilter implements Filter {
private Logger log = LoggerFactory.getLogger(DefaultExceptionFilter.class); private Logger log = LoggerFactory.getLogger(DefaultExceptionFilter.class);
...@@ -38,14 +40,12 @@ public class DefaultExceptionFilter extends ExceptionFilter implements Filter { ...@@ -38,14 +40,12 @@ public class DefaultExceptionFilter extends ExceptionFilter implements Filter {
@Override @Override
public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) { public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
if (appResponse.hasException() && GenericService.class != invoker.getInterface()) { if (appResponse.hasException() && GenericService.class != invoker.getInterface()) {
Exception exception = getException(appResponse.getException());
Exception exception = (Exception) appResponse.getException();
Method method = resolver.resolveMethod(exception); Method method = resolver.resolveMethod(exception);
try { try {
Object realResult = method.invoke(this, exception); Object realResult = method.invoke(this, exception);
appResponse.setValue(realResult); appResponse.setValue(realResult);
} catch (Exception e) { } catch (Exception e) {
appResponse.setValue(ResponseUtil.getFailResponse(new SystemInternalException())); appResponse.setValue(ResponseUtil.getFailResponse(new SystemInternalException()));
} }
...@@ -59,6 +59,26 @@ public class DefaultExceptionFilter extends ExceptionFilter implements Filter { ...@@ -59,6 +59,26 @@ public class DefaultExceptionFilter extends ExceptionFilter implements Filter {
logger.error("Got unchecked and undeclared exception which called by " + RpcContext.getContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e); logger.error("Got unchecked and undeclared exception which called by " + RpcContext.getContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e);
} }
private Exception getException(Throwable throwable) {
Exception exception = null;
String className = throwable.getClass().getSimpleName();
switch (className) {
case "BusinessException":
exception = (BusinessException) throwable;
break;
case "SystemInternalException":
exception = (SystemInternalException) throwable;
break;
case "ParameterException":
exception = (ParameterException) throwable;
break;
default:
exception = (Exception) throwable;
}
return exception;
}
} }
......
package com.secoo.mall.dubbo.swagger.annotations;
import org.springframework.context.annotation.ComponentScan;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value = {java.lang.annotation.ElementType.TYPE})
@Documented
@ComponentScan(basePackages = {"com.secoo.mall.dubbo.swagger.config",
"com.secoo.mall.dubbo.swagger.controller", "com.secoo.mall.common.provider"})
public @interface EnableDubboSwagger {
}
package com.secoo.mall.dubbo.swagger.config;
import com.secoo.mall.dubbo.swagger.http.ReferenceManager;
import io.swagger.config.SwaggerConfig;
import io.swagger.models.Contact;
import io.swagger.models.Info;
import io.swagger.models.Swagger;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.ApplicationConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.servlet.ServletContext;
import java.text.MessageFormat;
@Component
public class DubboPropertyConfig implements SwaggerConfig {
@Value("${swagger.dubbo.application.version:}")
private String version;
@Value("${swagger.dubbo.application.groupId:}")
private String groupId;
@Value("${swagger.dubbo.application.artifactId:}")
private String artifactId;
@Autowired
private ServletContext servletContext;
private static String mavenDependency = "&lt;dependency&gt;<br/>"
+ "&nbsp;&nbsp;&nbsp;&nbsp;&lt;groupId&gt;{0}&lt;/groupId&gt;<br/>"
+ "&nbsp;&nbsp;&nbsp;&nbsp;&lt;artifactId&gt;{1}&lt;/artifactId&gt;<br/>"
+ "&nbsp;&nbsp;&nbsp;&nbsp;&lt;version&gt;{2}&lt;/version&gt;<br/>"
+ "&lt;/dependency&gt;<br/>";
@Override
public Swagger configure(Swagger swagger) {
ApplicationConfig application = ReferenceManager.getInstance().getApplication();
if (null != application) {
Info info = swagger.getInfo();
if (info == null) {
info = new Info();
swagger.setInfo(info);
}
info.setTitle(application.getName());
version = StringUtils.isNotBlank(version) ? version : application.getVersion();
if (StringUtils.isNotBlank(groupId)
&& StringUtils.isNotBlank(artifactId)
&& StringUtils.isNotBlank(version)) {
info.setDescription(MessageFormat.format(mavenDependency, groupId, artifactId, version));
}
info.setVersion(StringUtils.isNotBlank(version) ? version : "");
Contact contact = new Contact();
info.setContact(contact);
contact.setName(application.getOwner());
}
setBashPath(swagger);
return swagger;
}
private void setBashPath(Swagger swagger) {
if (StringUtils.isEmpty(swagger.getBasePath())) {
swagger.setBasePath(StringUtils.isEmpty(servletContext.getContextPath()) ? "/" : servletContext.getContextPath());
}
}
@Override
public String getFilterClass() {
return null;
}
}
package com.secoo.mall.dubbo.swagger.config;
import com.secoo.mall.dubbo.swagger.http.ReferenceManager;
import io.swagger.config.Scanner;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.Set;
@Component
public class DubboServiceScanner implements Scanner {
@Override
public Set<Class<?>> classes() {
return interfaceMapRef().keySet();
}
public Map<Class<?>, Object> interfaceMapRef() {
return ReferenceManager.getInstance().getInterfaceMapRef();
}
@Override
public boolean getPrettyPrint() {
return false;
}
@Override
public void setPrettyPrint(boolean shouldPrettyPrint) {
}
}
package com.secoo.mall.dubbo.swagger.config;
import io.swagger.models.Swagger;
import org.springframework.stereotype.Component;
@Component
public class SwaggerDocCache {
private Swagger swagger;
public Swagger getSwagger() {
return swagger;
}
public void setSwagger(Swagger swagger) {
this.swagger = swagger;
}
}
package com.secoo.mall.dubbo.swagger.controller;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.secoo.mall.dubbo.swagger.http.HttpMatch;
import com.secoo.mall.dubbo.swagger.http.ReferenceManager;
import com.secoo.mall.dubbo.swagger.reader.NameDiscover;
import io.swagger.annotations.Api;
import io.swagger.util.Json;
import io.swagger.util.PrimitiveType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Map.Entry;
@Controller
@RequestMapping("${swagger.dubbo.http:h}")
@Api(hidden = true)
public class DubboHttpController {
private static Logger logger = LoggerFactory.getLogger(DubboHttpController.class);
private static final String CLUSTER_RPC = "rpc";
@Value("${swagger.dubbo.enable:true}")
private boolean enable = true;
@Value("${swagger.dubbo.cluster:rpc}")
private String cluster = CLUSTER_RPC;
@RequestMapping(value = "/{interfaceClass}/{methodName}", produces = "application/json; charset=utf-8")
@ResponseBody
public ResponseEntity<String> invokeDubbo(@PathVariable("interfaceClass") String interfaceClass,
@PathVariable("methodName") String methodName, HttpServletRequest request,
HttpServletResponse response) throws Exception {
return invokeDubbo(interfaceClass, methodName, null, request, response);
}
@RequestMapping(value = "/{interfaceClass}/{methodName}/{operationId}", produces = "application/json; charset=utf-8")
@ResponseBody
public ResponseEntity<String> invokeDubbo(@PathVariable("interfaceClass") String interfaceClass,
@PathVariable("methodName") String methodName,
@PathVariable("operationId") String operationId, HttpServletRequest request,
HttpServletResponse response) throws Exception {
if (!enable) {
return new ResponseEntity<String>(HttpStatus.NOT_FOUND);
}
Object ref = null;
Method method = null;
Object result = null;
Entry<Class<?>, Object> entry = ReferenceManager.getInstance().getRef(interfaceClass);
if (null == entry) {
logger.info("No Ref Service FOUND.");
return new ResponseEntity<String>(HttpStatus.NOT_FOUND);
}
ref = entry.getValue();
HttpMatch httpMatch = new HttpMatch(entry.getKey(), ref.getClass());
Method[] interfaceMethods = httpMatch.findInterfaceMethods(methodName);
if (null != interfaceMethods && interfaceMethods.length > 0) {
Method[] refMethods = httpMatch.findRefMethods(interfaceMethods, operationId,
request.getMethod());
method = httpMatch.matchRefMethod(refMethods, methodName, request.getParameterMap().keySet());
}
if (null == method) {
logger.info("No Service Method FOUND.");
return new ResponseEntity<String>(HttpStatus.NOT_FOUND);
}
String[] parameterNames = NameDiscover.parameterNameDiscover.getParameterNames(method);
logger.info("[Swagger-dubbo] Invoke by " + cluster);
if (CLUSTER_RPC.equals(cluster)) {
ref = ReferenceManager.getInstance().getProxy(interfaceClass);
if (null == ref) {
logger.info("No Ref Proxy Service FOUND.");
return new ResponseEntity<String>(HttpStatus.NOT_FOUND);
}
method = ref.getClass().getMethod(method.getName(), method.getParameterTypes());
if (null == method) {
logger.info("No Proxy Service Method FOUND.");
return new ResponseEntity<String>(HttpStatus.NOT_FOUND);
}
}
logger.debug("[Swagger-dubbo] Invoke dubbo service method:{},parameter:{}", method, Json.pretty(request.getParameterMap()));
if (null == parameterNames || parameterNames.length == 0) {
result = method.invoke(ref);
} else {
Object[] args = new Object[parameterNames.length];
Type[] parameterTypes = method.getGenericParameterTypes();
Class<?>[] parameterClazz = method.getParameterTypes();
for (int i = 0; i < parameterNames.length; i++) {
Object suggestPrameterValue = suggestPrameterValue(parameterTypes[i],
parameterClazz[i], request.getParameter(parameterNames[i]));
args[i] = suggestPrameterValue;
}
result = method.invoke(ref, args);
}
return ResponseEntity.ok(Json.mapper().writeValueAsString(result));
}
private Object suggestPrameterValue(Type type, Class<?> cls, String parameter)
throws JsonParseException, JsonMappingException, IOException {
PrimitiveType fromType = PrimitiveType.fromType(type);
if (null != fromType) {
DefaultConversionService service = new DefaultConversionService();
boolean actual = service.canConvert(String.class, cls);
if (actual) {
return service.convert(parameter, cls);
}
} else {
if (null == parameter) return null;
try {
return Json.mapper().readValue(parameter, cls);
} catch (Exception e) {
throw new IllegalArgumentException("The parameter value [" + parameter + "] should be json of [" + cls.getName() + "] Type.", e);
}
}
try {
return Class.forName(cls.getName()).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
package com.secoo.mall.dubbo.swagger.controller;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.secoo.mall.dubbo.swagger.config.DubboPropertyConfig;
import com.secoo.mall.dubbo.swagger.config.DubboServiceScanner;
import com.secoo.mall.dubbo.swagger.config.SwaggerDocCache;
import com.secoo.mall.dubbo.swagger.reader.Reader;
import io.swagger.annotations.Api;
import io.swagger.config.SwaggerConfig;
import io.swagger.models.Swagger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import springfox.documentation.spring.web.json.Json;
import java.util.Map;
@Controller
@RequestMapping("${swagger.dubbo.doc:swagger-dubbo}")
@Api(hidden = true)
public class SwaggerDubboController {
public static final String DEFAULT_URL = "/api-docs";
private static final String HAL_MEDIA_TYPE = "application/hal+json";
@Autowired
private DubboServiceScanner dubboServiceScanner;
@Autowired
private DubboPropertyConfig dubboPropertyConfig;
@Autowired
private SwaggerDocCache swaggerDocCache;
@Value("${swagger.dubbo.http:h}")
private String httpContext;
@Value("${swagger.dubbo.enable:true}")
private boolean enable = true;
@RequestMapping(value = DEFAULT_URL,
method = RequestMethod.GET,
produces = {"application/json; charset=utf-8", HAL_MEDIA_TYPE})
@ResponseBody
public ResponseEntity<Json> getApiList() throws JsonProcessingException {
if (!enable) {
return new ResponseEntity<Json>(HttpStatus.NOT_FOUND);
}
Swagger swagger = swaggerDocCache.getSwagger();
if (null != swagger) {
return new ResponseEntity<Json>(new Json(io.swagger.util.Json.mapper().writeValueAsString(swagger)), HttpStatus.OK);
} else {
swagger = new Swagger();
}
final SwaggerConfig configurator = dubboPropertyConfig;
if (configurator != null) {
configurator.configure(swagger);
}
Map<Class<?>, Object> interfaceMapRef = dubboServiceScanner.interfaceMapRef();
if (null != interfaceMapRef) {
Reader.read(swagger, interfaceMapRef, httpContext);
}
swaggerDocCache.setSwagger(swagger);
return new ResponseEntity<Json>(new Json(io.swagger.util.Json.mapper().writeValueAsString(swagger)), HttpStatus.OK);
}
}
package com.secoo.mall.dubbo.swagger.http;
import com.secoo.mall.dubbo.swagger.reader.NameDiscover;
import io.swagger.annotations.ApiOperation;
import io.swagger.models.HttpMethod;
import io.swagger.util.ReflectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Method;
import java.util.*;
public class HttpMatch {
private static Logger logger = LoggerFactory.getLogger(HttpMatch.class);
private Class<?> interfaceClass;
private Class<?> refClass;
public HttpMatch(Class<?> interfaceClass, Class<?> refClass) {
this.interfaceClass = interfaceClass;
this.refClass = refClass;
}
public Method[] findInterfaceMethods(String methodName) {
Method[] methods = interfaceClass.getMethods();
List<Method> ret = new ArrayList<Method>();
for (Method method : methods) {
if (method.getName().equals(methodName)) ret.add(method);
}
return ret.toArray(new Method[]{});
}
public Method[] findRefMethods(Method[] interfaceMethods, String operationId,
String requestMethod) {
List<Method> ret = new ArrayList<Method>();
for (Method method : interfaceMethods) {
Method m;
try {
m = refClass.getMethod(method.getName(), method.getParameterTypes());
final ApiOperation apiOperation = ReflectionUtils.getAnnotation(m,
ApiOperation.class);
String nickname = null == apiOperation ? null : apiOperation.nickname();
if (operationId != null) {
if (!operationId.equals(nickname)) continue;
} else {
if (StringUtils.isNotBlank(nickname)) continue;
}
if (requestMethod != null) {
String httpMethod = null == apiOperation ? null : apiOperation.httpMethod();
if (StringUtils.isNotBlank(httpMethod) && !requestMethod.equals(httpMethod))
continue;
if (StringUtils.isBlank(httpMethod)
&& !requestMethod.equalsIgnoreCase(HttpMethod.POST.name()))
continue;
}
ret.add(m);
} catch (NoSuchMethodException e) {
logger.error("NoSuchMethodException", e);
} catch (SecurityException e) {
logger.error("SecurityException", e);
}
}
return ret.toArray(new Method[]{});
}
public Method matchRefMethod(Method[] refMethods, String methodName, Set<String> keySet) {
if (refMethods.length == 0) {
return null;
}
if (refMethods.length == 1) {
return refMethods[0];
}
List<RateMethod> rateMethods = new ArrayList<RateMethod>();
for (Method method : refMethods) {
String[] parameterNames = NameDiscover.parameterNameDiscover
.getParameterNames(method);
if (parameterNames == null) return method;
float correctRate = 0.0f;
int hit = 0;
int error = 0;
for (String paramName : parameterNames) {
if (keySet.contains(paramName)) hit++;
else error++;
}
correctRate = error / (float) hit;
rateMethods.add(new RateMethod(method, (int) correctRate * 100));
}
if (rateMethods.isEmpty()) return null;
Collections.sort(rateMethods, new Comparator<RateMethod>() {
@Override
public int compare(RateMethod o1, RateMethod o2) {
return o2.getRate() - o1.getRate();
}
});
return rateMethods.get(0).getMethod();
}
class RateMethod {
private Method method;
private int rate;
public RateMethod(Method method, int rate) {
this.method = method;
this.rate = rate;
}
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
public int getRate() {
return rate;
}
public void setRate(int rate) {
this.rate = rate;
}
}
}
package com.secoo.mall.dubbo.swagger.http;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.spring.ServiceBean;
import org.apache.dubbo.config.spring.extension.SpringExtensionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
public class ReferenceManager {
private static Logger logger = LoggerFactory.getLogger(ReferenceManager.class);
@SuppressWarnings("rawtypes")
private static Collection<ServiceBean> services;
private static Map<Class<?>, Object> interfaceMapProxy = new ConcurrentHashMap<Class<?>, Object>();
private static Map<Class<?>, Object> interfaceMapRef = new ConcurrentHashMap<Class<?>, Object>();
private static ReferenceManager instance;
private static ApplicationConfig application;
private ReferenceManager() {
}
@SuppressWarnings({"rawtypes", "unchecked"})
public synchronized static ReferenceManager getInstance() {
if (null != instance) return instance;
instance = new ReferenceManager();
services = new HashSet<ServiceBean>();
try {
/* Field field = SpringExtensionFactory.class.getDeclaredField("contexts");
field.setAccessible(true);*/
Set<ApplicationContext> contexts = SpringExtensionFactory.getContexts();
for (ApplicationContext context : contexts) {
services.addAll(context.getBeansOfType(ServiceBean.class).values());
}
} catch (Exception e) {
logger.error("Get All Dubbo Service Error", e);
return instance;
}
for (ServiceBean<?> bean : services) {
interfaceMapRef.putIfAbsent(bean.getInterfaceClass(), bean.getRef());
}
//
if (!services.isEmpty()) {
ServiceBean<?> bean = services.toArray(new ServiceBean[]{})[0];
application = bean.getApplication();
}
return instance;
}
public Object getProxy(String interfaceClass) {
Set<Entry<Class<?>, Object>> entrySet = interfaceMapProxy.entrySet();
for (Entry<Class<?>, Object> entry : entrySet) {
if (entry.getKey().getName().equals(interfaceClass)) {
return entry.getValue();
}
}
for (ServiceBean<?> service : services) {
if (interfaceClass.equals(service.getInterfaceClass().getName())) {
ReferenceConfig<Object> reference = new ReferenceConfig<Object>();
reference.setApplication(service.getApplication());
reference.setRegistry(service.getRegistry());
reference.setRegistries(service.getRegistries());
reference.setInterface(service.getInterfaceClass());
reference.setVersion(service.getVersion());
interfaceMapProxy.put(service.getInterfaceClass(), reference.get());
return reference.get();
}
}
return null;
}
public Entry<Class<?>, Object> getRef(String interfaceClass) {
Set<Entry<Class<?>, Object>> entrySet = interfaceMapRef.entrySet();
for (Entry<Class<?>, Object> entry : entrySet) {
if (entry.getKey().getName().equals(interfaceClass)) {
return entry;
}
}
return null;
}
@SuppressWarnings("rawtypes")
public Collection<ServiceBean> getServices() {
return services;
}
public ApplicationConfig getApplication() {
return application;
}
public Map<Class<?>, Object> getInterfaceMapRef() {
return interfaceMapRef;
}
}
package com.secoo.mall.dubbo.swagger.reader;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.PrioritizedParameterNameDiscoverer;
import org.springframework.core.StandardReflectionParameterNameDiscoverer;
public final class NameDiscover {
public static final ParameterNameDiscoverer parameterNameDiscover;
static {
parameterNameDiscover = new PrioritizedParameterNameDiscoverer();
((PrioritizedParameterNameDiscoverer) parameterNameDiscover)
.addDiscoverer(new LocalVariableTableParameterNameDiscoverer());
((PrioritizedParameterNameDiscoverer) parameterNameDiscover)
.addDiscoverer(new StandardReflectionParameterNameDiscoverer());
}
}
package com.secoo.mall.dubbo.swagger.reader;
import io.swagger.models.Swagger;
import io.swagger.models.parameters.Parameter;
import java.util.List;
/**
* The <code>ReaderContext</code> class is wrapper for the <code>Reader</code>
* parameters.
*/
public class ReaderContext {
private Swagger swagger;
private Class<?> refCls;
private Class<?> interfaceCls;
private String parentPath;
private String parentHttpMethod;
private boolean readHidden;
private List<String> parentConsumes;
private List<String> parentProduces;
private List<String> parentTags;
private List<Parameter> parentParameters;
public ReaderContext(Swagger swagger, Class<?> refCls, Class<?> interfaceCls, String parentPath,
String parentHttpMethod, boolean readHidden, List<String> parentConsumes,
List<String> parentProduces, List<String> parentTags,
List<Parameter> parentParameters) {
setSwagger(swagger);
setRefCls(refCls);
setInterfaceCls(interfaceCls);
setParentPath(parentPath);
setParentHttpMethod(parentHttpMethod);
setReadHidden(readHidden);
setParentConsumes(parentConsumes);
setParentProduces(parentProduces);
setParentTags(parentTags);
setParentParameters(parentParameters);
}
public Swagger getSwagger() {
return swagger;
}
public void setSwagger(Swagger swagger) {
this.swagger = swagger;
}
public Class<?> getRefCls() {
return refCls;
}
public void setRefCls(Class<?> cls) {
this.refCls = cls;
}
public Class<?> getInterfaceCls() {
return interfaceCls;
}
public Class<?> getCls() {
return refCls;
}
public void setInterfaceCls(Class<?> interfaceCls) {
this.interfaceCls = interfaceCls;
}
public String getParentPath() {
return parentPath;
}
public void setParentPath(String parentPath) {
this.parentPath = parentPath;
}
public String getParentHttpMethod() {
return parentHttpMethod;
}
public void setParentHttpMethod(String parentHttpMethod) {
this.parentHttpMethod = parentHttpMethod;
}
public boolean isReadHidden() {
return readHidden;
}
public void setReadHidden(boolean readHidden) {
this.readHidden = readHidden;
}
public List<String> getParentConsumes() {
return parentConsumes;
}
public void setParentConsumes(List<String> parentConsumes) {
this.parentConsumes = parentConsumes;
}
public List<String> getParentProduces() {
return parentProduces;
}
public void setParentProduces(List<String> parentProduces) {
this.parentProduces = parentProduces;
}
public List<String> getParentTags() {
return parentTags;
}
public void setParentTags(List<String> parentTags) {
this.parentTags = parentTags;
}
public List<Parameter> getParentParameters() {
return parentParameters;
}
public void setParentParameters(List<Parameter> parentParameters) {
this.parentParameters = parentParameters;
}
}
package com.secoo.mall.dubbo.swagger.reader;
import io.swagger.models.Operation;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
/**
* The <code>ReaderExtension</code> interface defines methods for scans resources for Swagger.
*/
public interface ReaderExtension {
/**
* Returns this extension's priority.
* Note: Extension will be executed first with lowest priority.
*
* @return this extension's priority
*/
int getPriority();
/**
* Checks that a resource should be scanned.
*
* @param context is the resource context
* @return true if the resource needs to be scanned, otherwise false
*/
boolean isReadable(ReaderContext context);
/**
* Reads the consumes from the method's annotations and applies these to the operation.
*
* @param context is the resource context
* @param operation is the container for the operation data
* @param method is the method for reading annotations
*/
void applyConsumes(ReaderContext context, Operation operation, Method method);
/**
* Reads the produces from the method's annotations and applies these to the operation.
*
* @param context is the resource context
* @param operation is the container for the operation data
* @param method is the method for reading annotations
*/
void applyProduces(ReaderContext context, Operation operation, Method method);
/**
* Returns http method.
*
* @param context is the resource context
* @param method is the method for reading annotations
* @return http method
*/
String getHttpMethod(ReaderContext context, Method method);
/**
* Returns operation's path.
*
* @param context is the resource context
* @param method is the method for reading annotations
* @return operation's path
*/
String getPath(ReaderContext context, Method method);
/**
* Reads the operation id from the method's annotations and applies it to the operation.
*
* @param operation is the container for the operation data
* @param method is the method for reading annotations
*/
void applyOperationId(Operation operation, Method method);
/**
* Reads the summary from the method's annotations and applies it to the operation.
*
* @param operation is the container for the operation data
* @param method is the method for reading annotations
*/
void applySummary(Operation operation, Method method);
/**
* Reads the description from the method's annotations and applies it to the operation.
*
* @param operation is the container for the operation data
* @param method is the method for reading annotations
*/
void applyDescription(Operation operation, Method method);
/**
* Reads the schemes from the method's annotations and applies these to the operation.
*
* @param context is the resource context
* @param operation is the container for the operation data
* @param method is the method for reading annotations
*/
void applySchemes(ReaderContext context, Operation operation, Method method);
/**
* Sets the deprecated flag to the operation.
*
* @param operation is the container for the operation data
* @param method is the method for reading annotations
*/
void setDeprecated(Operation operation, Method method);
/**
* Reads the security requirement from the method's annotations and applies these to the operation.
*
* @param context is the resource context
* @param operation is the container for the operation data
* @param method is the method for reading annotations
*/
void applySecurityRequirements(ReaderContext context, Operation operation, Method method);
/**
* Reads the tags from the method's annotations and applies these to the operation.
*
* @param context is the resource context
* @param operation is the container for the operation data
* @param method is the method for reading annotations
*/
void applyTags(ReaderContext context, Operation operation, Method method);
/**
* Reads the responses from the method's annotations and applies these to the operation.
*
* @param context is the resource context
* @param operation is the container for the operation data
* @param method is the method for reading annotations
*/
void applyResponses(ReaderContext context, Operation operation, Method method);
/**
* Reads the parameters from the method's annotations and applies these to the operation.
*
* @param context is the resource context
* @param operation is the container for the operation data
* @param type is the type of parameter
* @param annotations are the method's annotations
*/
void applyParameters(ReaderContext context, Operation operation, Type type, Annotation[] annotations);
/**
* Reads the implicit parameters from the method's annotations and applies these to the operation.
*
* @param context is the resource context
* @param operation is the container for the operation data
* @param method is the method for reading annotations
*/
void applyImplicitParameters(ReaderContext context, Operation operation, Method method);
/**
* Reads the extensions from the method's annotations and applies these to the operation.
*
* @param context is the resource context
* @param operation is the container for the operation data
* @param method is the method for reading annotations
*/
void applyExtensions(ReaderContext context, Operation operation, Method method);
void applyParameters(ReaderContext context, Operation operation, Method method,
Method interfaceMethod);
}
...@@ -15,7 +15,7 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; ...@@ -15,7 +15,7 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
@RestControllerAdvice(annotations = ApiController.class) @RestControllerAdvice(annotations = ApiController.class)
public class ControllerResponseAdvice extends ProtocolExceptionHandler implements ResponseBodyAdvice<Object> { public class ControllerResponseAdvice extends ProtocolExceptionHandler implements ResponseBodyAdvice<Object> {
@Override @Override
public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) { public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
return AnnotationUtils.findAnnotation(methodParameter.getMethod(), ApiIgnoreJson.class) == null; return AnnotationUtils.findAnnotation(methodParameter.getMethod(), ApiIgnoreJson.class) == null;
......
com.secoo.mall.dubbo.filter.DefaultExceptionFilter exception=com.secoo.mall.dubbo.filter.DefaultExceptionFilter
\ No newline at end of file \ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment