Merge branch 'master' into eureka

eureka
tanghc 4 years ago
commit e536726503
  1. 16
      doc/docs/files/10011_项目接入到SOP.md
  2. 2
      dockerfile
  3. 1
      sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-2d238661.5eefcb02.js
  4. 24
      sop-admin/sop-admin-server/src/main/resources/public/static/sdkConfig.json
  5. 9
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/ApiUploadContext.java
  6. 2
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/UploadContext.java
  7. 16
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/util/RequestUtil.java
  8. 4
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/util/ResponseUtil.java
  9. 6
      sop-mysql5.6以下版本.sql
  10. 2
      sop-website/sop-website-server/pom.xml
  11. 23
      sop-website/sop-website-server/src/main/java/com/gitee/sop/websiteserver/bean/HttpTool.java
  12. 4
      sop-website/sop-website-server/src/main/java/com/gitee/sop/websiteserver/config/CorsConfig.java
  13. 6
      sop-website/sop-website-server/src/main/java/com/gitee/sop/websiteserver/controller/IsvController.java
  14. 2
      sop-website/sop-website-server/src/main/java/com/gitee/sop/websiteserver/controller/SandboxController.java
  15. 211
      sop-website/sop-website-server/src/main/java/com/gitee/sop/websiteserver/controller/SandboxV2Controller.java
  16. 2
      sop-website/sop-website-server/src/main/java/com/gitee/sop/websiteserver/controller/result/DocVO.java
  17. BIN
      sop-website/sop-website-server/src/main/resources/public/assets/image/auth.png
  18. 2
      sop-website/sop-website-server/src/main/resources/public/index.html
  19. 0
      sop-website/sop-website-server/src/main/resources/public/static/css/chunk-3d8e72b0.04f4b7fb.css
  20. 1
      sop-website/sop-website-server/src/main/resources/public/static/css/chunk-4e7f1f48.cf843403.css
  21. 2
      sop-website/sop-website-server/src/main/resources/public/static/css/chunk-5356e7e6.52876932.css
  22. BIN
      sop-website/sop-website-server/src/main/resources/public/static/img/404.a57b6f31.png
  23. BIN
      sop-website/sop-website-server/src/main/resources/public/static/img/404_cloud.0f4bc32b.png
  24. BIN
      sop-website/sop-website-server/src/main/resources/public/static/img/logo.aed72f8d.png
  25. 1
      sop-website/sop-website-server/src/main/resources/public/static/js/app.132894e5.js
  26. 1
      sop-website/sop-website-server/src/main/resources/public/static/js/app.5706d539.js
  27. 2
      sop-website/sop-website-server/src/main/resources/public/static/js/chunk-3d8e72b0.d5d1a474.js
  28. 1
      sop-website/sop-website-server/src/main/resources/public/static/js/chunk-4e7f1f48.331ccf8a.js
  29. 1
      sop-website/sop-website-server/src/main/resources/public/static/js/chunk-5356e7e6.2c0ab073.js
  30. 4
      sop-website/sop-website-server/src/main/resources/public/static/js/chunk-libs.e265b709.js
  31. 2
      sop-website/sop-website-vue/.env.production
  32. 11
      sop-website/sop-website-vue/README.md
  33. BIN
      sop-website/sop-website-vue/src/assets/404_images/404.png
  34. BIN
      sop-website/sop-website-vue/src/assets/404_images/404_cloud.png
  35. BIN
      sop-website/sop-website-vue/src/assets/images/logo.png
  36. 4
      sop-website/sop-website-vue/src/components/DocView/index.vue
  37. 262
      sop-website/sop-website-vue/src/components/Docdebug/index.vue
  38. 9
      sop-website/sop-website-vue/src/components/ParameterTable/index.vue
  39. 121
      sop-website/sop-website-vue/src/components/ParameterTableEdit/index.vue
  40. 3
      sop-website/sop-website-vue/src/router/index.js
  41. 42
      sop-website/sop-website-vue/src/utils/global.js
  42. 22
      sop-website/sop-website-vue/src/views/isv/platformManager/doc.vue
  43. 6
      sop.sql

@ -5,15 +5,13 @@
- pom.xml添加版本配置
```xml
<properties>
<!-- springboot 版本-->
<spring-boot.version>2.2.5.RELEASE</spring-boot.version>
<!-- spring cloud 版本 -->
<spring-cloud.version>Hoxton.SR3</spring-cloud.version>
<!-- spring cloud alibaba 版本 -->
<!-- 具体版本对应关系见:https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E -->
<spring-cloud-alibaba.version>2.2.1.RELEASE</spring-cloud-alibaba.version>
</properties>
<!-- springboot 版本-->
<spring-boot.version>2.3.4.RELEASE</spring-boot.version>
<!-- spring cloud 版本 -->
<spring-cloud.version>Hoxton.SR8</spring-cloud.version>
<!-- spring cloud alibaba 版本 -->
<!-- 具体版本对应关系见:https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E -->
<spring-cloud-alibaba.version>2.2.3.RELEASE</spring-cloud-alibaba.version>
```
- pom.xml添加`<dependencyManagement>`控制版本

