├── .gitignore ├── README.md ├── README_EN.md ├── pom.xml └── src └── main └── java └── cn └── veasion └── aippt ├── AiPptDemo1.java ├── AiPptDemo2.java ├── AiPptDemo3.java ├── AiPptDemo4.java ├── Api.java └── HttpUtils.java /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | !**/src/main/**/target/ 4 | !**/src/test/**/target/ 5 | 6 | ### IntelliJ IDEA ### 7 | .idea/ 8 | *.iws 9 | *.iml 10 | *.ipr 11 | 12 | ### Eclipse ### 13 | .apt_generated 14 | .classpath 15 | .factorypath 16 | .project 17 | .settings 18 | .springBeans 19 | .sts4-cache 20 | 21 | ### NetBeans ### 22 | /nbproject/private/ 23 | /nbbuild/ 24 | /dist/ 25 | /nbdist/ 26 | /.nb-gradle/ 27 | build/ 28 | !**/src/main/**/build/ 29 | !**/src/test/**/build/ 30 | 31 | ### VS Code ### 32 | .vscode/ 33 | 34 | ### Mac OS ### 35 | .DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

logo

2 |

文多多 AiPPT

3 |

4 | 简体中文 | English 5 |

6 |

7 | 🔗在线演示 8 |   •   9 | 📝PPT转JSON 10 |   •   11 | 🌏官方网站 12 |   •   13 | 💬合作交流 14 |

15 | 16 | 17 | 18 | 19 | 20 | # 🤖 AI 生成 PPT 21 | 22 | 商用级 AI 生成 PPT 项目,包含以下功能: 23 | 24 | * AI 生成 PPT 25 | * PPT 解析成 JSON 26 | * JSON 反渲染为 PPT 27 | 28 | 29 | 30 | # ✨ AiPPT 31 | 32 | 在线体验:https://veasion.github.io/aippt 33 | 34 | 35 | [演示视频](https://metasign-public.oss-cn-shanghai.aliyuncs.com/github/aippt.mp4) 36 | 37 | https://github.com/veasion/aippt/assets/24989778/24d5654b-09f3-4554-a732-dbffc1073a1d 38 | 39 | 40 | 41 | # ✨ PPT 解析成 JSON 42 | 43 | 支持上传PPT并渲染,在线编辑,编辑后下载 ppt 文件。 44 | 45 | 在线体验:https://veasion.github.io/aippt/ppt2json.html 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | # 🤝 商业合作 55 | 56 | 针对上面技术,我们开发了一套可商用 aippt 软件,支持代理 & 私有化部署! 57 | 58 | 我们的优势,支持定制化行业解决方案,支持原生图表、动画等复杂PPT解析和渲染,支持用户自定义模板,技术方案行业领先,价格行业最低。 59 | 60 | 官网地址(开放API): 61 | https://docmee.cn 62 | 63 | 开放平台(API/UI 接入): 64 | https://docmee.cn/open-platform 65 | 66 | 67 | 商业合作 & 进群交流: 68 | 69 | ![qrcode](https://metasign-public.oss-cn-shanghai.aliyuncs.com/github/contact_me_qr.png) 70 | -------------------------------------------------------------------------------- /README_EN.md: -------------------------------------------------------------------------------- 1 |

logo

2 |

Docmee AiPPT

3 |

4 | English | 简体中文 5 |

6 |

7 | 🔗Demo 8 |   •   9 | 📝PPT to JSON 10 |   •   11 | 🌏Official website 12 |   •   13 | 💬Business cooperation 14 |

