Skip to content
Permalink
Browse files
feature: Dubbo api docs UI (#671)
* 半成品,从dubboDoc合并,使用vue参考dubboDoc重做ui

* 使用swagger-ui半成品管,放弃swagger存档

* 放弃swagger

* admin中增加 dubbo-api-docs 的UI及测试

* 补遗漏的licenses

* 去除  lombok, 注释修改

* 排除不需要rat检查的文件
  • Loading branch information
KeRan213539 committed Dec 21, 2020
1 parent 93d756a commit 3268c49460c374d2b899d8a92f69468986047f70
Showing 26 changed files with 13,050 additions and 2,326 deletions.
@@ -172,6 +172,7 @@
<version>${mockito-version}</version>
<scope>test</scope>
</dependency>

</dependencies>

<build>
@@ -0,0 +1,204 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.admin.controller;

import org.apache.dubbo.admin.controller.editors.CustomLocalDateEditor;
import org.apache.dubbo.admin.controller.editors.CustomLocalDateTimeEditor;
import org.apache.dubbo.admin.model.dto.docs.ApiInfoRequest;
import org.apache.dubbo.admin.model.dto.docs.CallDubboServiceRequest;
import org.apache.dubbo.admin.model.dto.docs.CallDubboServiceRequestInterfaceParam;
import org.apache.dubbo.admin.utils.ApiDocsDubboGenericUtil;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SimplePropertyPreFilter;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
* dubbo doc ui server api.
*/
@Api(tags = {"dubbo-api-docs-api"})
@RestController
@RequestMapping("/api/{env}/docs")
public class ApiDocsController {

private static final Logger LOG = LoggerFactory.getLogger(ApiDocsController.class);

private static final SimplePropertyPreFilter CLASS_NAME_PRE_FILTER = new SimplePropertyPreFilter(HashMap.class);
static {
// Remove the "class" attribute from the returned result
CLASS_NAME_PRE_FILTER.getExcludes().add("class");
}

/**
* retries for dubbo provider
*/
@Value("${dubbo.consumer.retries:0}")
private int retries;

/**
* timeout
*/
@Value("${dubbo.consumer.timeout:1000}")
private int timeout;

@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
binder.registerCustomEditor(LocalDate.class, new CustomLocalDateEditor());
binder.registerCustomEditor(LocalDateTime.class, new CustomLocalDateTimeEditor());
}

/**
* Set timeout and retries for {@link ApiDocsDubboGenericUtil}
* 2020-11-02 11:16:28
* @param:
* @return void
*/
@PostConstruct
public void setRetriesAndTimeout(){
ApiDocsDubboGenericUtil.setRetriesAndTimeout(retries, timeout);
}

@ApiOperation(value = "request dubbo api", notes = "request dubbo api", httpMethod = "POST", produces = "application/json")
@PostMapping("/requestDubbo")
public String callDubboService(CallDubboServiceRequest dubboCfg, @RequestBody List<CallDubboServiceRequestInterfaceParam> methodparams){
String[] paramTypes = null;
Object[] paramValues = null;
if(null != methodparams && !methodparams.isEmpty()){
paramTypes = new String[methodparams.size()];
paramValues = new Object[methodparams.size()];
for(int i = 0; i < methodparams.size(); i++){
CallDubboServiceRequestInterfaceParam param = methodparams.get(i);
paramTypes[i] = param.getParamType();
Object paramValue = param.getParamValue();
if(isBaseType(param.getParamType()) && null != paramValue){
if(paramValue instanceof Map){
Map<?, ?> tempMap = (Map<?, ?>) paramValue;
if(!tempMap.isEmpty()) {
this.emptyString2Null(tempMap);
paramValues[i] = tempMap.values().stream().findFirst().orElse(null);
}
} else {
paramValues[i] = emptyString2Null(paramValue);
}
} else {
this.emptyString2Null(paramValue);
paramValues[i] = paramValue;
}
}
}
if (null == paramTypes) {
paramTypes = new String[0];
}
if (null == paramValues) {
paramValues = new Object[0];
}
CompletableFuture<Object> future = ApiDocsDubboGenericUtil.invoke(dubboCfg.getRegistryCenterUrl(), dubboCfg.getInterfaceClassName(),
dubboCfg.getMethodName(), dubboCfg.isAsync(), paramTypes, paramValues);
try {
Object objResult = future.get();
return JSON.toJSONString(objResult, CLASS_NAME_PRE_FILTER);
} catch (InterruptedException | ExecutionException e) {
LOG.error(e.getMessage(), e);
return "Some exceptions have occurred, please check the log.";
}
}

private Object emptyString2Null(Object paramValue){
if(null != paramValue) {
if (paramValue instanceof String && StringUtils.isBlank((String) paramValue)) {
return null;
} else if (paramValue instanceof Map) {
Map<String, Object> tempMap = (Map<String, Object>) paramValue;
tempMap.forEach((k, v) -> {
if (v != null && v instanceof String && StringUtils.isBlank((String) v)) {
tempMap.put(k, null);
} else {
this.emptyString2Null(v);
}
});
}
}
return paramValue;
}

@ApiOperation(value = "Get basic information of all modules, excluding API parameter information", notes = "Get basic information of all modules, excluding API parameter information", httpMethod = "GET", produces = "application/json")
@GetMapping("/apiModuleList")
public String apiModuleList(ApiInfoRequest apiInfoRequest){
CallDubboServiceRequest req = new CallDubboServiceRequest();
req.setRegistryCenterUrl("dubbo://" + apiInfoRequest.getDubboIp() + ":" + apiInfoRequest.getDubboPort());
req.setInterfaceClassName("org.apache.dubbo.apidocs.core.providers.IDubboDocProvider");
req.setMethodName("apiModuleList");
req.setAsync(false);
return callDubboService(req, null);
}

@ApiOperation(value = "Get the parameter information of the specified API", notes = "Get the parameter information of the specified API", httpMethod = "GET", produces = "application/json")
@GetMapping("/apiParamsResp")
public String apiParamsResp(ApiInfoRequest apiInfoRequest){
CallDubboServiceRequest req = new CallDubboServiceRequest();
req.setRegistryCenterUrl("dubbo://" + apiInfoRequest.getDubboIp() + ":" + apiInfoRequest.getDubboPort());
req.setInterfaceClassName("org.apache.dubbo.apidocs.core.providers.IDubboDocProvider");
req.setMethodName("apiParamsResponseInfo");
req.setAsync(false);

List<CallDubboServiceRequestInterfaceParam> methodparams = new ArrayList<>(1);
CallDubboServiceRequestInterfaceParam param = new CallDubboServiceRequestInterfaceParam();
param.setParamType(String.class.getName());
param.setParamValue(apiInfoRequest.getApiName());
methodparams.add(param);
return callDubboService(req, methodparams);
}

private static boolean isBaseType(String typeStr) {
if ("java.lang.Integer".equals(typeStr) ||
"java.lang.Byte".equals(typeStr) ||
"java.lang.Long".equals(typeStr) ||
"java.lang.Double".equals(typeStr) ||
"java.lang.Float".equals(typeStr) ||
"java.lang.Character".equals(typeStr) ||
"java.lang.Short".equals(typeStr) ||
"java.lang.Boolean".equals(typeStr) ||
"java.lang.String".equals(typeStr)) {
return true;
}
return false;
}
}
@@ -0,0 +1,92 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.admin.controller.beans;