@ -5,7 +5,7 @@ VOLUME /sop
# 将所有应用放到一个镜像当中
ADD sop-gateway/target/*.jar sop/sop-gateway/sop-gateway.jar
ADD sop-admin/sop-admin-server/target/*.jar sop/sop-admin/sop-admin.jar
ADD sop-website/target/*.jar sop/sop-website/sop-website.jar
ADD sop-website/sop-website-server/target/*.jar sop/sop-website/sop-website.jar
ADD sop-auth/target/*.jar sop/sop-auth/sop-auth.jar
ADD sop-example/sop-story/target/*.jar sop/sop-story/sop-story.jar

@ -0,0 +1,24 @@
{
"langList": [
{
"name": "Java"
},
{
"name": "C#"
},
{
"name": "C++"
},
{
"name": "Go"
},{
"name": "NodeJS"
},
{
"name": "Python"
},
{
"name": "Rust"
}
]
}

@ -17,15 +17,16 @@ public class ApiUploadContext implements UploadContext {
/**
* key: 表单name
*/
private Map<String, MultipartFile> fileMap;
private Map<String, List<MultipartFile>> fileMap;
private List<MultipartFile> allFile;
public ApiUploadContext(Map<String, MultipartFile> map) {
public ApiUploadContext(Map<String, List<MultipartFile>> map) {
if (map == null) {
map = Collections.emptyMap();
}
this.fileMap = map;
this.allFile = new ArrayList<>(map.values());
this.allFile = new ArrayList<>();
map.values().forEach(list -> this.allFile.addAll(list));
}
@Override
@ -34,7 +35,7 @@ public class ApiUploadContext implements UploadContext {
}
@Override
public MultipartFile getFile(String name) {
public List<MultipartFile> getFile(String name) {
return fileMap.get(name);
}

@ -25,7 +25,7 @@ public interface UploadContext {
* 表单名称
* @return 返回上传文件信息
*/
MultipartFile getFile(String name);
List<MultipartFile> getFile(String name);
/**
* 获取所有的上传文件

@ -15,6 +15,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.MultiValueMap;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;
@ -36,7 +37,6 @@ import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -298,9 +298,9 @@ public class RequestUtil {
}
}
if (multipartFileList.size() > 0) {
Map<String, MultipartFile> multipartFileMap = multipartFileList
Map<String, List<MultipartFile>> multipartFileMap = multipartFileList
.stream()
.collect(Collectors.toMap(MultipartFile::getName, Function.identity()));
.collect(Collectors.groupingBy(MultipartFile::getName));
uploadContext = new ApiUploadContext(multipartFileMap);
}
uploadInfo.setUploadParams(uploadParams);
@ -315,8 +315,14 @@ public class RequestUtil {
UploadInfo uploadInfo = new UploadInfo();
Map<String, String> uploadParams = new HashMap<>(16);
request.getParameterMap().forEach((key, value)-> uploadParams.put(key, value[0]));
Map<String, MultipartFile> multipartFileMap = request.getMultiFileMap().toSingleValueMap();
MultiValueMap<String, MultipartFile> multiFileMap = request.getMultiFileMap();
List<MultipartFile> multipartFileList = new ArrayList<>(10);
for (String key : multiFileMap.keySet()) {
multipartFileList.addAll(multiFileMap.get(key));
}
Map<String, List<MultipartFile>> multipartFileMap = multipartFileList
.stream()
.collect(Collectors.groupingBy(MultipartFile::getName));
UploadContext uploadContext = new ApiUploadContext(multipartFileMap);
uploadInfo.setUploadParams(uploadParams);

@ -27,12 +27,12 @@ public class ResponseUtil {
private static Logger log = LoggerFactory.getLogger(ResponseUtil.class);
public static void writeJson(HttpServletResponse response, Object result) {
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding(UTF_8);
try {
response.getWriter().write(result instanceof String ? (String)result : JSON.toJSONString(result));
} catch (IOException e) {
log.error("doWriter", e);
log.error("writeJson error", e);
}
}

@ -341,3 +341,9 @@ INSERT INTO `user_info` (`id`, `username`, `password`, `nickname`, `gmt_create`,
(1,'zhangsan','123456','张三','2019-04-27 08:32:57','2019-04-27 08:32:57');
INSERT INTO `isp_resource` (`id`, `name`, `content`, `ext_content`, `version`, `type`, `is_deleted`, `gmt_create`, `gmt_modified`) VALUES
(1,'Java','http://www.baidu.com','```java\nString url = "http://localhost:8081";\nString appId = "2019032617262200001";\nString privateKey = "你的私钥";\n\n// 声明一个就行\nOpenClient client = new OpenClient(url, appId, privateKey);\n\n// 标准用法\n@Test\npublic void testGet() {\n // 创建请求对象\n GetStoryRequest request = new GetStoryRequest();\n // 请求参数\n GetStoryModel model = new GetStoryModel();\n model.setName("白雪公主");\n \n request.setBizModel(model);\n\n // 发送请求\n GetStoryResponse response = client.execute(request);\n\n if (response.isSuccess()) {\n // 返回结果\n System.out.println(response);\n } else {\n System.out.println(response);\n }\n}\n```','1.0',0,0,'2020-11-07 14:29:11','2020-11-07 14:29:11'),
(2,'C#','http://www.soso.com','```\nclass MainClass\n{\n static string url = "http://localhost:8081";\n static string appId = "2019032617262200001";\n // 平台提供的私钥\n static string privateKey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCXJv1pQFqWNA/++OYEV7WYXwexZK/J8LY1OWlP9X0T6wHFOvxNKRvMkJ5544SbgsJpVcvRDPrcxmhPbi/sAhdO4x2PiPKIz9Yni2OtYCCeaiE056B+e1O2jXoLeXbfi9fPivJZkxH/tb4xfLkH3bA8ZAQnQsoXA0SguykMRZntF0TndUfvDrLqwhlR8r5iRdZLB6F8o8qXH6UPDfNEnf/K8wX5T4EB1b8x8QJ7Ua4GcIUqeUxGHdQpzNbJdaQvoi06lgccmL+PHzminkFYON7alj1CjDN833j7QMHdPtS9l7B67fOU/p2LAAkPMtoVBfxQt9aFj7B8rEhGCz02iJIBAgMBAAECggEARqOuIpY0v6WtJBfmR3lGIOOokLrhfJrGTLF8CiZMQha+SRJ7/wOLPlsH9SbjPlopyViTXCuYwbzn2tdABigkBHYXxpDV6CJZjzmRZ+FY3S/0POlTFElGojYUJ3CooWiVfyUMhdg5vSuOq0oCny53woFrf32zPHYGiKdvU5Djku1onbDU0Lw8w+5tguuEZ76kZ/lUcccGy5978FFmYpzY/65RHCpvLiLqYyWTtaNT1aQ/9pw4jX9HO9NfdJ9gYFK8r/2f36ZE4hxluAfeOXQfRC/WhPmiw/ReUhxPznG/WgKaa/OaRtAx3inbQ+JuCND7uuKeRe4osP2jLPHPP6AUwQKBgQDUNu3BkLoKaimjGOjCTAwtp71g1oo+k5/uEInAo7lyEwpV0EuUMwLA/HCqUgR4K9pyYV+Oyb8d6f0+Hz0BMD92I2pqlXrD7xV2WzDvyXM3s63NvorRooKcyfd9i6ccMjAyTR2qfLkxv0hlbBbsPHz4BbU63xhTJp3Ghi0/ey/1HQKBgQC2VsgqC6ykfSidZUNLmQZe3J0p/Qf9VLkfrQ+xaHapOs6AzDU2H2osuysqXTLJHsGfrwVaTs00ER2z8ljTJPBUtNtOLrwNRlvgdnzyVAKHfOgDBGwJgiwpeE9voB1oAV/mXqSaUWNnuwlOIhvQEBwekqNyWvhLqC7nCAIhj3yvNQKBgQCqYbeec56LAhWP903Zwcj9VvG7sESqXUhIkUqoOkuIBTWFFIm54QLTA1tJxDQGb98heoCIWf5x/A3xNI98RsqNBX5JON6qNWjb7/dobitti3t99v/ptDp9u8JTMC7penoryLKK0Ty3bkan95Kn9SC42YxaSghzqkt+uvfVQgiNGQKBgGxU6P2aDAt6VNwWosHSe+d2WWXt8IZBhO9d6dn0f7ORvcjmCqNKTNGgrkewMZEuVcliueJquR47IROdY8qmwqcBAN7Vg2K7r7CPlTKAWTRYMJxCT1Hi5gwJb+CZF3+IeYqsJk2NF2s0w5WJTE70k1BSvQsfIzAIDz2yE1oPHvwVAoGAA6e+xQkVH4fMEph55RJIZ5goI4Y76BSvt2N5OKZKd4HtaV+eIhM3SDsVYRLIm9ZquJHMiZQGyUGnsvrKL6AAVNK7eQZCRDk9KQz+0GKOGqku0nOZjUbAu6A2/vtXAaAuFSFx1rUQVVjFulLexkXR3KcztL1Qu2k5pB6Si0K/uwQ=";\n\n\n // 声明一个就行\n static OpenClient client = new OpenClient(url, appId, privateKey);\n\n public static void Main(string[] args)\n {\n TestGet();\n }\n\n // 标准用法\n private static void TestGet()\n {\n // 创建请求对象\n GetStoryRequest request = new GetStoryRequest();\n // 请求参数\n GetStoryModel model = new GetStoryModel();\n model.Name = "白雪公主";\n request.BizModel = model;\n\n // 发送请求\n GetStoryResponse response = client.Execute(request);\n\n if (response.IsSuccess())\n {\n // 返回结果\n Console.WriteLine("成功!response:{0}\\n响应原始内容:{1}", JsonUtil.ToJSONString(response), response.Body);\n }\n else\n {\n Console.WriteLine("错误, code:{0}, msg:{1}, subCode:{2}, subMsg:{3}",\n response.Code, response.Msg, response.SubCode, response.SubMsg);\n }\n }\n\n \n}\n```','1.0',0,0,'2020-11-07 14:29:38','2020-11-07 14:29:38'),
(3,'Python','http://www.bilibili.com','```python\n # 创建请求\n request = MemberInfoGetRequest()\n # 请求参数\n model = MemberInfoGetModel()\n model.age = 22\n model.name = \'jim\'\n model.address = \'xx\'\n # 添加请求参数\n request.biz_model = model\n\n # 添加上传文件\n # files = {\n # \'file1\': open(\'aa.txt\', \'rb\'),\n # \'file2\': open(\'bb.txt\', \'rb\')\n # }\n # request.files = files\n\n # 调用请求\n response = self.client.execute(request)\n\n if response.is_success():\n print \'response: \', response\n print \'is_vip:\', response.get(\'member_info\').get(\'is_vip\', 0)\n else:\n print \',code:%s, msg:%s, sub_code:%s, sub_msg:%s\' % \\\n (response.code, response.msg, response.sub_code, response.sub_msg)\n```','1.0',0,0,'2020-11-07 14:30:16','2020-11-07 14:31:41'),
(4,'Go','http://www.baidu.com','```go\n\n// 应用ID\nconst appId string = "xx"\n// 应用私钥\nconst privateKey string = "xx"\n// 请求地址\nconst url string = "http://localhost:7071/prod/gw68uy85"\n\n// 请求客户端\nvar openClient = common.OpenClient{AppId: appId, PrivateKey: privateKey, Url: url}\n\nfunc main() {\n // 创建请求\n memberInfoGetRequest := request.MemberInfoGetRequest{}\n // 请求参数\n memberInfoGetRequest.BizModel = model.MemberInfoGetModel{Name: "jim", Age: 22, Address: "xx"}\n \n // 添加上传文件\n //path, _ := os.Getwd()\n //files := []common.UploadFile{\n // {Name:"file1", Filepath:path + "/test/aa.txt"},\n // {Name:"file2", Filepath:path + "/test/bb.txt"},\n //}\n //memberInfoGetRequest.Files = files\n \n // 发送请求,返回json bytes\n var jsonBytes = openClient.Execute(memberInfoGetRequest)\n fmt.Printf("data:%s\\n", string(jsonBytes))\n // 转换结果\n var memberInfoGetResponse response.MemberInfoGetResponse\n response.ConvertResponse(jsonBytes, &memberInfoGetResponse)\n\n if memberInfoGetResponse.IsSuccess() {\n fmt.Printf("is_vip:%d, vip_endtime:%s\\n", memberInfoGetResponse.MemberInfo.IsVip, memberInfoGetResponse.MemberInfo.VipEndtime)\n } else {\n fmt.Printf("code:%s, msg:%s, subCode:%s, subMsg:%s\\n",\n memberInfoGetResponse.Code, memberInfoGetResponse.Msg, memberInfoGetResponse.SubCode, memberInfoGetResponse.SubMsg)\n }\n}\n```','1.0',0,0,'2020-11-07 14:31:21','2020-11-07 14:31:21'),
(5,'C++','http://pan.baidu.com','#include <iostream>\n\n#include "common/OpenClient.h"\n#include "request/BaseRequest.h"\n#include "request/MemberInfoGetRequest.hpp"\n\n// 应用ID\nstring appId = "2020051325943082302177280";\n// 存放私钥的文件路径\nstring privateKeyFile = "/Users/thc/IdeaProjects/opc/opc-sdk/sdk-c++/privateEx.pem";\n// 请求接口\nstring url = "http://localhost:7071/prod/gw68uy85";\n\nOpenClient openClient(appId, privateKeyFile, url);\n\nint main() {\n // 创建请求\n MemberInfoGetRequest request;\n\n // 业务参数\n map<string, string> bizModel;\n bizModel["name"] = "jim";\n bizModel["age"] = "22";\n bizModel["address"] = "xx";\n\n request.bizModel = bizModel;\n\n // 添加上传文件\n// request->setFiles({\n// FileInfo{"aa", "/Users/thc/IdeaProjects/opc/opc-sdk/sdk-c++/aa.txt"},\n// FileInfo{"bb", "/Users/thc/IdeaProjects/opc/opc-sdk/sdk-c++/bb.txt"}\n// });\n\n // 发送请求\n neb::CJsonObject jsonObj = openClient.execute(&request);\n std::cout << jsonObj.ToString() << std::endl;\n std::cout << "id:" << jsonObj["id"].ToString() << std::endl;\n std::cout << "is_vip:" << jsonObj["member_info"]["is_vip"].ToString() << std::endl;\n return 0;\n}\n\n','1.0',0,0,'2020-11-07 14:32:55','2020-11-07 14:32:55');

@ -4,7 +4,7 @@
<parent>
<groupId>com.gitee.sop</groupId>
<artifactId>sop-parent</artifactId>
<artifactId>sop-website</artifactId>
<version>4.2.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <!-- lookup parent from repository -->
</parent>

@ -198,6 +198,11 @@ public class HttpTool {
return paramBuilder.build();
}
public String requestFileString(String url, Map<String, ?> form, Map<String, String> header, List<UploadFile> files) throws IOException {
return requestFile(url, form, header, files).body().string();
}
/**
* 提交表单并且上传文件
*
@ -208,7 +213,7 @@ public class HttpTool {
* @return
* @throws IOException
*/
public String requestFile(String url, Map<String, ?> form, Map<String, String> header, List<UploadFile> files)
public Response requestFile(String url, Map<String, ?> form, Map<String, String> header, List<UploadFile> files)
throws IOException {
// 创建MultipartBody.Builder,用于添加请求的数据
MultipartBody.Builder bodyBuilder = new MultipartBody.Builder();
@ -236,14 +241,20 @@ public class HttpTool {
addHeader(builder, header);
Request request = builder.build();
Response response = httpClient.newCall(request).execute();
try {
return response.body().string();
} finally {
response.close();
return httpClient.newCall(request).execute();
}
public Response request(String url, Map<String, ?> form, Map<String, String> header, HTTPMethod method, List<UploadFile> files) throws IOException {
if (files != null && files.size() > 0) {
return requestFile(url, form, header, files);
} else {
return requestForResponse(url, form, header, method);
}
}
/**
* 请求数据
*

@ -30,6 +30,10 @@ public class CorsConfig {
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
corsConfiguration.addExposedHeader("target-response-headers");
corsConfiguration.addExposedHeader("sendbox-params");
corsConfiguration.addExposedHeader("sendbox-beforesign");
corsConfiguration.addExposedHeader("sendbox-sign");
return corsConfiguration;
}

@ -62,6 +62,9 @@ public class IsvController {
@Value("${api.url-prod}")
String urlProd;
@Value("${api.url-sandbox}")
String gatewayUrl;
@GetMapping("/getIsvPortal")
public Result<IsvInfoResult> getIsvInfo() {
LoginUser loginUser = UserContext.getLoginUser();
@ -180,6 +183,9 @@ public class IsvController {
return menuProject;
}).collect(Collectors.toList());
DocVO docVO = new DocVO();
LoginUser loginUser = UserContext.getLoginUser();
docVO.setGatewayUrl(gatewayUrl);
docVO.setAppId(loginUser.getAppKey());
docVO.setMenuProjects(menuProjects);
docVO.setUrlProd(urlProd);
docVO.setUrlTest(urlTest);

@ -137,7 +137,7 @@ public class SandboxController {
response.flushBuffer();
return null;
} else if (!CollectionUtils.isEmpty(files)) {
responseData = httpTool.requestFile(url, params, Collections.emptyMap(), files);
responseData = httpTool.requestFileString(url, params, Collections.emptyMap(), files);
} else {
responseData = httpTool.request(url, params, Collections.emptyMap(), HttpTool.HTTPMethod.fromValue(httpMethod));
}

@ -0,0 +1,211 @@
package com.gitee.sop.websiteserver.controller;
import com.alibaba.fastjson.JSON;
import com.gitee.sop.websiteserver.bean.HttpTool;
import com.gitee.sop.websiteserver.sign.AlipayApiException;
import com.gitee.sop.websiteserver.sign.AlipaySignature;
import com.gitee.sop.websiteserver.util.UploadUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Response;
import okhttp3.ResponseBody;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.util.UriUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* 沙箱环境代理类
*
* @author tanghc
*/
@Slf4j
@RestController
@RequestMapping("sandbox")
public class SandboxV2Controller {
@Value("${api.url-sandbox}")
private String url;
static HttpTool httpTool = new HttpTool();
@RequestMapping("/test_v2")
public void proxy(
@RequestParam(required = false) String gatewayUrl
, @RequestParam String appId
, @RequestParam String privateKey
, @RequestParam(required = false) String token
, @RequestParam String method
, @RequestParam String version
, @RequestParam String bizContent
, @RequestParam(defaultValue = "get") String httpMethod
, @RequestParam(defaultValue = "false") boolean isDownloadRequest
, HttpServletRequest request
, HttpServletResponse response
) throws AlipayApiException, IOException {
Assert.isTrue(StringUtils.isNotBlank(appId), "AppId不能为空");
Assert.isTrue(StringUtils.isNotBlank(privateKey), "PrivateKey不能为空");
Assert.isTrue(StringUtils.isNotBlank(method), "method不能为空");
if (StringUtils.isEmpty(gatewayUrl)) {
gatewayUrl = url;
}
// 公共请求参数
Map<String, String> params = new HashMap<String, String>();
params.put("app_id", appId);
params.put("method", method);
params.put("format", "json");
params.put("charset", "utf-8");
params.put("sign_type", "RSA2");
params.put("timestamp", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
params.put("version", version);
if (StringUtils.isNotBlank(token)) {
params.put("app_auth_token", token);
}
// 业务参数
params.put("biz_content", bizContent);
String paramsQuery = buildParamQuery(params);
String content = AlipaySignature.getSignContent(params);
String sign = null;
try {
sign = AlipaySignature.rsa256Sign(content, privateKey, "utf-8");
} catch (AlipayApiException e) {
throw new RuntimeException("构建签名失败");
}
params.put("sign", sign);
Collection<MultipartFile> uploadFiles = UploadUtil.getUploadFiles(request);
List<HttpTool.UploadFile> files = uploadFiles.stream()
.map(multipartFile -> {
try {
return new HttpTool.UploadFile(multipartFile.getName(), multipartFile.getOriginalFilename(), multipartFile.getBytes());
} catch (IOException e) {
log.error("封装文件失败", e);
return null;
}
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
try {
Response resp = httpTool.request(gatewayUrl, params, Collections.emptyMap(), HttpTool.HTTPMethod.fromValue(httpMethod), files);
ResponseBody body = resp.body();
if (body == null) {
return;
}
Map<String, List<String>> headersMap = resp.headers().toMultimap();
Map<String, String> targetHeaders = new HashMap<>(headersMap.size() * 2);
headersMap.forEach((key, value) -> {
String headerValue = String.join(",", value);
response.setHeader(key, headerValue);
targetHeaders.put(key, headerValue);
});
response.addHeader("target-response-headers", JSON.toJSONString(targetHeaders));
response.addHeader("sendbox-params", UriUtils.encode(paramsQuery, StandardCharsets.UTF_8));
response.addHeader("sendbox-beforesign", UriUtils.encode(content, StandardCharsets.UTF_8));
response.addHeader("sendbox-sign", UriUtils.encode(sign, StandardCharsets.UTF_8));
IOUtils.copy(body.byteStream(), response.getOutputStream());
response.flushBuffer();
} catch (Exception e) {
log.error("请求失败", e);
throw new RuntimeException("请求失败");
}
}
@Data
public static class SandboxResult {
private String params;
private String beforeSign;
private String sign;
private Object apiResult;
}
/**
* 发送get请求
*
* @param url
* @return JSON或者字符串
* @throws Exception
*/
public static String get(String url, Map<String, String> params) {
CloseableHttpClient httpClient = null;
CloseableHttpResponse response = null;
try {
httpClient = HttpClients.createDefault();
List<NameValuePair> nameValuePairs = params.entrySet()
.stream()
.map(entry -> new BasicNameValuePair(entry.getKey(), String.valueOf(entry.getValue())))
.collect(Collectors.toList());
/**
* 包装成一个Entity对象
*/
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(nameValuePairs, "UTF-8");
//参数转换为字符串
String paramsStr = EntityUtils.toString(entity);
url = url + "?" + paramsStr;
/**
* 创建一个post对象
*/
HttpGet get = new HttpGet(url);
/**
* 执行post请求
*/
response = httpClient.execute(get);
/**
* 通过EntityUitls获取返回内容
*/
return EntityUtils.toString(response.getEntity(), "UTF-8");
} catch (Exception e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(httpClient);
IOUtils.closeQuietly(response);
}
return null;
}
protected String buildParamQuery(Map<String, String> params) {
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry : params.entrySet()) {
sb.append("&").append(entry.getKey()).append("=").append(entry.getValue());
}
return sb.substring(1);
}
}

@ -11,6 +11,8 @@ import java.util.Collection;
@Getter
@Setter
public class DocVO {
private String gatewayUrl;
private String appId;
private String urlTest;
private String urlProd;
private Collection<MenuProject> menuProjects;

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

@ -1 +1 @@
<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><link rel=icon href=favicon.ico><title>开放平台</title><link href=static/css/chunk-elementUI.ded27da0.css rel=stylesheet><link href=static/css/chunk-libs.3dfb7769.css rel=stylesheet><link href=static/css/app.520ff3b4.css rel=stylesheet></head><body><noscript><strong>We're sorry but 开放平台 doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script>(function(e){function n(n){for(var r,c,o=n[0],f=n[1],d=n[2],i=0,h=[];i<o.length;i++)c=o[i],u[c]&&h.push(u[c][0]),u[c]=0;for(r in f)Object.prototype.hasOwnProperty.call(f,r)&&(e[r]=f[r]);l&&l(n);while(h.length)h.shift()();return a.push.apply(a,d||[]),t()}function t(){for(var e,n=0;n<a.length;n++){for(var t=a[n],r=!0,c=1;c<t.length;c++){var o=t[c];0!==u[o]&&(r=!1)}r&&(a.splice(n--,1),e=f(f.s=t[0]))}return e}var r={},c={runtime:0},u={runtime:0},a=[];function o(e){return f.p+"static/js/"+({}[e]||e)+"."+{"chunk-27eb7616":"26efb320","chunk-28a29d22":"7852c65c","chunk-2d0ac226":"908e7bac","chunk-2d0b6e8a":"ddfa15ec","chunk-2d0e958e":"1652deea","chunk-2d216d78":"211ad599","chunk-4e7f1f48":"331ccf8a","chunk-5142434b":"623e9909","chunk-6440f6d0":"4dcd9cf4","chunk-2d0d43b7":"a9f25820","chunk-2d0e1a00":"c05ee2a3","chunk-57325c88":"6f1a8ef5","chunk-788f7208":"6f676b03","chunk-eaa69404":"04ac7757"}[e]+".js"}function f(n){if(r[n])return r[n].exports;var t=r[n]={i:n,l:!1,exports:{}};return e[n].call(t.exports,t,t.exports,f),t.l=!0,t.exports}f.e=function(e){var n=[],t={"chunk-27eb7616":1,"chunk-28a29d22":1,"chunk-4e7f1f48":1,"chunk-5142434b":1,"chunk-6440f6d0":1,"chunk-57325c88":1,"chunk-eaa69404":1};c[e]?n.push(c[e]):0!==c[e]&&t[e]&&n.push(c[e]=new Promise((function(n,t){for(var r="static/css/"+({}[e]||e)+"."+{"chunk-27eb7616":"67b30787","chunk-28a29d22":"4dc6f542","chunk-2d0ac226":"31d6cfe0","chunk-2d0b6e8a":"31d6cfe0","chunk-2d0e958e":"31d6cfe0","chunk-2d216d78":"31d6cfe0","chunk-4e7f1f48":"cf843403","chunk-5142434b":"0ad43c8d","chunk-6440f6d0":"b35fc6d0","chunk-2d0d43b7":"31d6cfe0","chunk-2d0e1a00":"31d6cfe0","chunk-57325c88":"77426e4e","chunk-788f7208":"31d6cfe0","chunk-eaa69404":"04f4b7fb"}[e]+".css",u=f.p+r,a=document.getElementsByTagName("link"),o=0;o<a.length;o++){var d=a[o],i=d.getAttribute("data-href")||d.getAttribute("href");if("stylesheet"===d.rel&&(i===r||i===u))return n()}var h=document.getElementsByTagName("style");for(o=0;o<h.length;o++){d=h[o],i=d.getAttribute("data-href");if(i===r||i===u)return n()}var l=document.createElement("link");l.rel="stylesheet",l.type="text/css",l.onload=n,l.onerror=function(n){var r=n&&n.target&&n.target.src||u,a=new Error("Loading CSS chunk "+e+" failed.\n("+r+")");a.code="CSS_CHUNK_LOAD_FAILED",a.request=r,delete c[e],l.parentNode.removeChild(l),t(a)},l.href=u;var s=document.getElementsByTagName("head")[0];s.appendChild(l)})).then((function(){c[e]=0})));var r=u[e];if(0!==r)if(r)n.push(r[2]);else{var a=new Promise((function(n,t){r=u[e]=[n,t]}));n.push(r[2]=a);var d,i=document.createElement("script");i.charset="utf-8",i.timeout=120,f.nc&&i.setAttribute("nonce",f.nc),i.src=o(e),d=function(n){i.onerror=i.onload=null,clearTimeout(h);var t=u[e];if(0!==t){if(t){var r=n&&("load"===n.type?"missing":n.type),c=n&&n.target&&n.target.src,a=new Error("Loading chunk "+e+" failed.\n("+r+": "+c+")");a.type=r,a.request=c,t[1](a)}u[e]=void 0}};var h=setTimeout((function(){d({type:"timeout",target:i})}),12e4);i.onerror=i.onload=d,document.head.appendChild(i)}return Promise.all(n)},f.m=e,f.c=r,f.d=function(e,n,t){f.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},f.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(e,n){if(1&n&&(e=f(e)),8&n)return e;if(4&n&&"object"===typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var r in e)f.d(t,r,function(n){return e[n]}.bind(null,r));return t},f.n=function(e){var n=e&&e.__esModule?function(){return e["default"]}:function(){return e};return f.d(n,"a",n),n},f.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},f.p="",f.oe=function(e){throw console.error(e),e};var d=window["webpackJsonp"]=window["webpackJsonp"]||[],i=d.push.bind(d);d.push=n,d=d.slice();for(var h=0;h<d.length;h++)n(d[h]);var l=i;t()})([]);</script><script src=static/js/chunk-elementUI.1d3df44e.js></script><script src=static/js/chunk-libs.089b1949.js></script><script src=static/js/app.5706d539.js></script></body></html>
<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><link rel=icon href=favicon.ico><title>开放平台</title><link href=static/css/chunk-elementUI.ded27da0.css rel=stylesheet><link href=static/css/chunk-libs.3dfb7769.css rel=stylesheet><link href=static/css/app.520ff3b4.css rel=stylesheet></head><body><noscript><strong>We're sorry but 开放平台 doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script>(function(e){function n(n){for(var r,c,a=n[0],d=n[1],f=n[2],i=0,h=[];i<a.length;i++)c=a[i],u[c]&&h.push(u[c][0]),u[c]=0;for(r in d)Object.prototype.hasOwnProperty.call(d,r)&&(e[r]=d[r]);l&&l(n);while(h.length)h.shift()();return o.push.apply(o,f||[]),t()}function t(){for(var e,n=0;n<o.length;n++){for(var t=o[n],r=!0,c=1;c<t.length;c++){var a=t[c];0!==u[a]&&(r=!1)}r&&(o.splice(n--,1),e=d(d.s=t[0]))}return e}var r={},c={runtime:0},u={runtime:0},o=[];function a(e){return d.p+"static/js/"+({}[e]||e)+"."+{"chunk-28a29d22":"7852c65c","chunk-2d0ac226":"908e7bac","chunk-2d0b6e8a":"ddfa15ec","chunk-2d0e958e":"1652deea","chunk-2d216d78":"211ad599","chunk-3d8e72b0":"d5d1a474","chunk-5142434b":"623e9909","chunk-5356e7e6":"2c0ab073","chunk-6440f6d0":"4dcd9cf4","chunk-2d0d43b7":"a9f25820","chunk-2d0e1a00":"c05ee2a3","chunk-57325c88":"6f1a8ef5","chunk-788f7208":"6f676b03"}[e]+".js"}function d(n){if(r[n])return r[n].exports;var t=r[n]={i:n,l:!1,exports:{}};return e[n].call(t.exports,t,t.exports,d),t.l=!0,t.exports}d.e=function(e){var n=[],t={"chunk-28a29d22":1,"chunk-3d8e72b0":1,"chunk-5142434b":1,"chunk-5356e7e6":1,"chunk-6440f6d0":1,"chunk-57325c88":1};c[e]?n.push(c[e]):0!==c[e]&&t[e]&&n.push(c[e]=new Promise((function(n,t){for(var r="static/css/"+({}[e]||e)+"."+{"chunk-28a29d22":"4dc6f542","chunk-2d0ac226":"31d6cfe0","chunk-2d0b6e8a":"31d6cfe0","chunk-2d0e958e":"31d6cfe0","chunk-2d216d78":"31d6cfe0","chunk-3d8e72b0":"04f4b7fb","chunk-5142434b":"0ad43c8d","chunk-5356e7e6":"52876932","chunk-6440f6d0":"b35fc6d0","chunk-2d0d43b7":"31d6cfe0","chunk-2d0e1a00":"31d6cfe0","chunk-57325c88":"77426e4e","chunk-788f7208":"31d6cfe0"}[e]+".css",u=d.p+r,o=document.getElementsByTagName("link"),a=0;a<o.length;a++){var f=o[a],i=f.getAttribute("data-href")||f.getAttribute("href");if("stylesheet"===f.rel&&(i===r||i===u))return n()}var h=document.getElementsByTagName("style");for(a=0;a<h.length;a++){f=h[a],i=f.getAttribute("data-href");if(i===r||i===u)return n()}var l=document.createElement("link");l.rel="stylesheet",l.type="text/css",l.onload=n,l.onerror=function(n){var r=n&&n.target&&n.target.src||u,o=new Error("Loading CSS chunk "+e+" failed.\n("+r+")");o.code="CSS_CHUNK_LOAD_FAILED",o.request=r,delete c[e],l.parentNode.removeChild(l),t(o)},l.href=u;var s=document.getElementsByTagName("head")[0];s.appendChild(l)})).then((function(){c[e]=0})));var r=u[e];if(0!==r)if(r)n.push(r[2]);else{var o=new Promise((function(n,t){r=u[e]=[n,t]}));n.push(r[2]=o);var f,i=document.createElement("script");i.charset="utf-8",i.timeout=120,d.nc&&i.setAttribute("nonce",d.nc),i.src=a(e),f=function(n){i.onerror=i.onload=null,clearTimeout(h);var t=u[e];if(0!==t){if(t){var r=n&&("load"===n.type?"missing":n.type),c=n&&n.target&&n.target.src,o=new Error("Loading chunk "+e+" failed.\n("+r+": "+c+")");o.type=r,o.request=c,t[1](o)}u[e]=void 0}};var h=setTimeout((function(){f({type:"timeout",target:i})}),12e4);i.onerror=i.onload=f,document.head.appendChild(i)}return Promise.all(n)},d.m=e,d.c=r,d.d=function(e,n,t){d.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},d.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},d.t=function(e,n){if(1&n&&(e=d(e)),8&n)return e;if(4&n&&"object"===typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(d.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var r in e)d.d(t,r,function(n){return e[n]}.bind(null,r));return t},d.n=function(e){var n=e&&e.__esModule?function(){return e["default"]}:function(){return e};return d.d(n,"a",n),n},d.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},d.p="",d.oe=function(e){throw console.error(e),e};var f=window["webpackJsonp"]=window["webpackJsonp"]||[],i=f.push.bind(f);f.push=n,f=f.slice();for(var h=0;h<f.length;h++)n(f[h]);var l=i;t()})([]);</script><script src=static/js/chunk-elementUI.1d3df44e.js></script><script src=static/js/chunk-libs.e265b709.js></script><script src=static/js/app.132894e5.js></script></body></html>

@ -1 +0,0 @@
.dashboard-container[data-v-7229b958]{margin:30px}.dashboard-text[data-v-7229b958]{font-size:18px;line-height:46px}

@ -1 +1 @@
@font-face{font-family:fontello;src:url(../../static/fonts/fontello.e73a0647.eot);src:url(../../static/fonts/fontello.e73a0647.eot#iefix) format("embedded-opentype"),url(../../static/fonts/fontello.8d4a4e6f.woff2) format("woff2"),url(../../static/fonts/fontello.a782baa8.woff) format("woff"),url(../../static/fonts/fontello.068ca2b3.ttf) format("truetype"),url(../../static/img/fontello.9354499c.svg#fontello) format("svg");font-weight:400;font-style:normal}[class*=" fa-mavon-"]:before,[class^=fa-mavon-]:before{font-family:fontello;font-style:normal;font-weight:400;speak:none;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;margin-left:.2em;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-mavon-bold:before{content:"\E800"}.fa-mavon-italic:before{content:"\E801"}.fa-mavon-thumb-tack:before{content:"\E802"}.fa-mavon-link:before{content:"\E803"}.fa-mavon-picture-o:before{content:"\E804"}.fa-mavon-repeat:before{content:"\E805"}.fa-mavon-undo:before{content:"\E806"}.fa-mavon-trash-o:before{content:"\E807"}.fa-mavon-floppy-o:before{content:"\E808"}.fa-mavon-compress:before{content:"\E809"}.fa-mavon-eye:before{content:"\E80A"}.fa-mavon-eye-slash:before{content:"\E80B"}.fa-mavon-question-circle:before{content:"\E80C"}.fa-mavon-times:before{content:"\E80D"}.fa-mavon-align-left:before{content:"\E80F"}.fa-mavon-align-center:before{content:"\E810"}.fa-mavon-align-right:before{content:"\E811"}.fa-mavon-arrows-alt:before{content:"\F0B2"}.fa-mavon-bars:before{content:"\F0C9"}.fa-mavon-list-ul:before{content:"\F0CA"}.fa-mavon-list-ol:before{content:"\F0CB"}.fa-mavon-strikethrough:before{content:"\F0CC"}.fa-mavon-underline:before{content:"\F0CD"}.fa-mavon-table:before{content:"\F0CE"}.fa-mavon-columns:before{content:"\F0DB"}.fa-mavon-quote-left:before{content:"\F10D"}.fa-mavon-code:before{content:"\F121"}.fa-mavon-superscript:before{content:"\F12B"}.fa-mavon-subscript:before{content:"\F12C"}.fa-mavon-header:before{content:"\F1DC"}.fa-mavon-window-maximize:before{content:"\F2D0"}.markdown-body strong{font-weight:bolder}.markdown-body .hljs-center{text-align:center}.markdown-body .hljs-right{text-align:right}.markdown-body .hljs-left{text-align:left}.api-info[data-v-c361512c]{font-weight:700}.doc-overview[data-v-c361512c]{margin-top:20px;margin-bottom:30px;color:#666;font-size:14px}.doc-request-method[data-v-c361512c]{margin-bottom:20px;color:#666;font-size:14px}
@font-face{font-family:fontello;src:url(../../static/fonts/fontello.e73a0647.eot);src:url(../../static/fonts/fontello.e73a0647.eot#iefix) format("embedded-opentype"),url(../../static/fonts/fontello.8d4a4e6f.woff2) format("woff2"),url(../../static/fonts/fontello.a782baa8.woff) format("woff"),url(../../static/fonts/fontello.068ca2b3.ttf) format("truetype"),url(../../static/img/fontello.9354499c.svg#fontello) format("svg");font-weight:400;font-style:normal}[class*=" fa-mavon-"]:before,[class^=fa-mavon-]:before{font-family:fontello;font-style:normal;font-weight:400;speak:none;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;margin-left:.2em;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-mavon-bold:before{content:"\E800"}.fa-mavon-italic:before{content:"\E801"}.fa-mavon-thumb-tack:before{content:"\E802"}.fa-mavon-link:before{content:"\E803"}.fa-mavon-picture-o:before{content:"\E804"}.fa-mavon-repeat:before{content:"\E805"}.fa-mavon-undo:before{content:"\E806"}.fa-mavon-trash-o:before{content:"\E807"}.fa-mavon-floppy-o:before{content:"\E808"}.fa-mavon-compress:before{content:"\E809"}.fa-mavon-eye:before{content:"\E80A"}.fa-mavon-eye-slash:before{content:"\E80B"}.fa-mavon-question-circle:before{content:"\E80C"}.fa-mavon-times:before{content:"\E80D"}.fa-mavon-align-left:before{content:"\E80F"}.fa-mavon-align-center:before{content:"\E810"}.fa-mavon-align-right:before{content:"\E811"}.fa-mavon-arrows-alt:before{content:"\F0B2"}.fa-mavon-bars:before{content:"\F0C9"}.fa-mavon-list-ul:before{content:"\F0CA"}.fa-mavon-list-ol:before{content:"\F0CB"}.fa-mavon-strikethrough:before{content:"\F0CC"}.fa-mavon-underline:before{content:"\F0CD"}.fa-mavon-table:before{content:"\F0CE"}.fa-mavon-columns:before{content:"\F0DB"}.fa-mavon-quote-left:before{content:"\F10D"}.fa-mavon-code:before{content:"\F121"}.fa-mavon-superscript:before{content:"\F12B"}.fa-mavon-subscript:before{content:"\F12C"}.fa-mavon-header:before{content:"\F1DC"}.fa-mavon-window-maximize:before{content:"\F2D0"}.markdown-body strong{font-weight:bolder}.markdown-body .hljs-center{text-align:center}.markdown-body .hljs-right{text-align:right}.markdown-body .hljs-left{text-align:left}.api-info[data-v-0f669452]{font-weight:700}.doc-overview[data-v-0f669452]{margin-top:20px;margin-bottom:30px;color:#666;font-size:14px}.doc-request-method[data-v-0f669452]{margin-bottom:20px;color:#666;font-size:14px}.table-control .el-form-item__error{position:inherit}span.required:before{content:"*";color:#f56c6c;margin-right:4px}.api-info{font-weight:700}.doc-overview{margin-top:20px;margin-bottom:30px;color:#666;font-size:14px}.doc-request-method{margin-bottom:20px;color:#666;font-size:14px}.cell .choose-file{padding:5px}.doc-debug .cell .el-form-item{margin-bottom:0}

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1 +0,0 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-4e7f1f48"],{9406:function(t,e,n){"use strict";n.r(e);var a=function(){var t=this,e=t.$createElement;t._self._c;return t._m(0)},s=[function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"dashboard-container"},[n("div",{staticClass:"dashboard-text"},[t._v("欢迎使用开放平台")])])}],c=(n("eaba"),n("2877")),i={},r=Object(c["a"])(i,a,s,!1,null,"7229b958",null);e["default"]=r.exports},d4e0:function(t,e,n){},eaba:function(t,e,n){"use strict";n("d4e0")}}]);

@ -2,5 +2,5 @@
ENV = 'production'
# base api
VUE_APP_BASE_API = 'http://localhost:8083'
VUE_APP_BASE_API = ''

@ -8,8 +8,15 @@
- 执行`npm run dev`,访问`http://localhost:9529/`
- 修改端口号:打开`vue.config.js`,找到`port`属性
## 修改端口号
打开`vue.config.js`,找到`port`属性
## 修改请求url
- 开发环境:打开`.env.development`文件,修改`VUE_APP_BASE_API`
- 生产环境:打开`.env.production`文件,修改`VUE_APP_BASE_API`
## 构建
开发完毕后,运行`build.sh`脚本
开发完毕后,运行`build.sh`脚本,生成后的内容在dist目录

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

@ -155,10 +155,6 @@ export default {
type: Object,
default: () => {}
},
uri: {
type: String,
default: ''
},
urlProd: {
type: String,
default: ''

@ -1,31 +1,61 @@
<template>
<div class="doc-debug">
<h2>{{ docInfo.summary }}</h2>
<el-table
:data="[{ methodLabel: '接口名(method)', methodValue: docInfo.name, versionLabel: '版本号(version)', versionValue: docInfo.version }]"
border
:cell-style="baseInfoCellStyle"
:show-header="false"
<el-form
ref="configForm"
size="mini"
:model="configFormData"
:rules="configFormRules"
label-width="120px"
>
<el-table-column prop="methodLabel" align="center" width="130">
<template slot-scope="scope"><span class="api-info">{{ scope.row.methodLabel }}</span></template>
</el-table-column>
<el-table-column prop="methodValue" />
<el-table-column prop="versionLabel" align="center" width="130">
<template slot-scope="scope"><span class="api-info">{{ scope.row.versionLabel }}</span></template>
</el-table-column>
<el-table-column prop="versionValue" width="120" />
</el-table>
<h3>接口描述</h3>
<div class="doc-overview">{{ docInfo.description || docInfo.title }}</div>
<h3>请求方法</h3>
<div class="doc-request-method">
{{ docInfo.httpMethodList && docInfo.httpMethodList.join(' / ').toUpperCase() }}
</div>
<el-form-item prop="url" label="网关地址">
<el-input v-model="configFormData.url" clearable />
</el-form-item>
<el-form-item prop="appKey" label="AppId">
<el-input v-model="configFormData.appKey" clearable />
</el-form-item>
<el-form-item prop="privateKey" label="应用私钥">
<el-input v-model="configFormData.privateKey" clearable @change="onPrivateKeyChange" />
</el-form-item>
<el-form-item label="token">
<el-input v-model="configFormData.token" clearable />
</el-form-item>
</el-form>
<h2>请求参数</h2>
<parameter-table :data="docInfo.requestParameters" :editable="true" />
<parameter-table-edit ref="paramTableRef" :data="docInfo.requestParameters" />
<!-- 多文件选择 -->
<el-upload
v-show="docInfo.multiple"
action=""
:multiple="true"
:auto-upload="false"
style="width: 500px;margin-top: 10px"
:on-remove="(file, fileList) => onSelectMultiFile(file, fileList)"
:on-change="(file, fileList) => onSelectMultiFile(file, fileList)"
>
<el-button slot="trigger" type="primary" size="mini">上传多个文件</el-button>
</el-upload>
<br/>
<el-form
size="mini"
>
<el-form-item label="HttpMethod">
<el-radio-group v-model="httpMethod">
<el-radio v-for="method in docInfo.httpMethodList" :key="method" :label="method">{{ method.toUpperCase() }}</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<el-button type="primary" @click="send">发送请求</el-button>
<el-tabs v-show="resultShow">
<el-tabs v-model="resultActive" type="card">
<el-tab-pane label="请求信息" name="reqInfo">
<el-input v-model="reqInfo" type="textarea" :rows="10" readonly />
</el-tab-pane>
<el-tab-pane label="请求结果" name="resultContent">
<el-input v-model="resultContent" type="textarea" :rows="16" readonly />
</el-tab-pane>
</el-tabs>
</el-tabs>
</div>
</template>
<style>
@ -36,20 +66,21 @@
.doc-debug .cell .el-form-item {margin-bottom: 0;}
</style>
<script>
import ParameterTable from '@/components/ParameterTable'
import ParameterTableEdit from '@/components/ParameterTableEdit'
const privateKeyStoreKey = 'sop.sendbox.privateKey'
export default {
name: 'Docdebug',
components: { ParameterTable },
components: { ParameterTableEdit },
props: {
item: {
type: Object,
default: () => {}
},
uri: {
appId: {
type: String,
default: ''
},
urlProd: {
gatewayUrl: {
type: String,
default: ''
}
@ -63,31 +94,192 @@ export default {
return { padding: '5px 0' }
}
},
configFormRules: {
appKey: [
{ required: true, message: '请填写AppId', trigger: 'blur' }
],
privateKey: [
{ required: true, message: '请填写应用私钥', trigger: 'blur' }
],
url: [
{ required: true, message: '请填写URL', trigger: 'blur' }
]
},
configFormData: {
url: '',
appKey: '',
privateKey: '',
token: ''
},
httpMethod: '',
docInfo: {
summary: '',
name: '',
version: '',
multiple: false,
uploadRequest: false,
httpMethodList: [],
requestParameters: [],
responseParameters: [],
bizCodes: []
}
},
uploadFiles: [],
resultActive: 'resultContent',
resultShow: false,
reqInfo: '',
resultContent: ''
}
},
watch: {
item(newVal) {
this.initItem(newVal)
},
appId(newVal) {
this.configFormData.appKey = newVal
},
gatewayUrl(url) {
this.configFormData.url = url
}
},
created() {
const privateKey = this.getAttr(privateKeyStoreKey)
if (privateKey) {
this.configFormData.privateKey = privateKey
}
},
methods: {
send() {
this.$refs.configForm.validate(valid => {
if (valid) {
//
const promiseRequestArr = this.validateTable(this.docInfo.requestParameters, ['req_form_example_'])
Promise.all(promiseRequestArr).then(validArr => {
//
this.doSend()
}).catch((e) => {
// this.tipError('')
}) // Uncaught (in promise)
}
})
},
doSend() {
const bizContent = this.buildParamData(this.docInfo.requestParameters)
const data = {
gatewayUrl: this.configFormData.url,
appId: this.configFormData.appKey,
privateKey: this.configFormData.privateKey,
token: this.configFormData.token,
method: this.docInfo.name,
version: this.docInfo.version,
httpMethod: this.httpMethod,
bizContent: JSON.stringify(bizContent)
}
const files = this.buildFiles(this.docInfo.requestParameters)
const isForm = this.httpMethod.toUpperCase() === 'POST'
this.request(this.httpMethod, '/sandbox/test_v2', data, {}, false, isForm, files, function(error, response) {
this.resultShow = true
this.resultActive = 'resultContent'
const status = response.statusCode || response.status
if (!error && status === 200) {
this.successHandler(response)
} else {
console.log(error)
this.$message.error('请求异常,请查看日志')
}
})
},
validateTable: function(arr, refPrefixArr) {
const $refs = this.$refs.paramTableRef.$refs
let promiseArr = []
for (let i = 0; i < arr.length; i++) {
const row = arr[i]
const id = row.id
refPrefixArr.forEach(refPrefix => {
const ref = $refs[refPrefix + id]
if (ref) {
promiseArr.push(ref.validate())
}
})
const children = arr[i].children
if (children && children.length > 0) {
const childrenPromiseArr = this.validateTable(children, refPrefixArr)
promiseArr = promiseArr.concat(childrenPromiseArr)
}
}
return promiseArr
},
successHandler(response) {
this.setReqInfo(response)
this.setRespInfo(response)
},
setReqInfo(response) {
const headers = response.headers
if (headers) {
const html = []
html.push('【请求参数】:' + decodeURIComponent(headers['sendbox-params']))
html.push('【待签名内容】:' + decodeURIComponent(headers['sendbox-beforesign']))
html.push('【签名(sign)】:' + decodeURIComponent(headers['sendbox-sign']))
this.reqInfo = html.join('\r\n')
}
},
setRespInfo(response) {
const headers = response.headers
const targetHeadersString = headers['target-response-headers'] || '{}'
const targetHeaders = JSON.parse(targetHeadersString)
const contentType = targetHeaders['content-type'] || ''
const contentDisposition = targetHeaders['content-disposition'] || ''
if (contentType.indexOf('stream') > -1 || contentDisposition.indexOf('attachment') > -1) {
const filename = this.getDispositionFilename(contentDisposition)
this.downloadFile(filename, response.raw)
} else {
const body = response.body || response.data
this.resultContent = JSON.stringify(body, null, 4)
}
},
downloadFile(filename, buffer) {
const url = window.URL.createObjectURL(new Blob([buffer]))
const link = document.createElement('a')
link.href = url
link.setAttribute('download', filename)
document.body.appendChild(link)
link.click()
},
getDispositionFilename(disposition) {
const dispositionArr = disposition.split(';')
for (let i = 0; i < dispositionArr.length; i++) {
const item = dispositionArr[i].trim()
// filename="xx"
if (item.toLowerCase().startsWith('filename')) {
const result = item.match(new RegExp('filename="(.*?)"', 'i'))
return result ? result[1] : ''
}
}
},
resetResult() {
this.reqInfo = ''
this.resultContent = ''
this.resultShow = false
},
initItem(item) {
if (item) {
this.setData(item)
}
},
setData: function(data) {
this.resetResult()
this.docInfo = data
this.httpMethod = this.docInfo.httpMethodList[0]
},
onSelectMultiFile(file, fileList) {
const files = []
fileList.forEach(file => {
const rawFile = file.raw
files.push(rawFile)
})
this.uploadFiles = files
},
onPrivateKeyChange() {
this.setAttr(privateKeyStoreKey, this.configFormData.privateKey)
},
buildParamData: function(params) {
const responseJson = {}
@ -117,6 +309,22 @@ export default {
return Object.values(responseJson)[0]
}
return responseJson
},
buildFiles(params) {
const files = []
for (let i = 0; i < params.length; i++) {
const row = params[i]
//
const fileConfig = row.__file__
if (fileConfig) {
files.push(fileConfig)
}
}
//
if (this.uploadFiles.length > 0) {
files.push({ name: 'file', files: this.uploadFiles })
}
return files
}
}
}

@ -50,17 +50,12 @@
label="示例值"
>
<template slot-scope="scope">
<div v-if="editable">
</div>
<div v-else>
<div v-if="scope.row.type === 'enum'">
{{ (scope.row.enums || []).join('、') }}
</div>
<div v-else>
{{ scope.row.paramExample }}
</div>
</div>
</template>
</el-table-column>
</el-table>
@ -74,10 +69,6 @@ export default {
type: Array,
default: () => []
},
editable: {
type: Boolean,
default: false
},
tree: {
type: Boolean,
default: true

@ -0,0 +1,121 @@
<template>
<el-table
:data="data"
border
row-key="id"
default-expand-all
:tree-props="{ children: 'refs', hasChildren: 'hasChildren' }"
:cell-style="cellStyleSmall()"
:header-cell-style="headCellStyleSmall()"
empty-text="无参数"
>
<el-table-column
prop="name"
label="名称"
width="250"
>
<template slot-scope="scope">
<span :class="{ 'required': scope.row.required}">{{ scope.row.name }}</span>
</template>
</el-table-column>
<el-table-column
prop="type"
label="类型"
width="100"
>
<template slot-scope="scope">
<span>{{ scope.row.type }}</span>
<span v-show="scope.row.type === 'array' && scope.row.elementType">
<el-tooltip effect="dark" :content="`元素类型:${scope.row.elementType}`" placement="top">
<i class="el-icon-info"></i>
</el-tooltip>
</span>
</template>
</el-table-column>
<el-table-column
prop="paramExample"
label="参数值"
>
<template slot-scope="scope">
<el-form
v-if="scope.row.type !== 'object'"
:ref="'req_form_example_' + scope.row.id"
:model="scope.row"
:rules="buildParamRules(scope.row)"
size="mini"
style="display: inline-block"
>
<el-form-item
prop="paramExample"
label-width="0"
class="table-control"
>
<el-upload
v-if="scope.row.type === 'file' || scope.row.elementType === 'file'"
action=""
:multiple="false"
:auto-upload="false"
:on-change="(file, fileList) => onSelectFile(file, fileList, scope.row)"
:on-remove="(file, fileList) => onSelectFile(file, fileList, scope.row)"
>
<el-button slot="trigger" class="choose-file" type="primary">选择文件</el-button>
</el-upload>
<el-input v-else v-model="scope.row.paramExample" placeholder="参数值" clearable />
</el-form-item>
</el-form>
</template>
</el-table-column>
<el-table-column
prop="description"
label="描述"
/>
</el-table>
</template>
<style>
.table-control .el-form-item__error {
position: inherit;
}
span.required:before {
content: '*';
color: #F56C6C;
margin-right: 4px;
}
</style>
<script>
export default {
name: 'ParameterTableEdit',
props: {
data: {
type: Array,
default: () => []
},
tree: {
type: Boolean,
default: true
}
},
methods: {
buildParamRules(row) {
const rules = []
if (row.required && row.type !== 'file') {
rules.push({ required: true, message: '请填写参数值', trigger: 'blur' })
}
const max = parseInt(row.maxLength)
if (max) {
rules.push({ max: max, message: `长度不超过 ${max} 个字符`, trigger: 'blur' })
}
return {
paramExample: rules
}
},
onSelectFile(f, fileList, row) {
const files = []
fileList.forEach(file => {
const rawFile = file.raw
files.push(rawFile)
})
row.__file__ = { name: row.name, files: files }
}
}
}
</script>

@ -5,9 +5,6 @@ Vue.use(Router)
/* Layout */
import Layout from '@/layout'
const _import = require('@/router/_import_' + process.env.NODE_ENV)
const menuKey = 'route-menus'
/**
* Note: sub-menus only appear when route children.length >= 1

@ -8,7 +8,7 @@ import needle from 'needle'
import md5 from 'js-md5'
import axios from 'axios'
const baseURL = process.env.VUE_APP_BASE_API
const baseURL = process.env.VUE_APP_BASE_API || `${location.protocol}//${location.host}`
const OPC_USER_TYPE_KEY = 'sop-user-type'
// 创建axios实例
@ -55,6 +55,43 @@ Object.assign(Vue.prototype, {
that.doResponse(error, response, callback, errorCallback)
})
},
request(method, uri, data, headers, isJson, isForm, files, callback) {
// 如果是文件上传,使用axios,needle上传文件不完美,不支持一个name对应多个文件
if (files && files.length > 0) {
this.doMultipart(uri, data, files, headers, callback)
return
}
const that = this
if (isForm) {
headers['Content-Type'] = 'application/x-www-form-urlencoded'
}
needle.request(method, baseURL + uri, data, {
// 设置header
headers: headers,
json: isJson
}, (error, response) => {
callback.call(that, error, response)
})
},
doMultipart(uri, data, files, headers, callback) {
const that = this
const formData = new FormData()
files.forEach(fileConfig => {
fileConfig.files.forEach(file => {
formData.append(fileConfig.name, file)
})
})
for (const name in data) {
formData.append(name, data[name])
}
client.post(uri, formData, {
headers: headers
}).then(function(response) {
callback.call(that, null, response)
}).catch(function(error) {
callback.call(that, error, null)
})
},
doResponse(error, response, callback, errorCallback) {
// 成功
if (!error && response.statusCode === 200) {
@ -226,9 +263,6 @@ Object.assign(Vue.prototype, {
goLogin() {
removeToken()
this.$router.replace({ path: `/login` })
setTimeout(function() {
location.reload()
}, 200)
},
goRoute: function(path) {
this.$router.push({ path: path })

@ -24,12 +24,25 @@
/>
</el-aside>
<el-main style="padding-top: 0">
<el-tabs>
<el-tabs v-show="item" v-model="active" type="card">
<el-tab-pane name="info">
<span slot="label"><i class="el-icon-document"></i> 接口信息</span>
<doc-view
v-show="item"
:item="item"
:url-prod="docVO.urlProd"
uri="/portal/isv/getDocItem"
/>
</el-tab-pane>
<el-tab-pane name="debug">
<span slot="label"><i class="el-icon-position"></i> 接口调试</span>
<docdebug
:item="item"
:app-id="docVO.appId"
:gateway-url="docVO.gatewayUrl"
/>
</el-tab-pane>
</el-tabs>
</el-tabs>
</el-main>
</el-container>
</div>
@ -38,13 +51,16 @@
<script>
import 'mavon-editor/dist/css/index.css'
import docView from '@/components/DocView'
import docdebug from '@/components/Docdebug'
export default {
components: { docView },
components: { docView, docdebug },
data() {
return {
active: 'info',
docVO: {
appId: '',
gatewayUrl: '',
urlProd: '',
urlTest: '',
menuProjects: []

@ -344,3 +344,9 @@ INSERT INTO `perm_role_permission` (`id`, `role_code`, `route_id`, `gmt_create`,
INSERT INTO `user_info` (`id`, `username`, `password`, `nickname`, `gmt_create`, `gmt_modified`) VALUES
(1,'zhangsan','123456','张三','2019-04-27 08:32:57','2019-04-27 08:32:57');
INSERT INTO `isp_resource` (`id`, `name`, `content`, `ext_content`, `version`, `type`, `is_deleted`, `gmt_create`, `gmt_modified`) VALUES
(1,'Java','http://www.baidu.com','```java\nString url = "http://localhost:8081";\nString appId = "2019032617262200001";\nString privateKey = "你的私钥";\n\n// 声明一个就行\nOpenClient client = new OpenClient(url, appId, privateKey);\n\n// 标准用法\n@Test\npublic void testGet() {\n // 创建请求对象\n GetStoryRequest request = new GetStoryRequest();\n // 请求参数\n GetStoryModel model = new GetStoryModel();\n model.setName("白雪公主");\n \n request.setBizModel(model);\n\n // 发送请求\n GetStoryResponse response = client.execute(request);\n\n if (response.isSuccess()) {\n // 返回结果\n System.out.println(response);\n } else {\n System.out.println(response);\n }\n}\n```','1.0',0,0,'2020-11-07 14:29:11','2020-11-07 14:29:11'),
(2,'C#','http://www.soso.com','```\nclass MainClass\n{\n static string url = "http://localhost:8081";\n static string appId = "2019032617262200001";\n // 平台提供的私钥\n static string privateKey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCXJv1pQFqWNA/++OYEV7WYXwexZK/J8LY1OWlP9X0T6wHFOvxNKRvMkJ5544SbgsJpVcvRDPrcxmhPbi/sAhdO4x2PiPKIz9Yni2OtYCCeaiE056B+e1O2jXoLeXbfi9fPivJZkxH/tb4xfLkH3bA8ZAQnQsoXA0SguykMRZntF0TndUfvDrLqwhlR8r5iRdZLB6F8o8qXH6UPDfNEnf/K8wX5T4EB1b8x8QJ7Ua4GcIUqeUxGHdQpzNbJdaQvoi06lgccmL+PHzminkFYON7alj1CjDN833j7QMHdPtS9l7B67fOU/p2LAAkPMtoVBfxQt9aFj7B8rEhGCz02iJIBAgMBAAECggEARqOuIpY0v6WtJBfmR3lGIOOokLrhfJrGTLF8CiZMQha+SRJ7/wOLPlsH9SbjPlopyViTXCuYwbzn2tdABigkBHYXxpDV6CJZjzmRZ+FY3S/0POlTFElGojYUJ3CooWiVfyUMhdg5vSuOq0oCny53woFrf32zPHYGiKdvU5Djku1onbDU0Lw8w+5tguuEZ76kZ/lUcccGy5978FFmYpzY/65RHCpvLiLqYyWTtaNT1aQ/9pw4jX9HO9NfdJ9gYFK8r/2f36ZE4hxluAfeOXQfRC/WhPmiw/ReUhxPznG/WgKaa/OaRtAx3inbQ+JuCND7uuKeRe4osP2jLPHPP6AUwQKBgQDUNu3BkLoKaimjGOjCTAwtp71g1oo+k5/uEInAo7lyEwpV0EuUMwLA/HCqUgR4K9pyYV+Oyb8d6f0+Hz0BMD92I2pqlXrD7xV2WzDvyXM3s63NvorRooKcyfd9i6ccMjAyTR2qfLkxv0hlbBbsPHz4BbU63xhTJp3Ghi0/ey/1HQKBgQC2VsgqC6ykfSidZUNLmQZe3J0p/Qf9VLkfrQ+xaHapOs6AzDU2H2osuysqXTLJHsGfrwVaTs00ER2z8ljTJPBUtNtOLrwNRlvgdnzyVAKHfOgDBGwJgiwpeE9voB1oAV/mXqSaUWNnuwlOIhvQEBwekqNyWvhLqC7nCAIhj3yvNQKBgQCqYbeec56LAhWP903Zwcj9VvG7sESqXUhIkUqoOkuIBTWFFIm54QLTA1tJxDQGb98heoCIWf5x/A3xNI98RsqNBX5JON6qNWjb7/dobitti3t99v/ptDp9u8JTMC7penoryLKK0Ty3bkan95Kn9SC42YxaSghzqkt+uvfVQgiNGQKBgGxU6P2aDAt6VNwWosHSe+d2WWXt8IZBhO9d6dn0f7ORvcjmCqNKTNGgrkewMZEuVcliueJquR47IROdY8qmwqcBAN7Vg2K7r7CPlTKAWTRYMJxCT1Hi5gwJb+CZF3+IeYqsJk2NF2s0w5WJTE70k1BSvQsfIzAIDz2yE1oPHvwVAoGAA6e+xQkVH4fMEph55RJIZ5goI4Y76BSvt2N5OKZKd4HtaV+eIhM3SDsVYRLIm9ZquJHMiZQGyUGnsvrKL6AAVNK7eQZCRDk9KQz+0GKOGqku0nOZjUbAu6A2/vtXAaAuFSFx1rUQVVjFulLexkXR3KcztL1Qu2k5pB6Si0K/uwQ=";\n\n\n // 声明一个就行\n static OpenClient client = new OpenClient(url, appId, privateKey);\n\n public static void Main(string[] args)\n {\n TestGet();\n }\n\n // 标准用法\n private static void TestGet()\n {\n // 创建请求对象\n GetStoryRequest request = new GetStoryRequest();\n // 请求参数\n GetStoryModel model = new GetStoryModel();\n model.Name = "白雪公主";\n request.BizModel = model;\n\n // 发送请求\n GetStoryResponse response = client.Execute(request);\n\n if (response.IsSuccess())\n {\n // 返回结果\n Console.WriteLine("成功!response:{0}\\n响应原始内容:{1}", JsonUtil.ToJSONString(response), response.Body);\n }\n else\n {\n Console.WriteLine("错误, code:{0}, msg:{1}, subCode:{2}, subMsg:{3}",\n response.Code, response.Msg, response.SubCode, response.SubMsg);\n }\n }\n\n \n}\n```','1.0',0,0,'2020-11-07 14:29:38','2020-11-07 14:29:38'),
(3,'Python','http://www.bilibili.com','```python\n # 创建请求\n request = MemberInfoGetRequest()\n # 请求参数\n model = MemberInfoGetModel()\n model.age = 22\n model.name = \'jim\'\n model.address = \'xx\'\n # 添加请求参数\n request.biz_model = model\n\n # 添加上传文件\n # files = {\n # \'file1\': open(\'aa.txt\', \'rb\'),\n # \'file2\': open(\'bb.txt\', \'rb\')\n # }\n # request.files = files\n\n # 调用请求\n response = self.client.execute(request)\n\n if response.is_success():\n print \'response: \', response\n print \'is_vip:\', response.get(\'member_info\').get(\'is_vip\', 0)\n else:\n print \',code:%s, msg:%s, sub_code:%s, sub_msg:%s\' % \\\n (response.code, response.msg, response.sub_code, response.sub_msg)\n```','1.0',0,0,'2020-11-07 14:30:16','2020-11-07 14:31:41'),
(4,'Go','http://www.baidu.com','```go\n\n// 应用ID\nconst appId string = "xx"\n// 应用私钥\nconst privateKey string = "xx"\n// 请求地址\nconst url string = "http://localhost:7071/prod/gw68uy85"\n\n// 请求客户端\nvar openClient = common.OpenClient{AppId: appId, PrivateKey: privateKey, Url: url}\n\nfunc main() {\n // 创建请求\n memberInfoGetRequest := request.MemberInfoGetRequest{}\n // 请求参数\n memberInfoGetRequest.BizModel = model.MemberInfoGetModel{Name: "jim", Age: 22, Address: "xx"}\n \n // 添加上传文件\n //path, _ := os.Getwd()\n //files := []common.UploadFile{\n // {Name:"file1", Filepath:path + "/test/aa.txt"},\n // {Name:"file2", Filepath:path + "/test/bb.txt"},\n //}\n //memberInfoGetRequest.Files = files\n \n // 发送请求,返回json bytes\n var jsonBytes = openClient.Execute(memberInfoGetRequest)\n fmt.Printf("data:%s\\n", string(jsonBytes))\n // 转换结果\n var memberInfoGetResponse response.MemberInfoGetResponse\n response.ConvertResponse(jsonBytes, &memberInfoGetResponse)\n\n if memberInfoGetResponse.IsSuccess() {\n fmt.Printf("is_vip:%d, vip_endtime:%s\\n", memberInfoGetResponse.MemberInfo.IsVip, memberInfoGetResponse.MemberInfo.VipEndtime)\n } else {\n fmt.Printf("code:%s, msg:%s, subCode:%s, subMsg:%s\\n",\n memberInfoGetResponse.Code, memberInfoGetResponse.Msg, memberInfoGetResponse.SubCode, memberInfoGetResponse.SubMsg)\n }\n}\n```','1.0',0,0,'2020-11-07 14:31:21','2020-11-07 14:31:21'),
(5,'C++','http://pan.baidu.com','#include <iostream>\n\n#include "common/OpenClient.h"\n#include "request/BaseRequest.h"\n#include "request/MemberInfoGetRequest.hpp"\n\n// 应用ID\nstring appId = "2020051325943082302177280";\n// 存放私钥的文件路径\nstring privateKeyFile = "/Users/thc/IdeaProjects/opc/opc-sdk/sdk-c++/privateEx.pem";\n// 请求接口\nstring url = "http://localhost:7071/prod/gw68uy85";\n\nOpenClient openClient(appId, privateKeyFile, url);\n\nint main() {\n // 创建请求\n MemberInfoGetRequest request;\n\n // 业务参数\n map<string, string> bizModel;\n bizModel["name"] = "jim";\n bizModel["age"] = "22";\n bizModel["address"] = "xx";\n\n request.bizModel = bizModel;\n\n // 添加上传文件\n// request->setFiles({\n// FileInfo{"aa", "/Users/thc/IdeaProjects/opc/opc-sdk/sdk-c++/aa.txt"},\n// FileInfo{"bb", "/Users/thc/IdeaProjects/opc/opc-sdk/sdk-c++/bb.txt"}\n// });\n\n // 发送请求\n neb::CJsonObject jsonObj = openClient.execute(&request);\n std::cout << jsonObj.ToString() << std::endl;\n std::cout << "id:" << jsonObj["id"].ToString() << std::endl;\n std::cout << "is_vip:" << jsonObj["member_info"]["is_vip"].ToString() << std::endl;\n return 0;\n}\n\n','1.0',0,0,'2020-11-07 14:32:55','2020-11-07 14:32:55');

Loading…
Cancel
Save