15 | 16 | 17 | 18 | 19 | 20 | # 🤖 AI Generate PPT 21 | 22 | Commercial level AI generated PPT project, including the following features: 23 | 24 | * AI generated PPT 25 | * PPT parsed into JSON 26 | * JSON re-rendered as PPT 27 | 28 | 29 | 30 | # ✨ AiPPT 31 | 32 | Demo: https://veasion.github.io/aippt 33 | 34 | [Demo Video](https://metasign-public.oss-cn-shanghai.aliyuncs.com/github/aippt.mp4) 35 | 36 | https://github.com/veasion/aippt/assets/24989778/24d5654b-09f3-4554-a732-dbffc1073a1d 37 | 38 | 39 | 40 | # ✨ PPT to JSON 41 | 42 | Support uploading PPT and rendering, online editing, and download the edited PPT file. 43 | 44 | Demo: https://veasion.github.io/aippt/ppt2json.html 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | # 🤝 Business cooperation 54 | 55 | We have developed a commercially available aippt software that supports proxy and private deployment for the above technology! 56 | 57 | Our advantages include supporting customized industry solutions, supporting complex PPT analysis and rendering such as native charts and animations, supporting user-defined templates, leading technology solutions, and the lowest prices in the industry. 58 | 59 | Official website (Open API): 60 | https://docmee.cn 61 | 62 | Open platform (API / UI): 63 | https://docmee.cn/open-platform 64 | 65 | 66 | WeChat group qrcode: 67 | 68 | ![qrcode](https://metasign-public.oss-cn-shanghai.aliyuncs.com/github/contact_me_qr.png) 69 | 70 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | cn.veasion 8 | aippt-api-java-demo 9 | 1.0.0 10 | 11 | 12 | 1.8 13 | 8 14 | 8 15 | UTF-8 16 | UTF-8 17 | 1.2.83 18 | 2.15.0 19 | 4.5.14 20 | 21 | 22 | 23 | 24 | 25 | com.alibaba 26 | fastjson 27 | ${fastjson.version} 28 | 29 | 30 | 31 | org.apache.httpcomponents 32 | httpmime 33 | ${httpclient.version} 34 | 35 | 36 | commons-io 37 | commons-io 38 | ${commons-io.version} 39 | 40 | 41 | 42 | 43 | 44 | 45 | src/main/java 46 | 47 | 48 | 49 | 50 | org.apache.maven.plugins 51 | maven-compiler-plugin 52 | 3.1 53 | 54 | 1.8 55 | 1.8 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /src/main/java/cn/veasion/aippt/AiPptDemo1.java: -------------------------------------------------------------------------------- 1 | package cn.veasion.aippt; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | 5 | import javax.swing.filechooser.FileSystemView; 6 | import java.io.File; 7 | 8 | /** 9 | * 同步流式生成 PPT 10 | * 11 | * @author veasion 12 | * @date 2024/7/12 13 | */ 14 | public class AiPptDemo1 { 15 | 16 | public static void main(String[] args) throws Exception { 17 | // 官网 https://docmee.cn 18 | // 开放平台 https://docmee.cn/open-platform/api 19 | 20 | // 填写你的API-KEY 21 | String apiKey = "YOUR API KEY"; 22 | 23 | // 第三方用户ID(数据隔离) 24 | String uid = "test"; 25 | String subject = "AI未来的发展"; 26 | 27 | // 创建 api token (有效期2小时,建议缓存到redis,同一个 uid 创建时之前的 token 会在10秒内失效) 28 | String apiToken = Api.createApiToken(apiKey, uid, null); 29 | System.out.println("api token: " + apiToken); 30 | 31 | // 生成大纲 32 | System.out.println("\n\n========== 正在生成大纲 =========="); 33 | String outline = Api.generateOutline(apiToken, subject, null, null); 34 | 35 | // 生成大纲内容 36 | System.out.println("\n\n========== 正在生成大纲内容 =========="); 37 | String markdown = Api.generateContent(apiToken, outline, null, null); 38 | 39 | // 随机一个模板 40 | System.out.println("\n\n========== 随机选择模板 =========="); 41 | String templateId = Api.randomOneTemplateId(apiToken); 42 | System.out.println(templateId); 43 | 44 | // 生成PPT 45 | System.out.println("\n\n========== 正在生成PPT =========="); 46 | JSONObject pptInfo = Api.generatePptx(apiToken, templateId, markdown, false); 47 | String pptId = pptInfo.getString("id"); 48 | System.out.println("pptId: " + pptId); 49 | System.out.println("ppt主题:" + pptInfo.getString("subject")); 50 | System.out.println("ppt封面:" + pptInfo.getString("coverUrl") + "?token=" + apiToken); 51 | 52 | // 下载PPT到桌面 53 | System.out.println("\n\n========== 正在下载PPT =========="); 54 | JSONObject result = Api.downloadPptx(apiToken, pptId); 55 | String url = result.getString("fileUrl"); 56 | System.out.println("ppt链接:" + url); 57 | String savePath = FileSystemView.getFileSystemView().getHomeDirectory().getAbsolutePath() + File.separator + pptId + ".pptx"; 58 | HttpUtils.download(url, new File(savePath)); 59 | System.out.println("ppt下载完成,保存路径:" + savePath); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/cn/veasion/aippt/AiPptDemo2.java: -------------------------------------------------------------------------------- 1 | package cn.veasion.aippt; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | 5 | import javax.swing.filechooser.FileSystemView; 6 | import java.io.File; 7 | import java.util.Map; 8 | 9 | /** 10 | * 异步流式生成 PPT 11 | * 12 | * @author veasion 13 | * @date 2024/7/12 14 | */ 15 | public class AiPptDemo2 { 16 | 17 | public static void main(String[] args) throws Exception { 18 | // 官网 https://docmee.cn 19 | // 开放平台 https://docmee.cn/open-platform/api 20 | 21 | // 填写你的API-KEY 22 | String apiKey = "YOUR API KEY"; 23 | 24 | // 第三方用户ID(数据隔离) 25 | String uid = "test"; 26 | // 文档文件,支持 word/excel/ppt/md/txt/pdf 等类型 27 | File file = new File("README.md"); 28 | 29 | // 创建 api token (有效期2小时,建议缓存到redis,同一个 uid 创建时之前的 token 会在10秒内失效) 30 | String apiToken = Api.createApiToken(apiKey, uid, null); 31 | System.out.println("apiToken: " + apiToken); 32 | 33 | // 解析文件 34 | String dataUrl = Api.parseFileData(apiToken, file, null, null); 35 | 36 | // 生成大纲 37 | System.out.println("\n\n========== 正在生成大纲 =========="); 38 | String outline = Api.generateOutline(apiToken, null, dataUrl, null); 39 | 40 | // 异步生成大纲内容 41 | System.out.println("\n\n========== 正在异步生成大纲内容 =========="); 42 | Map pptInfo = Api.asyncGenerateContent(apiToken, outline, dataUrl, null, null); 43 | 44 | String pptId = pptInfo.get("id"); 45 | 46 | // 下载PPT到桌面 47 | System.out.println("\n\n========== 正在下载PPT =========="); 48 | System.out.println("pptId: " + pptId); 49 | String url = null; 50 | for (int i = 0; i < 30; i++) { 51 | // 等待PPT文件可下载 52 | JSONObject result = Api.downloadPptx(apiToken, pptId); 53 | if (result != null) { 54 | url = result.getString("fileUrl"); 55 | if (url != null) { 56 | break; 57 | } 58 | } 59 | Thread.sleep(1000); 60 | } 61 | System.out.println("ppt链接:" + url); 62 | String savePath = FileSystemView.getFileSystemView().getHomeDirectory().getAbsolutePath() + File.separator + pptId + ".pptx"; 63 | HttpUtils.download(url, new File(savePath)); 64 | System.out.println("ppt下载完成,保存路径:" + savePath); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/cn/veasion/aippt/AiPptDemo3.java: -------------------------------------------------------------------------------- 1 | package cn.veasion.aippt; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | 5 | import javax.swing.filechooser.FileSystemView; 6 | import java.io.File; 7 | 8 | /** 9 | * 通过主题直接生成 PPT 10 | * 11 | * @author veasion 12 | * @date 2024/7/12 13 | */ 14 | public class AiPptDemo3 { 15 | 16 | public static void main(String[] args) throws Exception { 17 | // 官网 https://docmee.cn 18 | // 开放平台 https://docmee.cn/open-platform/api 19 | 20 | // 填写你的API-KEY 21 | String apiKey = "YOUR API KEY"; 22 | 23 | // 第三方用户ID(数据隔离) 24 | String uid = "test"; 25 | String subject = "AI未来的发展"; 26 | 27 | // 创建 api token (有效期2小时,建议缓存到redis,同一个 uid 创建时之前的 token 会在10秒内失效) 28 | String apiToken = Api.createApiToken(apiKey, uid, null); 29 | System.out.println("apiToken: " + apiToken); 30 | 31 | // 通过主题直接生成PPT 32 | System.out.println("\n正在生成PPT...\n"); 33 | JSONObject pptInfo = Api.directGeneratePptx(apiToken, true, null, subject, null, null, false); 34 | 35 | String pptId = pptInfo.getString("id"); 36 | String fileUrl = pptInfo.getString("fileUrl"); 37 | System.out.println("\n\n==============="); 38 | System.out.println("pptId: " + pptId); 39 | System.out.println("ppt主题:" + pptInfo.getString("subject")); 40 | System.out.println("ppt封面:" + pptInfo.getString("coverUrl")); 41 | System.out.println("ppt链接:" + fileUrl); 42 | 43 | // 下载PPT到桌面 44 | String savePath = FileSystemView.getFileSystemView().getHomeDirectory().getAbsolutePath() + File.separator + pptId + ".pptx"; 45 | HttpUtils.download(fileUrl, new File(savePath)); 46 | System.out.println("ppt下载完成,保存路径:" + savePath); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/cn/veasion/aippt/AiPptDemo4.java: -------------------------------------------------------------------------------- 1 | package cn.veasion.aippt; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | 5 | import javax.swing.filechooser.FileSystemView; 6 | import java.io.File; 7 | 8 | /** 9 | * 通过文件直接生成 PPT 10 | * 11 | * @author veasion 12 | * @date 2024/7/12 13 | */ 14 | public class AiPptDemo4 { 15 | 16 | public static void main(String[] args) throws Exception { 17 | // 官网 https://docmee.cn 18 | // 开放平台 https://docmee.cn/open-platform/api 19 | 20 | // 填写你的API-KEY 21 | String apiKey = "YOUR API KEY"; 22 | 23 | // 第三方用户ID(数据隔离) 24 | String uid = "test"; 25 | // 文档文件,支持 word/excel/ppt/md/txt/pdf 等类型 26 | File file = new File("README.md"); 27 | 28 | // 创建 api token (有效期2小时,建议缓存到redis,同一个 uid 创建时之前的 token 会在10秒内失效) 29 | String apiToken = Api.createApiToken(apiKey, uid, null); 30 | System.out.println("apiToken: " + apiToken); 31 | 32 | // 解析文件 33 | String dataUrl = Api.parseFileData(apiToken, file, null, null); 34 | 35 | // 通过文件直接生成PPT 36 | System.out.println("\n正在生成PPT...\n"); 37 | JSONObject pptInfo = Api.directGeneratePptx(apiToken, true, null, null, dataUrl, null, false); 38 | 39 | String pptId = pptInfo.getString("id"); 40 | String fileUrl = pptInfo.getString("fileUrl"); 41 | System.out.println("\n\n==============="); 42 | System.out.println("pptId: " + pptId); 43 | System.out.println("ppt主题:" + pptInfo.getString("subject")); 44 | System.out.println("ppt封面:" + pptInfo.getString("coverUrl")); 45 | System.out.println("ppt链接:" + fileUrl); 46 | 47 | // 下载PPT到桌面 48 | String savePath = FileSystemView.getFileSystemView().getHomeDirectory().getAbsolutePath() + File.separator + pptId + ".pptx"; 49 | HttpUtils.download(fileUrl, new File(savePath)); 50 | System.out.println("ppt下载完成,保存路径:" + savePath); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/cn/veasion/aippt/Api.java: -------------------------------------------------------------------------------- 1 | package cn.veasion.aippt; 2 | 3 | import com.alibaba.fastjson.JSONArray; 4 | import com.alibaba.fastjson.JSONObject; 5 | import org.apache.http.entity.ContentType; 6 | import org.apache.http.entity.mime.MultipartEntityBuilder; 7 | 8 | import java.io.File; 9 | import java.nio.charset.StandardCharsets; 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | import java.util.Objects; 13 | 14 | /** 15 | * Api 16 | * 17 | * @author luozhuowei 18 | * @date 2024/7/15 19 | */ 20 | public class Api { 21 | 22 | public static final String BASE_URL = "https://docmee.cn"; 23 | 24 | public static String createApiToken(String apiKey, String uid, Integer limit) { 25 | String url = BASE_URL + "/api/user/createApiToken"; 26 | JSONObject body = new JSONObject(); 27 | body.put("uid", uid); 28 | body.put("limit", limit); 29 | HttpUtils.HttpRequest httpRequest = HttpUtils.HttpRequest.postJson(url); 30 | httpRequest.setBody(body.toJSONString()); 31 | httpRequest.addHeaders("Api-Key", apiKey); 32 | HttpUtils.HttpResponse response = HttpUtils.request(httpRequest); 33 | if (response.getStatus() != 200) { 34 | throw new RuntimeException("创建apiToken失败,httpStatus=" + response.getStatus()); 35 | } 36 | JSONObject result = response.getResponseToJson(); 37 | if (result.getIntValue("code") != 0) { 38 | throw new RuntimeException("创建apiToken异常," + result.getString("message")); 39 | } 40 | return result.getJSONObject("data").getString("token"); 41 | } 42 | 43 | public static String parseFileData(String apiToken, File file, String content, String fileUrl) { 44 | String url = BASE_URL + "/api/ppt/parseFileData"; 45 | HttpUtils.HttpRequest httpRequest = new HttpUtils.HttpRequest(); 46 | httpRequest.setUrl(url); 47 | httpRequest.setMethod("POST"); 48 | httpRequest.addHeaders("token", apiToken); 49 | MultipartEntityBuilder multipartEntity = MultipartEntityBuilder.create(); 50 | multipartEntity.setCharset(StandardCharsets.UTF_8); 51 | if (file != null) { 52 | multipartEntity.addBinaryBody("file", file); 53 | } 54 | if (content != null) { 55 | multipartEntity.addTextBody("content", content, ContentType.create("text/plain", StandardCharsets.UTF_8)); 56 | } 57 | if (fileUrl != null) { 58 | multipartEntity.addTextBody("fileUrl", fileUrl, ContentType.create("text/plain", StandardCharsets.UTF_8)); 59 | } 60 | httpRequest.setBody(multipartEntity.build()); 61 | HttpUtils.HttpResponse response = HttpUtils.request(httpRequest); 62 | if (response.getStatus() != 200) { 63 | throw new RuntimeException("解析文件或内容失败,httpStatus=" + response.getStatus()); 64 | } 65 | JSONObject result = response.getResponseToJson(); 66 | if (result.getIntValue("code") != 0) { 67 | throw new RuntimeException("解析文件或内容异常," + result.getString("message")); 68 | } 69 | return result.getJSONObject("data").getString("dataUrl"); 70 | } 71 | 72 | public static String generateOutline(String apiToken, String subject, String dataUrl, String prompt) { 73 | String url = BASE_URL + "/api/ppt/generateOutline"; 74 | JSONObject body = new JSONObject(); 75 | body.put("subject", subject); 76 | body.put("dataUrl", dataUrl); 77 | body.put("prompt", prompt); 78 | HttpUtils.HttpRequest httpRequest = HttpUtils.HttpRequest.postJson(url); 79 | httpRequest.setBody(body.toJSONString()); 80 | httpRequest.addHeaders("token", apiToken); 81 | StringBuilder sb = new StringBuilder(); 82 | HttpUtils.HttpResponse response = HttpUtils.requestWithEventStream(httpRequest, data -> { 83 | if (data == null || data.isEmpty()) { 84 | return; 85 | } 86 | JSONObject json = JSONObject.parseObject(data); 87 | if (Objects.equals(json.getInteger("status"), -1)) { 88 | throw new RuntimeException(json.getString("error")); 89 | } 90 | String text = json.getString("text"); 91 | sb.append(text); 92 | // 打印输出 93 | System.out.print(text); 94 | }); 95 | if (response.getStatus() != 200) { 96 | throw new RuntimeException("生成大纲失败,httpStatus=" + response.getStatus()); 97 | } 98 | if (response.getHeaders().getOrDefault("Content-Type", response.getHeaders().get("content-type")).contains("application/json")) { 99 | JSONObject result = response.getResponseToJson(); 100 | throw new RuntimeException("生成大纲失败:" + result.getString("message")); 101 | } 102 | return sb.toString(); 103 | } 104 | 105 | public static String generateContent(String apiToken, String outlineMarkdown, String dataUrl, String prompt) { 106 | String url = BASE_URL + "/api/ppt/generateContent"; 107 | JSONObject body = new JSONObject(); 108 | body.put("outlineMarkdown", outlineMarkdown); 109 | body.put("dataUrl", dataUrl); 110 | body.put("prompt", prompt); 111 | HttpUtils.HttpRequest httpRequest = HttpUtils.HttpRequest.postJson(url); 112 | httpRequest.setBody(body.toJSONString()); 113 | httpRequest.addHeaders("token", apiToken); 114 | StringBuilder sb = new StringBuilder(); 115 | HttpUtils.HttpResponse response = HttpUtils.requestWithEventStream(httpRequest, data -> { 116 | if (data == null || data.isEmpty()) { 117 | return; 118 | } 119 | JSONObject json = JSONObject.parseObject(data); 120 | if (Objects.equals(json.getInteger("status"), -1)) { 121 | throw new RuntimeException(json.getString("error")); 122 | } 123 | String text = json.getString("text"); 124 | sb.append(text); 125 | // 打印输出 126 | System.out.print(text); 127 | }); 128 | if (response.getStatus() != 200) { 129 | throw new RuntimeException("生成大纲内容失败,httpStatus=" + response.getStatus()); 130 | } 131 | if (response.getHeaders().getOrDefault("Content-Type", response.getHeaders().get("content-type")).contains("application/json")) { 132 | JSONObject result = response.getResponseToJson(); 133 | throw new RuntimeException("生成大纲内容失败:" + result.getString("message")); 134 | } 135 | return sb.toString(); 136 | } 137 | 138 | public static Map asyncGenerateContent(String apiToken, String outlineMarkdown, String dataUrl, String templateId, String prompt) { 139 | String url = BASE_URL + "/api/ppt/generateContent"; 140 | JSONObject body = new JSONObject(); 141 | body.put("asyncGenPptx", true); 142 | body.put("templateId", templateId); 143 | body.put("outlineMarkdown", outlineMarkdown); 144 | body.put("dataUrl", dataUrl); 145 | body.put("prompt", prompt); 146 | HttpUtils.HttpRequest httpRequest = HttpUtils.HttpRequest.postJson(url); 147 | httpRequest.setBody(body.toJSONString()); 148 | httpRequest.addHeaders("token", apiToken); 149 | Map pptInfo = new HashMap<>(); 150 | StringBuilder sb = new StringBuilder(); 151 | HttpUtils.HttpResponse response = HttpUtils.requestWithEventStream(httpRequest, data -> { 152 | if (data == null || data.isEmpty()) { 153 | return; 154 | } 155 | JSONObject json = JSONObject.parseObject(data); 156 | if (Objects.equals(json.getInteger("status"), -1)) { 157 | throw new RuntimeException(json.getString("error")); 158 | } 159 | if (json.getString("pptId") != null) { 160 | pptInfo.put("id", json.getString("pptId")); 161 | } 162 | String text = json.getString("text"); 163 | sb.append(text); 164 | // 打印输出 165 | System.out.print(text); 166 | }); 167 | if (response.getStatus() != 200) { 168 | throw new RuntimeException("生成大纲内容失败,httpStatus=" + response.getStatus()); 169 | } 170 | if (response.getHeaders().getOrDefault("Content-Type", response.getHeaders().get("content-type")).contains("application/json")) { 171 | JSONObject result = response.getResponseToJson(); 172 | throw new RuntimeException("生成大纲内容失败:" + result.getString("message")); 173 | } 174 | pptInfo.put("markdown", sb.toString()); 175 | return pptInfo; 176 | } 177 | 178 | public static String randomOneTemplateId(String apiToken) { 179 | String url = BASE_URL + "/api/ppt/randomTemplates"; 180 | JSONObject body = new JSONObject(); 181 | body.put("size", 1); 182 | JSONObject filters = new JSONObject(); 183 | filters.put("type", 1); 184 | body.put("filters", filters); 185 | HttpUtils.HttpRequest httpRequest = HttpUtils.HttpRequest.postJson(url); 186 | httpRequest.setBody(body.toJSONString()); 187 | httpRequest.addHeaders("token", apiToken); 188 | HttpUtils.HttpResponse response = HttpUtils.request(httpRequest); 189 | if (response.getStatus() != 200) { 190 | throw new RuntimeException("获取模板失败,httpStatus=" + response.getStatus()); 191 | } 192 | JSONObject result = response.getResponseToJson(); 193 | if (result.getIntValue("code") != 0) { 194 | throw new RuntimeException("获取模板异常," + result.getString("message")); 195 | } 196 | JSONArray data = result.getJSONArray("data"); 197 | JSONObject template = data.getJSONObject(0); 198 | return template.getString("id"); 199 | } 200 | 201 | public static JSONObject generatePptx(String apiToken, String templateId, String markdown, boolean pptxProperty) { 202 | String url = BASE_URL + "/api/ppt/generatePptx"; 203 | JSONObject body = new JSONObject(); 204 | body.put("templateId", templateId); 205 | body.put("outlineContentMarkdown", markdown); 206 | body.put("pptxProperty", pptxProperty); 207 | HttpUtils.HttpRequest httpRequest = HttpUtils.HttpRequest.postJson(url); 208 | httpRequest.setBody(body.toJSONString()); 209 | httpRequest.addHeaders("token", apiToken); 210 | HttpUtils.HttpResponse response = HttpUtils.request(httpRequest); 211 | if (response.getStatus() != 200) { 212 | throw new RuntimeException("生成PPT失败,httpStatus=" + response.getStatus()); 213 | } 214 | JSONObject result = response.getResponseToJson(); 215 | if (result.getIntValue("code") != 0) { 216 | throw new RuntimeException("生成PPT异常," + result.getString("message")); 217 | } 218 | return result.getJSONObject("data").getJSONObject("pptInfo"); 219 | } 220 | 221 | public static JSONObject downloadPptx(String apiToken, String id) { 222 | String url = BASE_URL + "/api/ppt/downloadPptx"; 223 | JSONObject body = new JSONObject(); 224 | body.put("id", id); 225 | HttpUtils.HttpRequest httpRequest = HttpUtils.HttpRequest.postJson(url); 226 | httpRequest.setBody(body.toJSONString()); 227 | httpRequest.addHeaders("token", apiToken); 228 | HttpUtils.HttpResponse response = HttpUtils.request(httpRequest); 229 | if (response.getStatus() != 200) { 230 | throw new RuntimeException("下载PPT失败,httpStatus=" + response.getStatus()); 231 | } 232 | JSONObject result = response.getResponseToJson(); 233 | if (result.getIntValue("code") != 0) { 234 | throw new RuntimeException("下载PPT异常," + result.getString("message")); 235 | } 236 | return result.getJSONObject("data"); 237 | } 238 | 239 | public static JSONObject directGeneratePptx(String apiToken, boolean stream, String templateId, String subject, String dataUrl, String prompt, boolean pptxProperty) { 240 | String url = BASE_URL + "/api/ppt/directGeneratePptx"; 241 | JSONObject body = new JSONObject(); 242 | body.put("stream", stream); 243 | body.put("templateId", templateId); 244 | body.put("subject", subject); 245 | body.put("dataUrl", dataUrl); 246 | body.put("prompt", prompt); 247 | body.put("pptxProperty", pptxProperty); 248 | HttpUtils.HttpRequest httpRequest = HttpUtils.HttpRequest.postJson(url); 249 | httpRequest.setBody(body.toJSONString()); 250 | httpRequest.addHeaders("token", apiToken); 251 | if (stream) { 252 | // 流式生成 253 | JSONObject[] pptInfo = new JSONObject[1]; 254 | HttpUtils.HttpResponse response = HttpUtils.requestWithEventStream(httpRequest, data -> { 255 | if (data == null || data.isEmpty()) { 256 | return; 257 | } 258 | JSONObject json = JSONObject.parseObject(data); 259 | if (Objects.equals(json.getInteger("status"), -1)) { 260 | throw new RuntimeException(json.getString("error")); 261 | } 262 | if (Objects.equals(json.getInteger("status"), 4) && json.containsKey("result")) { 263 | pptInfo[0] = json.getJSONObject("result"); 264 | } 265 | String text = json.getString("text"); 266 | // 打印输出 267 | System.out.print(text); 268 | }); 269 | if (response.getStatus() != 200) { 270 | throw new RuntimeException("生成PPT失败,httpStatus=" + response.getStatus()); 271 | } 272 | if (response.getHeaders().getOrDefault("Content-Type", response.getHeaders().get("content-type")).contains("application/json")) { 273 | JSONObject result = response.getResponseToJson(); 274 | throw new RuntimeException("生成PPT失败:" + result.getString("message")); 275 | } 276 | return pptInfo[0]; 277 | } else { 278 | // 非流式生成 279 | HttpUtils.HttpResponse response = HttpUtils.request(httpRequest); 280 | if (response.getStatus() != 200) { 281 | throw new RuntimeException("生成PPT失败,httpStatus=" + response.getStatus()); 282 | } 283 | JSONObject result = response.getResponseToJson(); 284 | if (result.getIntValue("code") != 0) { 285 | throw new RuntimeException("生成PPT异常," + result.getString("message")); 286 | } 287 | return result.getJSONObject("data").getJSONObject("pptInfo"); 288 | } 289 | } 290 | 291 | } 292 | -------------------------------------------------------------------------------- /src/main/java/cn/veasion/aippt/HttpUtils.java: -------------------------------------------------------------------------------- 1 | package cn.veasion.aippt; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.JSONObject; 5 | import org.apache.commons.io.IOUtils; 6 | import org.apache.http.Header; 7 | import org.apache.http.HttpEntity; 8 | import org.apache.http.HttpEntityEnclosingRequest; 9 | import org.apache.http.client.HttpClient; 10 | import org.apache.http.client.config.RequestConfig; 11 | import org.apache.http.client.methods.HttpDelete; 12 | import org.apache.http.client.methods.HttpGet; 13 | import org.apache.http.client.methods.HttpPatch; 14 | import org.apache.http.client.methods.HttpPost; 15 | import org.apache.http.client.methods.HttpPut; 16 | import org.apache.http.client.methods.HttpRequestBase; 17 | import org.apache.http.config.Registry; 18 | import org.apache.http.config.RegistryBuilder; 19 | import org.apache.http.conn.socket.ConnectionSocketFactory; 20 | import org.apache.http.conn.socket.PlainConnectionSocketFactory; 21 | import org.apache.http.conn.ssl.SSLConnectionSocketFactory; 22 | import org.apache.http.entity.ByteArrayEntity; 23 | import org.apache.http.entity.ContentType; 24 | import org.apache.http.entity.FileEntity; 25 | import org.apache.http.entity.InputStreamEntity; 26 | import org.apache.http.entity.StringEntity; 27 | import org.apache.http.impl.client.HttpClients; 28 | import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; 29 | 30 | import javax.net.ssl.SSLContext; 31 | import javax.net.ssl.X509TrustManager; 32 | import java.io.BufferedReader; 33 | import java.io.File; 34 | import java.io.FileOutputStream; 35 | import java.io.InputStream; 36 | import java.io.InputStreamReader; 37 | import java.io.Serializable; 38 | import java.io.UnsupportedEncodingException; 39 | import java.net.HttpURLConnection; 40 | import java.net.SocketException; 41 | import java.net.URL; 42 | import java.net.URLEncoder; 43 | import java.nio.charset.StandardCharsets; 44 | import java.security.SecureRandom; 45 | import java.security.cert.X509Certificate; 46 | import java.util.ArrayList; 47 | import java.util.Arrays; 48 | import java.util.Collections; 49 | import java.util.HashMap; 50 | import java.util.LinkedHashMap; 51 | import java.util.List; 52 | import java.util.Map; 53 | import java.util.concurrent.ExecutionException; 54 | import java.util.concurrent.ExecutorService; 55 | import java.util.concurrent.Future; 56 | import java.util.concurrent.TimeUnit; 57 | import java.util.concurrent.TimeoutException; 58 | import java.util.concurrent.atomic.AtomicInteger; 59 | import java.util.function.Consumer; 60 | import java.util.function.Function; 61 | 62 | /** 63 | * HttpUtils 64 | * 65 | * @author veasion 66 | * @date 2021/9/13 67 | */ 68 | public class HttpUtils { 69 | 70 | public static final String CHARSET_DEFAULT = "UTF-8"; 71 | public static final String CONTENT_TYPE = "Content-Type"; 72 | public static final String CONTENT_TYPE_JSON = "application/json"; 73 | public static final String CONTENT_TYPE_FORM_DATA = "application/x-www-form-urlencoded"; 74 | private static final PoolingHttpClientConnectionManager CONNECTION_MANAGER; 75 | private static final int MAX_CONNECT_TIMEOUT = 8000; 76 | private static final int MAX_SOCKET_TIMEOUT = 90000; 77 | 78 | static { 79 | CONNECTION_MANAGER = new PoolingHttpClientConnectionManager(getDefaultRegistry()); 80 | CONNECTION_MANAGER.setMaxTotal(500); 81 | CONNECTION_MANAGER.setDefaultMaxPerRoute(50); 82 | CONNECTION_MANAGER.setValidateAfterInactivity(2000); 83 | } 84 | 85 | public static HttpResponse get(String url) { 86 | return get(url, null); 87 | } 88 | 89 | public static HttpResponse get(String url, Map params) { 90 | String urlLinks = getUrlLinks(params); 91 | if (urlLinks != null) { 92 | if (url.contains("?")) { 93 | url = url + "&" + urlLinks; 94 | } else { 95 | url = url + "?" + urlLinks; 96 | } 97 | } 98 | return request(HttpRequest.build(url, "GET")); 99 | } 100 | 101 | public static void download(String url, File destFile) throws Exception { 102 | HttpRequest request = HttpRequest.build(url, "GET"); 103 | request.setResponseHandler(entity -> { 104 | try { 105 | if (!destFile.getParentFile().exists()) { 106 | destFile.getParentFile().mkdirs(); 107 | } 108 | try (FileOutputStream fs = new FileOutputStream(destFile)) { 109 | entity.writeTo(fs); 110 | } 111 | return destFile; 112 | } catch (Exception e) { 113 | return e; 114 | } 115 | }); 116 | HttpResponse response = request(request); 117 | if (response.getResponse() instanceof Exception) { 118 | throw (Exception) response.getResponse(); 119 | } 120 | } 121 | 122 | public static HttpResponse postJson(String url, String bodyJson) { 123 | HttpRequest request = HttpRequest.build(url, "POST").setBody(bodyJson); 124 | if (request.getHeaders() == null) { 125 | request.setHeaders(Collections.singletonMap(CONTENT_TYPE, CONTENT_TYPE_JSON)); 126 | } else { 127 | request.getHeaders().put(CONTENT_TYPE, CONTENT_TYPE_JSON); 128 | } 129 | return request(request); 130 | } 131 | 132 | public static HttpResponse postForm(String url, Map params) { 133 | String urlLinks = getUrlLinks(params); 134 | HttpRequest request = HttpRequest.build(url, "POST").setBody(urlLinks != null ? urlLinks : ""); 135 | if (request.getHeaders() == null) { 136 | request.setHeaders(Collections.singletonMap(CONTENT_TYPE, CONTENT_TYPE_FORM_DATA)); 137 | } else { 138 | request.getHeaders().put(CONTENT_TYPE, CONTENT_TYPE_FORM_DATA); 139 | } 140 | return request(request); 141 | } 142 | 143 | public static HttpResponse requestWithEventStream(ExecutorService executorService, long firstReadTimeout, HttpRequest request, Consumer dataConsumer) throws ExecutionException, InterruptedException, TimeoutException { 144 | return requestWithEventStream(executorService, firstReadTimeout, request, dataConsumer, null); 145 | } 146 | 147 | public static HttpResponse requestWithEventStream(ExecutorService executorService, long firstReadTimeout, HttpRequest request, Consumer dataConsumer, Consumer> futureConsumer) throws ExecutionException, InterruptedException, TimeoutException { 148 | // status: 0 start 1 run 2 timeout 149 | AtomicInteger status = new AtomicInteger(0); 150 | Future submit = executorService.submit(() -> { 151 | if (request.getMaxSocketTimeout() == null) { 152 | request.setMaxSocketTimeout(30_000); 153 | } 154 | request.setResponseHandler(entity -> { 155 | StringBuilder sb = new StringBuilder(); 156 | try { 157 | try (InputStream is = entity.getContent()) { 158 | try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) { 159 | String line; 160 | while ((line = bufferedReader.readLine()) != null) { 161 | if (status.get() == 2) { 162 | throw new TimeoutException(); 163 | } 164 | status.set(1); 165 | sb.append(line).append("\n"); 166 | if (line.startsWith("data:")) { 167 | dataConsumer.accept(line.substring(line.startsWith("data: ") ? 6 : 5)); 168 | } 169 | } 170 | } 171 | } 172 | } catch (Exception e) { 173 | throw new RuntimeException("eventStream 请求异常", e); 174 | } 175 | return sb.toString(); 176 | }); 177 | return request(request); 178 | }); 179 | if (futureConsumer != null) { 180 | futureConsumer.accept(submit); 181 | } 182 | try { 183 | HttpResponse httpResponse = submit.get(firstReadTimeout, TimeUnit.MILLISECONDS); 184 | if (httpResponse != null) { 185 | return httpResponse; 186 | } 187 | } catch (TimeoutException e) { 188 | if (status.get() == 0) { 189 | status.set(2); 190 | submit.cancel(true); 191 | throw e; 192 | } 193 | } 194 | return submit.get(); 195 | } 196 | 197 | public static HttpResponse requestWithEventStream(HttpRequest request, Consumer dataConsumer) { 198 | if (request.getMaxSocketTimeout() == null) { 199 | request.setMaxSocketTimeout(30_000); 200 | } 201 | request.setResponseHandler(entity -> { 202 | StringBuilder sb = new StringBuilder(); 203 | try { 204 | try (InputStream is = entity.getContent()) { 205 | try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) { 206 | String line; 207 | while ((line = bufferedReader.readLine()) != null) { 208 | sb.append(line).append("\n"); 209 | if (line.startsWith("data:")) { 210 | dataConsumer.accept(line.substring(line.startsWith("data: ") ? 6 : 5)); 211 | } 212 | } 213 | } 214 | } 215 | } catch (Exception e) { 216 | throw new RuntimeException("eventStream 请求异常", e); 217 | } 218 | return sb.toString(); 219 | }); 220 | return request(request); 221 | } 222 | 223 | public static int getUrlHttpStatus(String _url) { 224 | HttpURLConnection urlConnection = null; 225 | try { 226 | URL url = new URL(_url); 227 | urlConnection = (HttpURLConnection) url.openConnection(); 228 | urlConnection.connect(); 229 | return urlConnection.getResponseCode(); 230 | } catch (Exception ignored) { 231 | return -1; 232 | } finally { 233 | if (urlConnection != null) { 234 | urlConnection.disconnect(); 235 | } 236 | } 237 | } 238 | 239 | public static String getUrlLinks(Map params) { 240 | if (params == null || params.isEmpty()) { 241 | return null; 242 | } 243 | StringBuilder sb = new StringBuilder(); 244 | try { 245 | String[] sortedKeys = params.keySet().toArray(new String[0]); 246 | Arrays.sort(sortedKeys); 247 | for (String key : sortedKeys) { 248 | if (key == null || key.isEmpty()) { 249 | continue; 250 | } 251 | Object value = params.get(key); 252 | sb.append(key).append("="); 253 | if (value != null) { 254 | sb.append(URLEncoder.encode(value.toString(), "UTF-8")); 255 | } 256 | sb.append("&"); 257 | } 258 | } catch (UnsupportedEncodingException e) { 259 | throw new RuntimeException(e); 260 | } 261 | if (sb.length() > 0) { 262 | sb.setLength(sb.length() - 1); 263 | } 264 | return sb.toString(); 265 | } 266 | 267 | @SuppressWarnings("unchecked") 268 | public static Map parseUrlLinks(String params) { 269 | Map result = new LinkedHashMap<>(); 270 | if (params == null || params.isEmpty()) { 271 | return result; 272 | } 273 | for (String param : params.split("&")) { 274 | String[] split = param.split("="); 275 | String key = split[0]; 276 | String value = ""; 277 | if (split.length > 1) { 278 | value = split[1]; 279 | } 280 | if (result.containsKey(key)) { 281 | Object o = result.get(key); 282 | if (o instanceof List) { 283 | ((List) o).add(value); 284 | } else { 285 | List list = new ArrayList<>(); 286 | list.add(o); 287 | list.add(value); 288 | result.put(key, list); 289 | } 290 | } else { 291 | result.put(key, value); 292 | } 293 | } 294 | return result; 295 | } 296 | 297 | /** 298 | * 通用接口请求 299 | */ 300 | public static HttpResponse request(HttpRequest request) { 301 | return request(request, 0); 302 | } 303 | 304 | private static HttpResponse request(HttpRequest request, int retryCount) { 305 | HttpRequestBase requestBase = toRequest(request); 306 | Map headers = request.getHeaders(); 307 | ContentType contentType = null; 308 | if (headers != null && !headers.isEmpty()) { 309 | for (Map.Entry entry : headers.entrySet()) { 310 | String key = entry.getKey(); 311 | if (key == null || key.isEmpty()) { 312 | continue; 313 | } 314 | String value = entry.getValue(); 315 | if (CONTENT_TYPE.equalsIgnoreCase(key) && value != null) { 316 | contentType = ContentType.parse(value); 317 | } 318 | requestBase.setHeader(key, value); 319 | } 320 | } 321 | 322 | // body 323 | setBodyEntity(requestBase, contentType, request.getBody()); 324 | 325 | try { 326 | HttpClient client = getHttpClient(request, requestBase); 327 | org.apache.http.HttpResponse response; 328 | long startTime = System.currentTimeMillis(); 329 | response = client.execute(requestBase); 330 | HttpResponse httpResponse = new HttpResponse(); 331 | httpResponse.setReqTime(System.currentTimeMillis() - startTime); 332 | httpResponse.setStatus(response.getStatusLine().getStatusCode()); 333 | Header[] allHeaders = response.getAllHeaders(); 334 | if (allHeaders != null && allHeaders.length > 0) { 335 | httpResponse.setHeaders(new HashMap<>()); 336 | for (Header header : allHeaders) { 337 | httpResponse.getHeaders().put(header.getName(), header.getValue()); 338 | } 339 | } 340 | HttpEntity entity = response.getEntity(); 341 | if (request.responseHandler != null) { 342 | httpResponse.setResponse(request.responseHandler.apply(entity)); 343 | } else { 344 | String charset = null; 345 | if (entity.getContentType() != null && entity.getContentType().getValue() != null) { 346 | contentType = ContentType.parse(entity.getContentType().getValue()); 347 | if (contentType.getCharset() != null) { 348 | charset = contentType.getCharset().name(); 349 | } 350 | } 351 | if (charset == null) { 352 | charset = CHARSET_DEFAULT; 353 | } 354 | httpResponse.setResponse(IOUtils.toString(entity.getContent(), charset)); 355 | } 356 | return httpResponse; 357 | } catch (Exception e) { 358 | requestBase.abort(); 359 | if (request.getMaxRetryCount() > retryCount) { 360 | return request(request, retryCount + 1); 361 | } else if (e instanceof SocketException && "Connection reset".equals(e.getMessage()) && retryCount == 0 && request.getMaxRetryCount() == 0) { 362 | // 遇到 Connection reset 默认重试一次 363 | return request(request, retryCount + 1); 364 | } else { 365 | throw new RuntimeException("请求异常", e); 366 | } 367 | } finally { 368 | requestBase.releaseConnection(); 369 | } 370 | } 371 | 372 | private static void setBodyEntity(HttpRequestBase requestBase, ContentType contentType, Object body) { 373 | if (body != null && requestBase instanceof HttpEntityEnclosingRequest) { 374 | HttpEntityEnclosingRequest entityRequest = (HttpEntityEnclosingRequest) requestBase; 375 | if (body instanceof HttpEntity) { 376 | entityRequest.setEntity((HttpEntity) body); 377 | } else if (body instanceof String) { 378 | entityRequest.setEntity(getStringEntity((String) body, contentType)); 379 | } else if (body instanceof byte[]) { 380 | entityRequest.setEntity(new ByteArrayEntity((byte[]) body, contentType)); 381 | } else if (body instanceof File) { 382 | entityRequest.setEntity(new FileEntity((File) body, contentType)); 383 | } else if (body instanceof InputStream) { 384 | entityRequest.setEntity(new InputStreamEntity((InputStream) body, contentType)); 385 | } else if (ContentType.APPLICATION_JSON.equals(contentType)) { 386 | entityRequest.setEntity(getStringEntity(JSON.toJSONString(body), contentType)); 387 | } else { 388 | entityRequest.setEntity(getStringEntity(body.toString(), contentType)); 389 | } 390 | } 391 | } 392 | 393 | private static StringEntity getStringEntity(String body, ContentType contentType) { 394 | if (contentType != null && contentType.getCharset() != null) { 395 | return new StringEntity(body, contentType); 396 | } else { 397 | return new StringEntity(body, CHARSET_DEFAULT); 398 | } 399 | } 400 | 401 | public static HttpRequestBase toRequest(HttpRequest request) { 402 | String url = request.getUrl(); 403 | String method = request.getMethod(); 404 | if (url == null || url.isEmpty()) { 405 | throw new RuntimeException("url不能为空"); 406 | } 407 | if (method == null || method.isEmpty()) { 408 | method = "GET"; 409 | } 410 | switch (method.toUpperCase()) { 411 | case "GET": 412 | return new HttpGet(url); 413 | case "POST": 414 | return new HttpPost(url); 415 | case "PUT": 416 | return new HttpPut(url); 417 | case "PATCH": 418 | return new HttpPatch(url); 419 | case "DELETE": 420 | return new HttpDelete(url); 421 | default: 422 | throw new RuntimeException("不支持的请求方式:" + method); 423 | } 424 | } 425 | 426 | private static HttpClient getHttpClient(HttpRequest req, HttpRequestBase request) { 427 | RequestConfig.Builder customReqConf = RequestConfig.custom(); 428 | if (req.getMaxSocketTimeout() != null) { 429 | customReqConf.setSocketTimeout(req.getMaxSocketTimeout()); 430 | } else { 431 | customReqConf.setSocketTimeout(MAX_SOCKET_TIMEOUT); 432 | } 433 | customReqConf.setConnectTimeout(MAX_CONNECT_TIMEOUT); 434 | customReqConf.setConnectionRequestTimeout(MAX_CONNECT_TIMEOUT); 435 | if (req.getRequestConfigConsumer() != null) { 436 | req.getRequestConfigConsumer().accept(customReqConf); 437 | } 438 | request.setConfig(customReqConf.build()); 439 | return HttpClients.custom().setConnectionManager(CONNECTION_MANAGER).build(); 440 | } 441 | 442 | private static Registry getDefaultRegistry() { 443 | try { 444 | // ssl: TLS / TLSv1.2 / TLSv1.3 445 | SSLContext context = SSLContext.getInstance("TLS"); 446 | context.init(null, new X509TrustManager[]{new X509TrustManager() { 447 | public void checkClientTrusted(X509Certificate[] x509Certificates, String s) { 448 | } 449 | 450 | public void checkServerTrusted(X509Certificate[] x509Certificates, String s) { 451 | } 452 | 453 | public X509Certificate[] getAcceptedIssuers() { 454 | return new X509Certificate[0]; 455 | } 456 | }}, new SecureRandom()); 457 | return RegistryBuilder.create() 458 | .register("http", PlainConnectionSocketFactory.getSocketFactory()) 459 | .register("https", new SSLConnectionSocketFactory(context)) 460 | .build(); 461 | } catch (Exception e) { 462 | return RegistryBuilder.create() 463 | .register("http", PlainConnectionSocketFactory.getSocketFactory()) 464 | .register("https", SSLConnectionSocketFactory.getSocketFactory()) 465 | .build(); 466 | } 467 | } 468 | 469 | public static String toParamLinks(Map params, boolean encode) { 470 | List keys = new ArrayList<>(params.keySet()); 471 | Collections.sort(keys); 472 | StringBuilder sb = new StringBuilder(); 473 | try { 474 | for (String key : keys) { 475 | if (key == null || "".equals(key)) { 476 | continue; 477 | } 478 | Object value = params.get(key); 479 | if (value == null || "".equals(value)) { 480 | continue; 481 | } 482 | if (encode) { 483 | sb.append(key).append("=").append(URLEncoder.encode(value.toString(), "UTF-8")).append("&"); 484 | } else { 485 | sb.append(key).append("=").append(value).append("&"); 486 | } 487 | } 488 | } catch (UnsupportedEncodingException e) { 489 | throw new RuntimeException("编码失败", e); 490 | } 491 | if (sb.length() > 0) { 492 | sb.setLength(sb.length() - 1); 493 | } 494 | return sb.toString(); 495 | } 496 | 497 | public static class HttpRequest implements Serializable { 498 | 499 | private String url; 500 | private String method; 501 | private Map headers; 502 | private Object body; 503 | private int maxRetryCount = 0; 504 | private Integer maxSocketTimeout; 505 | private Consumer requestConfigConsumer; 506 | private Function responseHandler; 507 | 508 | public static HttpRequest build(String url, String method) { 509 | HttpRequest request = new HttpRequest(); 510 | request.url = url; 511 | request.method = method; 512 | return request; 513 | } 514 | 515 | public static HttpRequest get(String url) { 516 | return build(url, "GET"); 517 | } 518 | 519 | public static HttpRequest postJson(String url) { 520 | return build(url, "POST").setContentType(CONTENT_TYPE_JSON); 521 | } 522 | 523 | public static HttpRequest postFormData(String url) { 524 | return build(url, "POST").setContentType(CONTENT_TYPE_FORM_DATA); 525 | } 526 | 527 | public String getUrl() { 528 | return url; 529 | } 530 | 531 | public HttpRequest setUrl(String url) { 532 | this.url = url; 533 | return this; 534 | } 535 | 536 | public String getMethod() { 537 | return method; 538 | } 539 | 540 | public HttpRequest setMethod(String method) { 541 | this.method = method; 542 | return this; 543 | } 544 | 545 | public Map getHeaders() { 546 | return headers; 547 | } 548 | 549 | public HttpRequest setHeaders(Map headers) { 550 | this.headers = headers; 551 | return this; 552 | } 553 | 554 | public HttpRequest setContentType(String contentType) { 555 | if (this.headers == null) { 556 | this.headers = new HashMap<>(); 557 | } 558 | this.headers.put(CONTENT_TYPE, contentType); 559 | return this; 560 | } 561 | 562 | public HttpRequest addHeaders(String key, Object value) { 563 | if (headers == null) { 564 | headers = new HashMap<>(); 565 | } 566 | headers.put(key, value != null ? value.toString() : null); 567 | return this; 568 | } 569 | 570 | public Object getBody() { 571 | return body; 572 | } 573 | 574 | public HttpRequest setBody(Object body) { 575 | this.body = body; 576 | return this; 577 | } 578 | 579 | public void setMaxRetryCount(int maxRetryCount) { 580 | this.maxRetryCount = maxRetryCount; 581 | } 582 | 583 | public int getMaxRetryCount() { 584 | return maxRetryCount; 585 | } 586 | 587 | public HttpRequest setMaxSocketTimeout(Integer maxSocketTimeout) { 588 | this.maxSocketTimeout = maxSocketTimeout; 589 | return this; 590 | } 591 | 592 | public Integer getMaxSocketTimeout() { 593 | return maxSocketTimeout; 594 | } 595 | 596 | public Consumer getRequestConfigConsumer() { 597 | return requestConfigConsumer; 598 | } 599 | 600 | public void setRequestConfigConsumer(Consumer requestConfigConsumer) { 601 | this.requestConfigConsumer = requestConfigConsumer; 602 | } 603 | 604 | public Function getResponseHandler() { 605 | return responseHandler; 606 | } 607 | 608 | public HttpRequest setResponseHandler(Function responseHandler) { 609 | this.responseHandler = responseHandler; 610 | return this; 611 | } 612 | } 613 | 614 | public static class HttpResponse implements Serializable { 615 | 616 | private int status; 617 | private long reqTime; 618 | private Object response; 619 | private Map headers; 620 | 621 | public int getStatus() { 622 | return status; 623 | } 624 | 625 | public void setStatus(int status) { 626 | this.status = status; 627 | } 628 | 629 | public long getReqTime() { 630 | return reqTime; 631 | } 632 | 633 | public void setReqTime(long reqTime) { 634 | this.reqTime = reqTime; 635 | } 636 | 637 | public Object getResponse() { 638 | return response; 639 | } 640 | 641 | public String getResponseToString() { 642 | if (response == null) { 643 | return null; 644 | } 645 | return response instanceof String ? (String) response : String.valueOf(response); 646 | } 647 | 648 | public JSONObject getResponseToJson() { 649 | return JSON.parseObject(getResponseToString()); 650 | } 651 | 652 | public void setResponse(Object response) { 653 | this.response = response; 654 | } 655 | 656 | public Map getHeaders() { 657 | return headers; 658 | } 659 | 660 | public void setHeaders(Map headers) { 661 | this.headers = headers; 662 | } 663 | } 664 | 665 | } --------------------------------------------------------------------------------