/**
* api parameter bean.
*/
public class DubboApiDocsParamInfoBean {

private String fieldName;

private String fieldJavaType;

private String methodParamType;

private int methodParamIndex;

private Object fieldValue;

public DubboApiDocsParamInfoBean(String fieldName,String fieldJavaType,String methodParamType,int methodParamIndex) {
this.fieldName = fieldName;
this.fieldJavaType = fieldJavaType;
this.methodParamType = methodParamType;
this.methodParamIndex = methodParamIndex;
}

public String getFieldName() {
return fieldName;
}

public void setFieldName(String fieldName) {
this.fieldName = fieldName;
}

public String getFieldJavaType() {
return fieldJavaType;
}

public void setFieldJavaType(String fieldJavaType) {
this.fieldJavaType = fieldJavaType;
}

public String getMethodParamType() {
return methodParamType;
}

public void setMethodParamType(String methodParamType) {
this.methodParamType = methodParamType;
}

public int getMethodParamIndex() {
return methodParamIndex;
}

public void setMethodParamIndex(int methodParamIndex) {
this.methodParamIndex = methodParamIndex;
}

public Object getFieldValue() {
return fieldValue;
}

public void setFieldValue(Object fieldValue) {
this.fieldValue = fieldValue;
}

@Override
public String toString() {
return "DubboApiDocsParamInfoBean{" +
"fieldName='" + fieldName + '\'' +
", fieldJavaType='" + fieldJavaType + '\'' +
", methodParamType='" + methodParamType + '\'' +
", methodParamIndex=" + methodParamIndex +
", paramValue=" + fieldValue +
'}';
}
}
@@ -0,0 +1,43 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.admin.controller.editors;


import org.apache.dubbo.admin.utils.LocalDateTimeUtil;

import java.beans.PropertyEditorSupport;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

/**
* Localdate editor for controller.
*/
public class CustomLocalDateEditor extends PropertyEditorSupport {

@Override
public void setAsText(String text) throws IllegalArgumentException {
setValue(LocalDateTimeUtil.formatToLD(text));
}

@Override
public String getAsText() {
LocalDate date = (LocalDate) getValue();
return date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
}


}
@@ -0,0 +1,43 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.admin.controller.editors;


import org.apache.dubbo.admin.utils.LocalDateTimeUtil;

import java.beans.PropertyEditorSupport;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
* LocalDateTime editor for controller.
*/
public class CustomLocalDateTimeEditor extends PropertyEditorSupport {

@Override
public void setAsText(String text) throws IllegalArgumentException {
setValue(LocalDateTimeUtil.formatToLDT(text));
}

@Override
public String getAsText() {
LocalDateTime date = (LocalDateTime) getValue();
return date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}


}

0 comments on commit 3268c49

Please sign in to comment.