作者 徐宝林

工具类迁移

... ... @@ -208,7 +208,32 @@
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!--okhttp-->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.9.3</version>
</dependency>
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId>
<version>1.28.5</version>
</dependency>
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-parsers</artifactId>
<version>1.28.5</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext7-core</artifactId>
<version>7.2.5</version>
<type>pom</type>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
... ...
package com.aigeo.article.controller;
import com.aigeo.article.service.SearchService;
import com.aigeo.common.Result;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/search")
@Tag(name = "搜索", description = "搜索功能相关接口")
public class SearchController {
@Autowired
private SearchService searchService;
@PostMapping("/keywords")
public Result<String> searchKeywords(@RequestBody String keywords) {
searchService.search(keywords);
return Result.success("");
}
}
... ...
package com.aigeo.article.service;
import com.aigeo.common.Result;
public interface SearchService {
Result<String> search(String keyword);
}
... ...
package com.aigeo.article.service.impl;
import com.aigeo.article.service.SearchService;
import com.aigeo.common.Result;
import org.springframework.stereotype.Service;
@Service
public class SearchServiceImpl implements SearchService {
@Override
public Result<String> search(String keyword) {
return null;
}
}
... ...
... ... @@ -30,34 +30,34 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
final String requestTokenHeader = request.getHeader("Authorization");
String username = null;
String jwtToken = null;
if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
jwtToken = requestTokenHeader.substring(7);
try {
username = jwtUtil.getUsernameFromToken(jwtToken);
} catch (Exception e) {
logger.error("Unable to get JWT Token", e);
}
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
// 创建一个临时User对象用于验证token
com.aigeo.company.entity.User tempUser = new com.aigeo.company.entity.User();
tempUser.setUsername(username);
if (jwtUtil.validateToken(jwtToken, tempUser)) {
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authToken);
}
}
// final String requestTokenHeader = request.getHeader("Authorization");
//
// String username = null;
// String jwtToken = null;
//
// if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
// jwtToken = requestTokenHeader.substring(7);
// try {
// username = jwtUtil.getUsernameFromToken(jwtToken);
// } catch (Exception e) {
// logger.error("Unable to get JWT Token", e);
// }
// }
//
// if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
// UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
//
// // 创建一个临时User对象用于验证token
// com.aigeo.company.entity.User tempUser = new com.aigeo.company.entity.User();
// tempUser.setUsername(username);
//
// if (jwtUtil.validateToken(jwtToken, tempUser)) {
// UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
// userDetails, null, userDetails.getAuthorities());
// authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
// SecurityContextHolder.getContext().setAuthentication(authToken);
// }
// }
chain.doFilter(request, response);
}
}
\ No newline at end of file
... ...
package com.aigeo.entity;
import com.aigeo.util.article.PlatformTypeEnum;
import lombok.Data;
@Data
public class CreateArticleDTO {
private String blogId;
private String title;
private Author author;
private String handle;
private String body;
private Integer companyId;
private String summary;
private Boolean isPublished;
private String publishDate;
private String[] tags;
private String imageAltText;
private String imageUrl;
private PlatformTypeEnum platform;
@Data
public static class Author {
private String name;
}
}
... ...
package com.aigeo.entity;
import lombok.Data;
import java.util.List;
@Data
public class DifyDatasetDocuments {
private Integer code;
private List<Document> data;
private Integer total;
private Integer page;
private Integer limit;
private Boolean has_more;
}
... ...
package com.aigeo.entity;
import lombok.Data;
@Data
public class DifyRequestDTO {
private Object inputs;
private String query;
private String response_mode;
private String conversation_id;
private String user;
private FileInfos[] files;
@Data
public static class FileInfos{
private String type;
private String transfer_method;
private String url;
}
}
... ...
package com.aigeo.entity;
import lombok.Data;
@Data
public class DifyResponse {
/**
* 任务 ID,用于请求跟踪和下方的停止响应接口
*/
private String task_id;
/**
* 消息唯一 ID
*/
private String message_id;
/**
* 返回文本块内容
*/
private String answer;
/**
* 返回文本块事件
*/
private String event;
/**
* 会话 ID
*/
private String conversation_id;
/**
* 创建时间戳
*/
private Long created_at;
/**
* 每一轮Agent迭代都会有一个唯一的id
*/
private String id;
/**
* agent_thought在消息中的位置
*/
private Integer position;
/**
* agent的思考内容
*/
private String thought;
/**
* 工具调用的返回结果
*/
private String observation;
/**
* 使用的工具列表,以 ; 分割多个工具
*/
private String tool;
private Object tool_labels;
/**
* 工具的输入,JSON格式的字符串
*/
private String tool_input;
/**
* 错误消息
*/
private String message;
/**
* 当前 agent_thought 关联的文件ID
*/
private DifyRequestDTO.FileInfos message_files;
private Integer code;
}
... ...
package com.aigeo.entity;
import lombok.Data;
import java.util.List;
@Data
public class DifyUploadFileToDatasetDTO {
private String indexing_technique;
private PrecessRule process_rule;
@Data
public static class PrecessRule {
private String mode;
private Rules rules;
@Data
public static class Rules {
private List<PreProcessingRules> pre_processing_rules;
private Segmentation segmentation;
@Data
public static class Segmentation {
private String separator;
private Integer max_tokens;
}
@Data
public static class PreProcessingRules {
private String id;
private String enabled;
}
}
}
}
... ...
package com.aigeo.entity;
import lombok.Data;
@Data
public class Document {
private String id;
private String position;
private String data_source_type;
private String data_source_info;
private String dataset_process_rule_id;
private String name;
private String created_from;
private String created_by;
private String created_at;
private String tokens;
private String indexing_status;
private String error;
private String enabled;
private String disabled_at;
private String disabled_by;
private String archived;
private String display_status;
private String word_count;
private String hit_count;
private String doc_form;
}
... ...
package com.aigeo.entity;
import lombok.Data;
@Data
public class DocumentUploadRes {
private Document document;
private String batch;
private Integer code;
}
... ...
package com.aigeo.entity;
import com.aigeo.util.article.PlatformTypeEnum;
import lombok.Data;
@Data
public class UpdateArticleDTO {
private String id;
private String title;
private String handle;
private String body;
private String summary;
private String[] tags;
private String imageAltText;
private String imageUrl;
private Integer companyId;
private PlatformTypeEnum platform;
}
... ...
package com.aigeo.socket;
import com.alibaba.fastjson2.JSONException;
import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.websocket.*;
import jakarta.websocket.server.ServerEndpoint;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
@ServerEndpoint("/ws/chat/{userId}")
@Component
public class WebSocketAiServer {
// public static AiSerivce aiSerivce;
// TokenInfo tokenInfo = TokenInfo.getIntance();
private static final ConcurrentHashMap<String, Session> sessionMap = new ConcurrentHashMap<>();
@OnOpen
public void onOpen(Session session) {
sessionMap.put(session.getId(),session);
System.out.println("New connection: " + session.getId());
}
@OnClose
public void onClose(Session session) {
sessionMap.remove(session.getId());
System.out.println("Connection closed: " + session.getId());
}
@OnMessage
public void onMessage(String message, Session session) {
// SocketDTO socketDTO = JSONObject.parseObject(message, SocketDTO.class);
// socketDTO.setId(session.getId());
// // 解析消息
// try {
// // 调用 reply 方法处理消息
// aiSerivce.chat(socketDTO);
// } catch (JSONException e) {
// e.printStackTrace();
// // 发送错误信息给客户端
// DifyResponse difyResponse = new DifyResponse();
// difyResponse.setCode(500);
// sendMessage(session.getId(), difyResponse);
// } catch (Exception e) {
// e.printStackTrace();
// // 发送错误信息给客户端
// DifyResponse difyResponse = new DifyResponse();
// difyResponse.setCode(500);
// sendMessage(session.getId(), difyResponse);
// }
}
@OnError
public void onError(Session session, Throwable throwable) {
System.out.println("Error occurred: " + throwable.getMessage());
}
public static void sendMessage(String sessionId, Object message) {
Session session = sessionMap.get(sessionId);
if (session != null && session.isOpen()) {
try {
ObjectMapper objectMapper = new ObjectMapper();
String jsonMessage;
try {
jsonMessage = objectMapper.writeValueAsString(message);
} catch (Exception e) {
e.printStackTrace();
jsonMessage = "Error: Failed to serialize message";
}
session.getBasicRemote().sendText(jsonMessage);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void sendMessageToAll(Object message) {
ObjectMapper objectMapper = new ObjectMapper();
String jsonMessage;
try {
jsonMessage = objectMapper.writeValueAsString(message);
} catch (Exception e) {
e.printStackTrace();
jsonMessage = "Error: Failed to serialize message";
}
// 遍历 sessionMap 的所有 Session
for (Session session : sessionMap.values()) {
if (session.isOpen()) {
try {
session.getBasicRemote().sendText(jsonMessage);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
... ...
package com.aigeo.util;
import com.aigeo.entity.*;
import com.aigeo.socket.WebSocketAiServer;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import okhttp3.*;
import okio.BufferedSource;
import org.apache.tika.exception.TikaException;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
/**
* <b>Dify AI工具类.</b>
* <p>
* 文件详情: 如需修改请联系开发人员<br>
* 版权所有: 深圳市科飞时速网络技术有限公司(0755-88843705)<br>
* 技术支持: info@21gmail.com<br>
* 开始时间: 2025/08/19 16:36<br>
* 最后修改: 2025/08/19 16:36<br>
*
* @author : 温志锋
* @version : 3.0
*/
public class DifyAiUtil {
//测试知识库ID:8b3c4cdd-01a3-453b-8e12-bc7c0d5268db
private static final String DIFY_BASE_URL="http://193.112.177.8:8088/v1";
private static final String API_KEY="app-sxppRrqW8OMd6Ak07iprjn2t";
private static final String DATASET_KEY="dataset-2nhuEkzhNshtvZ6L6Ut3G5hC";
private static final String DIFY_CHAT_URL="/chat-messages";
private static final String DATASET_ENDPOINT="/datasets/";
private static final String DATASET_DOCUMENT_ENDPOINT="/document/create-by-text";
private static final String DATASET_UPLOADFILE_ENDPOINT="/document/create-by-file";
private static final MediaType JSON_TYPE = MediaType.get("application/json; charset=utf-8");
private static final OkHttpClient client = new OkHttpClient();
/**
* 回复
* @param message 用户消息
* @param sessionId 会话ID
*/
public static void reply(String message,String sessionId){
DifyRequestDTO difyRequestDTO = JSONObject.parseObject(message, DifyRequestDTO.class);
difyRequestDTO.setInputs(new Object());
difyRequestDTO.setUser("anhssd");
difyRequestDTO.setResponse_mode("streaming");
String jsonBody = JSON.toJSONString(difyRequestDTO);
// 创建请求体
RequestBody requestBody = RequestBody.create(
jsonBody,
JSON_TYPE
);
// 创建请求
Request request = new Request.Builder()
.url(DIFY_BASE_URL+DIFY_CHAT_URL)
.addHeader("Authorization", "Bearer " + API_KEY)
.addHeader("Content-Type", "application/json")
.post(requestBody)
.build();
// 发送请求并处理流式响应
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) {
System.err.println("请求失败: " + response.code() + " - " + response.body().string());
return;
}
processStream(response,sessionId);
}
});
}
/**
* 创建知识库
* @param datasetName 知识库名称
* @param description 知识库描述
*/
public static void createDataset(String datasetName, String description) {
HashMap<String, Object> map = new HashMap<>();
map.put("name", datasetName);
map.put("description", description);
map.put("permission", "all_team_members");
String jsonBody = JSON.toJSONString(map);
RequestBody requestBody = RequestBody.create(jsonBody, JSON_TYPE);
// 创建请求
Request request = new Request.Builder()
.url(DIFY_BASE_URL + DATASET_ENDPOINT)
.addHeader("Authorization", "Bearer " + DATASET_KEY)
.addHeader("Content-Type", "application/json")
.post(requestBody)
.build();
// 发送请求
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) {
System.err.println("请求失败: " + response.code() + " - " + response.body().string());
return;
}
System.out.println("知识库创建成功: " + response.body().string());
}
});
}
/**
* 获取知识库列表
*/
public static void getDatasetList() {
// 创建请求
Request request = new Request.Builder()
.url(DIFY_BASE_URL + DATASET_ENDPOINT)
.addHeader("Authorization", "Bearer " + DATASET_KEY)
.build();
try {
// 发送请求并获取响应
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) {
System.err.println("请求失败: " + response.code() + " - " + response.body().string());
return;
}
if (response.body() != null) {
System.out.println("数据集列表: " + response.body().string());
}
} catch (IOException e) {
System.err.println("获取数据集列表失败: " + e.getMessage());
e.printStackTrace();
}
}
/**
* 上传文件到知识库
* @param datasetId 知识库ID
* @param file 文件
* @param fileName 文件名
* @throws IOException IO异常
*/
public static DocumentUploadRes uploadFileToDataset(String datasetId, MultipartFile file, String fileName) throws IOException, TikaException {
// 构建URL
String uploadUrl = DIFY_BASE_URL + DATASET_ENDPOINT + datasetId + DATASET_UPLOADFILE_ENDPOINT;
DifyUploadFileToDatasetDTO datasetDTO = new DifyUploadFileToDatasetDTO();
datasetDTO.setIndexing_technique("high_quality");
DifyUploadFileToDatasetDTO.PrecessRule precessRule = new DifyUploadFileToDatasetDTO.PrecessRule();
precessRule.setMode("custom");
DifyUploadFileToDatasetDTO.PrecessRule.Rules rules = new DifyUploadFileToDatasetDTO.PrecessRule.Rules();
DifyUploadFileToDatasetDTO.PrecessRule.Rules.Segmentation segmentation = new DifyUploadFileToDatasetDTO.PrecessRule.Rules.Segmentation();
segmentation.setSeparator("###");
segmentation.setMax_tokens(500);
DifyUploadFileToDatasetDTO.PrecessRule.Rules.PreProcessingRules processingRules = new DifyUploadFileToDatasetDTO.PrecessRule.Rules.PreProcessingRules();
processingRules.setId("remove_extra_spaces");
processingRules.setEnabled("true");
DifyUploadFileToDatasetDTO.PrecessRule.Rules.PreProcessingRules processingRules1 = new DifyUploadFileToDatasetDTO.PrecessRule.Rules.PreProcessingRules();
processingRules1.setId("remove_urls_emails");
processingRules1.setEnabled("true");
ArrayList<DifyUploadFileToDatasetDTO.PrecessRule.Rules.PreProcessingRules> list = new ArrayList<>();
list.add(processingRules);
list.add(processingRules1);
rules.setPre_processing_rules(list);
rules.setSegmentation(segmentation);
precessRule.setRules(rules);
datasetDTO.setProcess_rule(precessRule);
String jsonString = JSONObject.toJSONString(datasetDTO);
//System.out.println("Request JSON: " + jsonString);
// 关键修改:使用正确的媒体类型 application/json
RequestBody dataBody = RequestBody.create(
jsonString,
MediaType.parse("text/plain")
);
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
// 修改点:使用 application/json 类型传递JSON数据
.addFormDataPart("data", null, dataBody)
.addFormDataPart("file", fileName,
RequestBody.create(file.getBytes(), MediaType.parse("application/octet-stream")))
.build();
// 创建请求
Request request = new Request.Builder()
.url(uploadUrl)
.addHeader("Authorization", "Bearer " + DATASET_KEY)
.post(requestBody)
.build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) {
String errorBody = response.body() != null ? response.body().string() : "null";
System.err.println("上传文件请求失败: " + response.code() + " - " + errorBody);
DocumentUploadRes documentUploadRes = new DocumentUploadRes();
documentUploadRes.setCode(response.code());
return documentUploadRes;
}
if (response.body() != null) {
String responseBody = response.body().string();
return JSONObject.parseObject(responseBody, DocumentUploadRes.class); // 直接返回结果
} else {
DocumentUploadRes documentUploadRes = new DocumentUploadRes();
documentUploadRes.setCode(400);
return documentUploadRes;
}
}
}
/**
* 上传知识库内容并创建文档至知识库
* @param datasetId 知识库ID
* @param documentName 文档名称
* @param text 文本内容
*/
public static void createDocumentByText(String datasetId, String documentName, String text) throws IOException {
// 构建URL
String url = DIFY_BASE_URL + DATASET_ENDPOINT + datasetId + DATASET_DOCUMENT_ENDPOINT;
// 构建请求数据
JSONObject requestData = new JSONObject();
requestData.put("name", documentName);
requestData.put("text", text);
requestData.put("indexing_technique", "high_quality");
// 构建处理规则
JSONObject processRule = new JSONObject();
processRule.put("mode", "automatic");
requestData.put("process_rule", processRule);
String jsonBody = requestData.toJSONString();
// 创建请求体
RequestBody requestBody = RequestBody.create(jsonBody, JSON_TYPE);
// 创建请求
Request request = new Request.Builder()
.url(url)
.addHeader("Authorization", "Bearer " + DATASET_KEY)
.addHeader("Content-Type", "application/json")
.post(requestBody)
.build();
// 发送请求
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
System.err.println("创建文档失败: " + e.getMessage());
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) {
String errorBody = response.body() != null ? response.body().string() : "null";
System.err.println("创建文档请求失败: " + response.code() + " - " + errorBody);
return;
}
if (response.body() != null) {
System.out.println("文档创建成功: " + response.body().string());
}
}
});
}
/**
* 获取指定数据集中特定文档的详细信息
* @param datasetId 数据集ID
* @param documentId 文档ID
* @throws IOException IO异常
*/
public static void getDocumentById(String datasetId, String documentId) throws IOException {
// 构建URL
String url = DIFY_BASE_URL + DATASET_ENDPOINT + datasetId + "/documents/" + documentId;
// 创建请求
Request request = new Request.Builder()
.url(url)
.addHeader("Authorization", "Bearer " + DATASET_KEY)
.get() // 明确指定GET方法
.build();
// 发送请求
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
System.err.println("获取文档失败: " + e.getMessage());
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) {
String errorBody = response.body() != null ? response.body().string() : "null";
System.err.println("获取文档请求失败: " + response.code() + " - " + errorBody);
return;
}
if (response.body() != null) {
System.out.println("文档详情: " + response.body().string());
}
}
});
}
/**
* 获取指定知识库中的文档列表
* @param datasetId 数据集ID
* @param page 页码(从1开始)
* @param limit 每页返回条数
* @param keyword 搜索关键词
* @return 响应内容
* @throws IOException IO异常
*/
public static DifyDatasetDocuments getDatasetDocuments(String datasetId, Integer page, Integer limit, String keyword) throws IOException {
// 构建基础URL
String url = DIFY_BASE_URL + DATASET_ENDPOINT + datasetId + "/documents";
// 构建查询参数
HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
// 添加可选参数
if (page != null && page > 0) {
urlBuilder.addQueryParameter("page", String.valueOf(page));
}
if (limit != null && limit > 0) {
urlBuilder.addQueryParameter("limit", String.valueOf(limit));
}
if (keyword != null && !keyword.trim().isEmpty()) {
urlBuilder.addQueryParameter("keyword", keyword);
}
// 构建最终URL
String finalUrl = urlBuilder.build().toString();
// 创建请求
Request request = new Request.Builder()
.url(finalUrl)
.addHeader("Authorization", "Bearer " + DATASET_KEY)
.build();
// 发送请求并处理响应
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) {
DifyDatasetDocuments documents = new DifyDatasetDocuments();
documents.setCode(500);
return documents;
}
if (response.body() != null) {
DifyDatasetDocuments documents = JSONObject.parseObject(response.body().string(), DifyDatasetDocuments.class);
documents.setCode(200);
return documents;
} else {
DifyDatasetDocuments documents = new DifyDatasetDocuments();
documents.setCode(500);
return documents;
}
} catch (IOException e) {
System.err.println("获取文档列表失败: " + e.getMessage());
throw e;
}
}
/**
* 同步方式删除指定数据集中的特定文档
* @param datasetId 数据集ID
* @param documentId 文档ID
* @return 删除操作结果
* @throws IOException IO异常
*/
public static boolean deleteDocumentSync(String datasetId, String documentId) throws IOException {
// 构建URL
String url = DIFY_BASE_URL + DATASET_ENDPOINT + datasetId + "/documents/" + documentId;
// 创建DELETE请求
Request request = new Request.Builder()
.url(url)
.addHeader("Authorization", "Bearer " + DATASET_KEY)
.delete()
.build();
// 发送请求并处理响应
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) {
String errorBody = response.body() != null ? response.body().string() : "null";
System.err.println("删除文档请求失败: " + response.code() + " - " + errorBody);
return false;
}
System.out.println("文档删除成功: " + response.code());
return true;
} catch (IOException e) {
System.err.println("删除文档失败: " + e.getMessage());
throw e;
}
}
private static void processStream(Response response,String sessionId) throws IOException {
try (BufferedSource source = response.body().source()) {
StringBuilder eventBuffer = new StringBuilder();
while (!source.exhausted()) {
String line = source.readUtf8Line();
if (line == null) break;
if (line.startsWith("data:")) {
eventBuffer.setLength(0);
eventBuffer.append(line.substring(5).trim());
} else if (line.isEmpty() && eventBuffer.length() > 0) {
handleEvent(eventBuffer.toString(),sessionId);
eventBuffer.setLength(0);
}
}
}
}
private static void handleEvent(String eventData,String sessionId) {
try {
DifyResponse event = JSON.parseObject(eventData, DifyResponse.class);
switch (event.getEvent()) {
case "agent_thought":
//System.out.println("[思考] " + event.getThought());
break;
case "agent_message":
System.out.print(event.getAnswer());
event.setCode(200);
WebSocketAiServer.sendMessage(sessionId,event);
break;
case "message_end":
event.setCode(203);
System.out.println("\n[对话结束]");
WebSocketAiServer.sendMessage(sessionId,event);
break;
case "error":
event.setCode(500);
System.err.println("[错误] " + event.getMessage());
WebSocketAiServer.sendMessage(sessionId,event);
break;
default:
System.out.println("[事件] " + event.getEvent());
}
} catch (Exception e) {
System.err.println("解析错误: " + eventData);
e.printStackTrace();
}
}
}
... ...
package com.aigeo.util;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTInd;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSpacing;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STLineSpacingRule;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.math.BigInteger;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class DocumentCreator {
public static String create(String content) {
try {
//生成一个随机文件名称
long l = System.currentTimeMillis();
String fileName = "D:/LsYwxProject/YwxErpApi/yiwaixiaoerp/YwxErp/upload/aidocx/" + l + ".docx";
createFormattedDocx(content, fileName);
System.out.println("文档创建成功:自然的诗篇.docx");
return fileName;
} catch (Exception e) {
System.err.println("创建文档时出错: " + e.getMessage());
e.printStackTrace();
return null;
}
}
public static void createFormattedDocx(String content, String fileName) throws Exception {
// 创建新文档
XWPFDocument document = new XWPFDocument();
// 按换行符分割内容
String[] parts = content.split("\n\n");
if (parts.length == 0) return;
// 处理标题(第一部分)
String title = parts[0];
// 移除标题前的Markdown标记
if (title.startsWith("# ")) {
title = title.substring(2);
}
createHeading(document, title, 1);
// 处理其余部分
for (int i = 1; i < parts.length; i++) {
String part = parts[i];
// 检查是否是图片标记
if (part.startsWith("![")) {
String imageUrl = extractImageUrl(part);
if (imageUrl != null) {
// 下载并插入图片
insertImage(document, imageUrl);
}
} else {
// 处理普通文本段落
createFormattedParagraph(document, part);
}
}
// 保存文件
try (FileOutputStream out = new FileOutputStream(fileName)) {
document.write(out);
}
}
// 从Markdown图片标记中提取URL
private static String extractImageUrl(String markdown) {
// 正则表达式匹配Markdown图片语法
Pattern pattern = Pattern.compile("!\\[.*?\\]\\((.*?)\\)");
Matcher matcher = pattern.matcher(markdown);
if (matcher.find()) {
return matcher.group(1);
}
return null;
}
// 下载并插入图片
private static void insertImage(XWPFDocument doc, String imageUrl) throws Exception {
try {
// 创建新段落用于放置图片
XWPFParagraph para = doc.createParagraph();
para.setAlignment(ParagraphAlignment.CENTER);
XWPFRun run = para.createRun();
// 下载图片
URL url = new URL(imageUrl);
try (InputStream is = url.openStream()) {
// 插入图片(宽度15厘米,高度按比例自动计算)
run.addPicture(is,
XWPFDocument.PICTURE_TYPE_JPEG,
"image.jpg",
Units.toEMU(400), // 宽度15厘米
Units.toEMU(200)); // 高度10厘米(实际会按比例调整)
}
// 添加图片标题(可选)
//XWPFParagraph caption = doc.createParagraph();
//caption.setAlignment(ParagraphAlignment.CENTER);
//XWPFRun captionRun = caption.createRun();
//captionRun.setText("自然的画卷");
//captionRun.setFontSize(10);
//captionRun.setFontFamily("宋体");
//captionRun.setItalic(true);
} catch (Exception e) {
System.err.println("无法插入图片: " + e.getMessage());
// 创建错误信息段落
XWPFParagraph errorPara = doc.createParagraph();
XWPFRun errorRun = errorPara.createRun();
errorRun.setText("[图片加载失败: " + imageUrl + "]");
errorRun.setColor("FF0000");
}
}
// 创建标题方法
private static void createHeading(XWPFDocument doc, String text, int level) {
XWPFParagraph heading = doc.createParagraph();
heading.setStyle("Heading" + level);
XWPFRun run = heading.createRun();
run.setText(text);
run.setBold(true);
run.setFontSize(18);
run.setFontFamily("楷体");
// 设置标题居中
heading.setAlignment(ParagraphAlignment.CENTER);
// 设置段后间距
CTPPr ppr = heading.getCTP().getPPr();
if (ppr == null) ppr = heading.getCTP().addNewPPr();
CTSpacing spacing = ppr.isSetSpacing() ? ppr.getSpacing() : ppr.addNewSpacing();
spacing.setAfter(BigInteger.valueOf(400)); // 20磅间距
}
// 创建格式化的正文段落
private static void createFormattedParagraph(XWPFDocument doc, String text) {
XWPFParagraph para = doc.createParagraph();
XWPFRun run = para.createRun();
run.setText(text);
run.setFontSize(12);
run.setFontFamily("宋体");
// 设置首行缩进和行距
CTPPr ppr = para.getCTP().getPPr();
if (ppr == null) ppr = para.getCTP().addNewPPr();
// 首行缩进2字符 (1字符=400)
CTInd ind = ppr.isSetInd() ? ppr.getInd() : ppr.addNewInd();
ind.setFirstLine(BigInteger.valueOf(800));
// 设置行距 (1.5倍行距)
CTSpacing spacing = ppr.isSetSpacing() ? ppr.getSpacing() : ppr.addNewSpacing();
spacing.setLineRule(STLineSpacingRule.AUTO);
spacing.setLine(BigInteger.valueOf(360)); // 1.5倍行距 = 1.5*240=360
// 设置段后间距
spacing.setAfter(BigInteger.valueOf(100)); // 5磅段落间距
}
// 下载并插入图片
//private static void insertImage(XWPFDocument doc, String imageUrl) throws Exception {
// try {
// // 创建新段落用于放置图片
// XWPFParagraph para = doc.createParagraph();
// para.setAlignment(ParagraphAlignment.CENTER);
// XWPFRun run = para.createRun();
//
// // 下载图片并获取原始尺寸
// URL url = new URL(imageUrl);
// try (InputStream is = url.openStream()) {
// // 将输入流转换为字节数组,以便多次使用
// byte[] imageBytes = IOUtils.toByteArray(is);
// ByteArrayInputStream bis = new ByteArrayInputStream(imageBytes);
//
// // 获取图片尺寸
// BufferedImage bufferedImage = ImageIO.read(bis);
// if (bufferedImage != null) {
// int originalWidth = bufferedImage.getWidth();
// int originalHeight = bufferedImage.getHeight();
//
// // 重置bis以供图片插入使用
// bis.reset();
// bis = new ByteArrayInputStream(imageBytes);
//
// // 插入图片(使用原始宽高,转换为EMU单位)
// run.addPicture(new ByteArrayInputStream(imageBytes),
// XWPFDocument.PICTURE_TYPE_JPEG,
// "image.jpg",
// Units.toEMU(400), // 宽度15厘米
// Units.toEMU(200)); // 高度10厘米
// } else {
// // 如果无法获取尺寸,使用默认尺寸
// run.addPicture(new ByteArrayInputStream(imageBytes),
// XWPFDocument.PICTURE_TYPE_JPEG,
// "image.jpg",
// Units.toEMU(400), // 宽度15厘米
// Units.toEMU(200)); // 高度10厘米
// }
// }
//
// } catch (Exception e) {
// System.err.println("无法插入图片: " + e.getMessage());
// // 创建错误信息段落
// XWPFParagraph errorPara = doc.createParagraph();
// XWPFRun errorRun = errorPara.createRun();
// errorRun.setText("[图片加载失败: " + imageUrl + "]");
// errorRun.setColor("FF0000");
// }
//}
}
\ No newline at end of file
... ...
package com.aigeo.util;
import org.apache.tika.Tika;
import org.apache.tika.exception.TikaException;
import java.io.IOException;
import java.io.InputStream;
import java.util.regex.Pattern;
public class DocumentParse {
private final Tika tika;
// 定义有意义字符的正则表达式
private static final Pattern MEANINGFUL_CHAR_PATTERN = Pattern.compile("[\\s\\u4e00-\\u9fa5a-zA-Z0-9¥$€£¢₹₽₩₪₨₦₡₫₴₵₸₺₼₾₿.,;:'\"!?()-]*");
// 字符限制
private static final int CHINESE_CHAR_LIMIT = 30000;
private static final int ENGLISH_CHAR_LIMIT = 100000;
// 中文比例阈值
private static final double CHINESE_THRESHOLD = 0.4;
public DocumentParse() {
this.tika = new Tika();
}
// public String parse(InputStream inputStream) throws TikaException, IOException, DocumentParseException {
// // 使用Tika解析文档内容
// String rawContent = this.tika.parseToString(inputStream);
//
// // 过滤特殊字符,只保留有意义的字符
// String filteredContent = filterMeaningfulCharacters(rawContent);
//
// // 检查字符数是否超过限制
// validateContentLength(filteredContent);
//
// return filteredContent;
// }
/**
* 过滤特殊字符,只保留有意义的字符
* @param content 原始内容
* @return 过滤后的内容
*/
private String filterMeaningfulCharacters(String content) {
if (content == null || content.isEmpty()) {
return "";
}
// 使用正则表达式匹配有意义的字符
StringBuilder result = new StringBuilder();
java.util.regex.Matcher matcher = MEANINGFUL_CHAR_PATTERN.matcher(content);
while (matcher.find()) {
result.append(matcher.group());
}
return result.toString();
}
/**
* 验证内容长度是否超过限制
* @param content 过滤后的内容
* @throws DocumentParseException 当内容超过限制时抛出异常
*/
// private void validateContentLength(String content) throws DocumentParseException {
// if (content == null || content.isEmpty()) {
// return;
// }
//
// // 计算中文字符比例
// double chineseRatio = calculateChineseRatio(content);
//
// if (chineseRatio > CHINESE_THRESHOLD) {
// // 中文文档处理
// if (content.length() > CHINESE_CHAR_LIMIT) {
// throw new DocumentParseException("您的文档字符超过限制,请缩减文档再次上传");
// }
// } else {
// // 英文文档处理
// if (content.length() > ENGLISH_CHAR_LIMIT) {
// throw new DocumentParseException("您的文档字符超过限制,请缩减文档再次上传");
// }
// }
// }
/**
* 计算中文字符在总字符中的比例
* @param content 文档内容
* @return 中文字符比例
*/
private double calculateChineseRatio(String content) {
if (content == null || content.isEmpty()) {
return 0.0;
}
int totalChars = content.length();
int chineseChars = 0;
for (char c : content.toCharArray()) {
// 判断是否为中文字符(基本汉字范围)
if (c >= 0x4e00 && c <= 0x9fa5) {
chineseChars++;
}
}
return (double) chineseChars / totalChars;
}
}
... ...
package com.aigeo.util;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
public class FtpUtil {
// FTP服务器配置参数
private static final String SERVER = "193.112.177.8"; // FTP服务器地址
private static final int PORT = 21; // FTP服务器端口,默认21
private static final String USERNAME = "user1"; // FTP用户名
private static final String PASSWORD = "sz123321"; // FTP密码
// 本地文件路径及远程存储路径
private static final String LOCAL_FILE_PATH = "C:\\Users\\Lenovo\\Desktop\\sql.txt";
private static final String REMOTE_FILE_PATH = "/1/sql.txt";
// public static void upload(FtpDTO ftpDTO) {
// FTPClient ftpClient = new FTPClient();
// try {
// // 1. 连接FTP服务器
// System.out.println("正在连接到FTP服务器 " + ftpDTO.getFtpHost() + "...");
// ftpClient.connect(ftpDTO.getFtpHost(), PORT);
// int replyCode = ftpClient.getReplyCode();
// if (!FTPReply.isPositiveCompletion(replyCode)) {
// System.err.println("FTP服务器拒绝连接,响应代码:" + replyCode);
// return;
// }
// System.out.println("连接成功,准备登录...");
//
// // 2. 登录FTP服务器
// boolean success = ftpClient.login(ftpDTO.getUser(), ftpDTO.getPassword());
// if (!success) {
// System.err.println("FTP登录失败,请检查用户名和密码。");
// return;
// }
// System.out.println("登录成功!");
//
// // 3. 设置FTP客户端工作模式
// // 进入被动模式,以适应防火墙/NAT环境
// ftpClient.enterLocalPassiveMode();
// // 设置文件传输类型为二进制文件,确保上传文件内容正确
// ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
//
// // 4. 上传文件
// System.out.println("开始上传文件:" + ftpDTO.getSourcePath());
// // 使用try-with-resources确保InputStream自动关闭
// try (InputStream inputStream = new FileInputStream(ftpDTO.getSourcePath())) {
// boolean uploadSuccess = ftpClient.storeFile(ftpDTO.getTargetPath(), inputStream);
// if (uploadSuccess) {
// System.out.println("文件上传成功!保存到:" + ftpDTO.getTargetPath());
// } else {
// System.err.println("文件上传失败,请检查文件路径和网络连接。");
// }
// }
//
// // 5. 登出并断开FTP连接
// ftpClient.logout();
// System.out.println("已登出FTP服务器。");
//
// } catch (IOException ex) {
// System.err.println("发生异常:" + ex.getMessage());
// ex.printStackTrace();
// } finally {
// // 6. 确保FTP连接被断开
// if (ftpClient.isConnected()) {
// try {
// ftpClient.disconnect();
// System.out.println("FTP连接已关闭。");
// } catch (IOException ex) {
// System.err.println("关闭FTP连接时发生异常:" + ex.getMessage());
// ex.printStackTrace();
// }
// }
// }
// }
// public static List<String> listFileNames(ApiConfig apiConfig, String directoryPath) {
// FTPClient ftpClient = new FTPClient();
// List<String> fileNames = new ArrayList<>();
//
// try {
// // 连接并登录FTP服务器
// ftpClient.connect(apiConfig.getApiUrl(), PORT);
// int replyCode = ftpClient.getReplyCode();
// if (!FTPReply.isPositiveCompletion(replyCode)) {
// return null;
// }
//
// boolean success = ftpClient.login(apiConfig.getApiId(), apiConfig.getApiKey());
// if (!success) {
// return null;
// }
//
// // 进入被动模式
// ftpClient.enterLocalPassiveMode();
//
// // 获取文件列表
// FTPFile[] files;
// if (directoryPath != null && !directoryPath.isEmpty()) {
// files = ftpClient.listFiles(directoryPath);
// } else {
// files = ftpClient.listFiles();
// }
//
// // 提取文件名称
// for (FTPFile file : files) {
// fileNames.add(file.getName());
// }
//
// return fileNames;
//
// } catch (IOException ex) {
// return null;
// } finally {
// // 确保连接被正确关闭
// if (ftpClient.isConnected()) {
// try {
// ftpClient.logout();
// ftpClient.disconnect();
// } catch (IOException ex) {
// System.err.println("关闭FTP连接时发生异常:" + ex.getMessage());
// ex.printStackTrace();
// }
// }
// }
// }
/**
* 获取FTP服务器当前目录下的文件列表
* @return FTPFile数组,包含目录中的文件和子目录信息
*/
// public static FTPFile[] getlistFiles() {
// return listFiles(null);
// }
/**
* 打印指定目录下的文件列表信息
* @param directoryPath 目录路径
*/
// public static void printFileList(String directoryPath) {
// FTPFile[] files = listFiles(directoryPath);
//
// if (files.length == 0) {
// System.out.println("目录为空或获取失败");
// return;
// }
//
// System.out.println("目录 " + (directoryPath != null ? directoryPath : "当前目录") + " 中的文件列表:");
// for (FTPFile file : files) {
// String fileType = file.isDirectory() ? "目录" : "文件";
// System.out.printf("%-10s %-20s %10d bytes%n",
// fileType, file.getName(), file.getSize());
// }
// }
// public static byte[] downloadFile(ApiConfig apiConfig, String targetPath) {
// FTPClient ftpClient = new FTPClient();
// try {
// // 1. 连接FTP服务器
// System.out.println("正在连接到FTP服务器 " + apiConfig.getApiUrl() + "...");
// ftpClient.connect(apiConfig.getApiUrl(), PORT);
// int replyCode = ftpClient.getReplyCode();
// if (!FTPReply.isPositiveCompletion(replyCode)) {
// System.err.println("FTP服务器拒绝连接,响应代码:" + replyCode);
// return null;
// }
// System.out.println("连接成功,准备登录...");
//
// // 2. 登录FTP服务器
// boolean success = ftpClient.login(apiConfig.getApiId(), apiConfig.getApiKey());
// if (!success) {
// System.err.println("FTP登录失败,请检查用户名和密码。");
// return null;
// }
// System.out.println("登录成功!");
//
// // 3. 设置FTP客户端工作模式
// // 进入被动模式,以适应防火墙/NAT环境
// ftpClient.enterLocalPassiveMode();
// // 设置文件传输类型为二进制文件,确保下载文件内容正确
// ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
//
// // 4. 下载文件
// System.out.println("开始下载文件:" + targetPath);
// ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
// boolean downloadSuccess = ftpClient.retrieveFile(targetPath, outputStream);
// if (downloadSuccess) {
// System.out.println("文件下载成功!文件大小:" + outputStream.size() + " 字节");
// return outputStream.toByteArray();
// } else {
// System.err.println("文件下载失败,请检查文件路径和网络连接。");
// return null;
// }
//
// } catch (IOException ex) {
// System.err.println("下载文件时发生异常:" + ex.getMessage());
// ex.printStackTrace();
// return null;
// } finally {
// // 5. 确保FTP连接被正确关闭
// if (ftpClient.isConnected()) {
// try {
// ftpClient.logout();
// ftpClient.disconnect();
// System.out.println("FTP连接已关闭。");
// } catch (IOException ex) {
// System.err.println("关闭FTP连接时发生异常:" + ex.getMessage());
// ex.printStackTrace();
// }
// }
// }
// }
}
... ...
package com.aigeo.util;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;
public class GoogleUtil {
private static final String API_KEY = "";
public static void search(){
OkHttpClient client = new OkHttpClient();
HttpUrl.Builder urlBuilder = HttpUrl.get("https://www.searchapi.io/api/v1/search").newBuilder();
urlBuilder.addQueryParameter("engine", "google");
urlBuilder.addQueryParameter("q", "chatgpt");
urlBuilder.addQueryParameter("api_key", API_KEY);
Request request = new Request.Builder()
.url(urlBuilder.build())
.build();
Response response = null;
try {
response = client.newCall(request).execute();
System.out.println(response.body().string());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
... ...
package com.aigeo.util;
import okhttp3.*;
import org.apache.commons.codec.digest.DigestUtils;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class PbootUtil {
private static final String BASE_URL = "http://web.szcxybz.com/admin.php/content/";
private static final String API_APP_ID = "admin";
private static final String API_SECRET_KEY = "123456";
private static final OkHttpClient httpClient = new OkHttpClient();
private static final String MEDIA_TYPE_JSON = "application/json; charset=utf-8";
private static final String MEDIA_TYPE_FORM = "application/x-www-form-urlencoded; charset=utf-8";
/**
* 通用API请求方法
* @param url 请求路径
* @param method 请求方法 (GET/POST)
* @param params 请求参数
* @return 响应结果
*/
public static String apiRequest(String url, String method, Map<String, Object> params) throws IOException {
// 获取当前时间戳
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
// 生成签名
String signature = generateSignature(API_APP_ID, API_SECRET_KEY, timestamp);
// 构造请求参数
Map<String, Object> requestParams = new HashMap<>();
requestParams.put("appid", API_APP_ID);
requestParams.put("timestamp", timestamp);
requestParams.put("signature", signature);
// 添加传入的参数
if (params != null) {
requestParams.putAll(params);
}
if ("POST".equalsIgnoreCase(method)) {
return postRequest(url, requestParams);
} else {
return getRequest(url, requestParams);
}
}
/**
* 发送POST请求
* @param url 请求路径
* @param params 请求参数
* @return 响应结果
*/
private static String postRequest(String url, Map<String, Object> params) throws IOException {
// 构建表单数据而不是JSON
FormBody.Builder formBuilder = new FormBody.Builder();
for (Map.Entry<String, Object> entry : params.entrySet()) {
formBuilder.add(entry.getKey(), String.valueOf(entry.getValue()));
}
RequestBody body = formBuilder.build();
Request request = new Request.Builder()
.url(BASE_URL + url)
.post(body)
.addHeader("Content-Type", MEDIA_TYPE_FORM)
.build();
try (Response response = httpClient.newCall(request).execute()) {
if (response.isSuccessful()) {
return response.body().string();
} else {
throw new IOException("请求失败: " + response.code() + " " + response.message());
}
}
}
/**
* 发送GET请求
* @param url 请求路径
* @param params 请求参数
* @return 响应结果
*/
private static String getRequest(String url, Map<String, Object> params) throws IOException {
// 构建带参数的URL
String fullUrl = buildUrlWithParams(BASE_URL + url, params);
Request request = new Request.Builder()
.url(fullUrl)
.get()
.addHeader("Content-Type", MEDIA_TYPE_JSON)
.build();
try (Response response = httpClient.newCall(request).execute()) {
if (response.isSuccessful()) {
return response.body().string();
} else {
throw new IOException("请求失败: " + response.code() + " " + response.message());
}
}
}
/**
* 构建带查询参数的URL
* @param baseUrl 基础URL
* @param params 查询参数
* @return 完整URL
*/
private static String buildUrlWithParams(String baseUrl, Map<String, Object> params) {
if (params == null || params.isEmpty()) {
return baseUrl;
}
StringBuilder urlBuilder = new StringBuilder(baseUrl);
urlBuilder.append("?");
boolean first = true;
for (Map.Entry<String, Object> entry : params.entrySet()) {
if (!first) {
urlBuilder.append("&");
}
urlBuilder.append(entry.getKey())
.append("=")
.append(entry.getValue());
first = false;
}
return urlBuilder.toString();
}
/**
* 生成PbootCMS API签名(双层MD5加密)
* @param appid 应用ID
* @param secret 密钥
* @param timestamp 时间戳
* @return 签名字符串
*/
private static String generateSignature(String appid, String secret, String timestamp) {
// 构造签名字符串: appid + secret + timestamp
String sign = appid + secret + timestamp;
// 双层MD5加密
String firstMd5 = DigestUtils.md5Hex(sign);
return DigestUtils.md5Hex(firstMd5);
}
// 使用示例
//public static void main(String[] args) {
// try {
// // GET请求示例
// //String getResult = apiRequest("site", "GET", null);
// //System.out.println("GET结果: " + getResult);
//
// // POST请求示例
// Map<String, Object> postParams = new HashMap<>();
// postParams.put("contacts", "测试文章标题");
// postParams.put("name", "nimhjcws");
// postParams.put("tel", "14523687549");
// postParams.put("mobile", "12345678914");
// postParams.put("content", ";lsdjfpolasndlwiojnkldoifdfnddfd");
//
// String postResult = apiRequest("add", "POST", postParams);
// System.out.println("POST结果: " + postResult);
//
// } catch (IOException e) {
// e.printStackTrace();
// }
//}
}
... ...
package com.aigeo.util;
import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.colors.ColorConstants;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Image;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.properties.TextAlignment;
import com.itextpdf.layout.properties.UnitValue;
import java.io.File;
import java.io.FileOutputStream;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PdfCreateUtil {
public static String create(String content) {
try {
long l = System.currentTimeMillis();
String fileName = "D:/LsYwxProject/YwxErpApi/yiwaixiaoerp/YwxErp/upload/aidocx/" + l + ".pdf";
createFormattedPdfWithIText(content, fileName);
System.out.println("文档创建成功:自然的诗篇.pdf");
return fileName;
} catch (Exception e) {
System.err.println("创建文档时出错: " + e.getMessage());
e.printStackTrace();
}
return "success";
}
public static void createFormattedPdfWithIText(String content, String fileName) throws Exception {
// 确保输出目录存在
File outputFile = new File(fileName);
File parentDir = outputFile.getParentFile();
if (parentDir != null && !parentDir.exists()) {
parentDir.mkdirs();
}
// 创建PDF文档
PdfWriter writer = new PdfWriter(new FileOutputStream(outputFile));
PdfDocument pdf = new PdfDocument(writer);
Document document = new Document(pdf);
// 尝试设置中文字体
try {
PdfFont chineseFont = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H");
document.setFont(chineseFont);
System.out.println("中文字体设置成功");
} catch (Exception e) {
System.err.println("无法设置中文字体,将使用默认字体: " + e.getMessage());
}
try {
// 按段落分割内容(两个换行符)
String[] paragraphs = content.split("\n");
System.out.println("检测到 " + paragraphs.length + " 个段落");
// 遍历所有段落
for (int i = 0; i < paragraphs.length; i++) {
String paragraph = paragraphs[i].trim();
System.out.println("处理第 " + (i+1) + " 段: " + (paragraph.length() > 50 ? paragraph.substring(0, 50) + "..." : paragraph));
if (paragraph.isEmpty()) {
continue;
}
// 检查是否是标题
if (paragraph.startsWith("# ")) {
// 处理以 # 开头的标题
String title = paragraph.substring(2).trim(); // 移除 "# "
System.out.println("发现标题: " + title);
//.setTextAlignment(TextAlignment.CENTER)
Paragraph titlePara = new Paragraph(title)
.setFontSize(18)
.setBold()
.setMarginBottom(20);
document.add(titlePara);
}
else if (paragraph.startsWith("**") && paragraph.endsWith("**")) {
// 处理以 ** 开头和结尾的标题
String title = paragraph.substring(2, paragraph.length() - 2).trim(); // 移除开头和结尾的 **
System.out.println("发现标题: " + title);
Paragraph titlePara = new Paragraph(title)
.setFontSize(18)
.setBold()
.setMarginBottom(20);
document.add(titlePara);
}
// 检查是否是图片
else if (paragraph.startsWith("![")) {
String imageUrl = extractImageUrl(paragraph);
if (imageUrl != null) {
System.out.println("发现图片,URL: " + imageUrl);
try {
ImageData imageData = ImageDataFactory.create(new URL(imageUrl));
Image image = new Image(imageData);
image.setAutoScale(true);
image.setMaxWidth(UnitValue.createPointValue(400));
image.setTextAlignment(TextAlignment.CENTER);
document.add(image);
} catch (Exception e) {
System.err.println("无法加载图片: " + e.getMessage());
Paragraph errorPara = new Paragraph("[图片加载失败: " + imageUrl + "]")
.setFontColor(ColorConstants.RED);
document.add(errorPara);
}
}
}
// 普通文本段落
else {
System.out.println("发现文本段落,长度: " + paragraph.length());
if (!paragraph.isEmpty()) {
Paragraph textPara = new Paragraph(paragraph)
.setFontSize(12)
.setMarginBottom(10)
.setFirstLineIndent(20);
document.add(textPara);
}
}
}
System.out.println("所有内容处理完成");
} finally {
document.close();
System.out.println("PDF文档已关闭");
}
}
private static String extractImageUrl(String markdown) {
Pattern pattern = Pattern.compile("!\\[.*?\\]\\((.*?)\\)");
Matcher matcher = pattern.matcher(markdown);
if (matcher.find()) {
return matcher.group(1);
}
return null;
}
}
... ...
package com.aigeo.util.article;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
// 文章服务门面类
@Component
public class ArticleOperationFacade {
@Autowired
private ArticleServiceFactory articleServiceFactory;
public void publishArticle(PlatformTypeEnum platformType, Object articleData, Integer companyId) {
ArticlePlatformService service = articleServiceFactory.getArticleService(platformType);
// return service.publishArticle(articleData, companyId);
}
public void updateArticle(PlatformTypeEnum platformType, Object articleData, Integer companyId) {
ArticlePlatformService service = articleServiceFactory.getArticleService(platformType);
// return service.updateArticle(articleData, companyId);
}
public void deleteArticle(PlatformTypeEnum platformType, String articleId, Integer companyId) {
ArticlePlatformService service = articleServiceFactory.getArticleService(platformType);
// return service.deleteArticle(articleId, companyId);
}
}
... ...
package com.aigeo.util.article;
public interface ArticlePlatformService {
void publishArticle(Object articleData, Integer companyId);
void updateArticle(Object articleData, Integer companyId);
void deleteArticle(String articleId, Integer companyId);
String getPlatform();
}
... ...
package com.aigeo.util.article;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Component
public class ArticleServiceFactory {
private Map<String, ArticlePlatformService> platformServices;
private final Map<String, ArticlePlatformService> serviceMap = new ConcurrentHashMap<>();
@Autowired
public void setPlatformServices(Map<String, ArticlePlatformService> platformServices) {
this.platformServices = platformServices;
initServiceMap();
}
private void initServiceMap() {
for (ArticlePlatformService service : platformServices.values()) {
serviceMap.put(service.getPlatform(), service);
}
}
public ArticlePlatformService getArticleService(PlatformTypeEnum platformType) {
ArticlePlatformService service = serviceMap.get(platformType.getPlatform());
if (service == null) {
throw new IllegalArgumentException("不支持的平台类型: " + platformType);
}
return service;
}
public ArticlePlatformService getArticleService(String platform) {
ArticlePlatformService service = serviceMap.get(platform);
if (service == null) {
throw new IllegalArgumentException("不支持的平台类型: " + platform);
}
return service;
}
}
\ No newline at end of file
... ...
package com.aigeo.util.article;
public enum PlatformTypeEnum {
SHOPIFY("shopify"),
WORDPRESS("wordpress");
private final String platform;
PlatformTypeEnum(String platform) {
this.platform = platform;
}
public String getPlatform() {
return platform;
}
}
... ...
package com.aigeo.util.article;
import com.aigeo.entity.CreateArticleDTO;
import com.aigeo.entity.UpdateArticleDTO;
import com.alibaba.fastjson2.JSONObject;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.IOException;
@Component
public class Shopify implements ArticlePlatformService {
private static final OkHttpClient okHttpClient = new OkHttpClient();
// @Value("${openapi.url}")
private String api_url;
private static String staticApiUrl;
@PostConstruct
public void init() {
staticApiUrl = api_url;
}
@Override
public void publishArticle(Object articleData, Integer companyId) {
// 实现Shopify发布文章逻辑
// if (!(articleData instanceof CreateArticleDTO)) {
// return BaseResponse.error(ReturnCodeEnum.ERROR, "参数类型错误");
// }
CreateArticleDTO createArticleDTO = (CreateArticleDTO) articleData;
// // 参数校验
// if (StringUtils.isBlank(createArticleDTO.getBlogId())) {
// return BaseResponse.error(ReturnCodeEnum.ERROR, "博客ID不能为空");
// }
// if (StringUtils.isBlank(createArticleDTO.getTitle())) {
// return BaseResponse.error(ReturnCodeEnum.ERROR, "标题不能为空");
// }
// if (createArticleDTO.getAuthor() == null || StringUtils.isBlank(createArticleDTO.getAuthor().getName())) {
// return BaseResponse.error(ReturnCodeEnum.ERROR, "作者信息不能为空");
// }
// if (StringUtils.isBlank(createArticleDTO.getBody())) {
// return BaseResponse.error(ReturnCodeEnum.ERROR, "文章内容不能为空");
// }
// 构建请求体
JSONObject requestBody = new JSONObject();
requestBody.put("blogId", createArticleDTO.getBlogId());
requestBody.put("title", createArticleDTO.getTitle());
// 构建author对象
JSONObject authorObject = new JSONObject();
authorObject.put("name", createArticleDTO.getAuthor().getName());
requestBody.put("author", authorObject);
requestBody.put("handle", generateUniqueHandle(createArticleDTO.getTitle()));
requestBody.put("body", createArticleDTO.getBody());
requestBody.put("companyId", companyId);
// 构建请求
Request request = new Request.Builder()
.url("http:127.0.0.1:8009" + "/shopify/createArticle")
.post(okhttp3.RequestBody.create(
requestBody.toJSONString(),
okhttp3.MediaType.parse("application/json; charset=utf-8")
))
.build();
// 发送请求
try (Response response = okHttpClient.newCall(request).execute()) {
if (response.isSuccessful()) {
String responseBody = response.body().string();
JSONObject jsonResponse = JSONObject.parseObject(responseBody);
int code = jsonResponse.getIntValue("code");
String message = jsonResponse.getString("message");
// if (code != 200) {
// return BaseResponse.error(ReturnCodeEnum.ERROR, message);
// } else {
// return BaseResponse.success(jsonResponse.get("data"));
// }
} else {
// return BaseResponse.error(ReturnCodeEnum.SYSTEM_ERROR);
}
} catch (IOException e) {
e.printStackTrace();
// return BaseResponse.error(ReturnCodeEnum.SYSTEM_ERROR);
}
}
@Override
public void updateArticle(Object articleData, Integer companyId) {
// if (!(articleData instanceof UpdateArticleDTO)) {
// return BaseResponse.error(ReturnCodeEnum.ERROR, "参数类型错误");
// }
UpdateArticleDTO updateArticleDTO = (UpdateArticleDTO) articleData;
// 参数校验
// if (StringUtils.isBlank(updateArticleDTO.getId())) {
// return BaseResponse.error(ReturnCodeEnum.ERROR, "文章ID不能为空");
// }
// if (StringUtils.isBlank(updateArticleDTO.getTitle())) {
// return BaseResponse.error(ReturnCodeEnum.ERROR, "标题不能为空");
// }
// if (StringUtils.isBlank(updateArticleDTO.getBody())) {
// return BaseResponse.error(ReturnCodeEnum.ERROR, "文章内容不能为空");
// }
// 构建请求体
JSONObject requestBody = new JSONObject();
requestBody.put("id", updateArticleDTO.getId());
requestBody.put("title", updateArticleDTO.getTitle());
requestBody.put("handle", updateArticleDTO.getHandle() != null ?
updateArticleDTO.getHandle() : generateUniqueHandle(updateArticleDTO.getTitle()));
requestBody.put("body", updateArticleDTO.getBody());
requestBody.put("companyId", companyId);
// 可选字段
if (StringUtils.isNotBlank(updateArticleDTO.getSummary())) {
requestBody.put("summary", updateArticleDTO.getSummary());
}
if (updateArticleDTO.getTags() != null && updateArticleDTO.getTags().length > 0) {
requestBody.put("tags", updateArticleDTO.getTags());
}
if (StringUtils.isNotBlank(updateArticleDTO.getImageAltText())) {
requestBody.put("imageAltText", updateArticleDTO.getImageAltText());
}
if (StringUtils.isNotBlank(updateArticleDTO.getImageUrl())) {
requestBody.put("imageUrl", updateArticleDTO.getImageUrl());
}
// 构建请求
Request request = new Request.Builder()
.url(staticApiUrl + "/shopify/updateArticle")
.post(okhttp3.RequestBody.create(
requestBody.toJSONString(),
okhttp3.MediaType.parse("application/json; charset=utf-8")
))
.build();
// 发送请求
try (Response response = okHttpClient.newCall(request).execute()) {
if (response.isSuccessful()) {
String responseBody = response.body().string();
JSONObject jsonResponse = JSONObject.parseObject(responseBody);
int code = jsonResponse.getIntValue("code");
String message = jsonResponse.getString("message");
// if (code != 200) {
// return BaseResponse.error(ReturnCodeEnum.ERROR, message);
// } else {
// return BaseResponse.success(jsonResponse.get("data"));
// }
} else {
// return BaseResponse.error(ReturnCodeEnum.SYSTEM_ERROR);
}
} catch (IOException e) {
e.printStackTrace();
// return BaseResponse.error(ReturnCodeEnum.SYSTEM_ERROR);
}
}
@Override
public void deleteArticle(String articleId, Integer companyId) {
// 参数校验
// if (StringUtils.isBlank(articleId)) {
// return BaseResponse.error(ReturnCodeEnum.ERROR, "文章ID不能为空");
// }
// 构建带参数的URL
String deleteUrl = staticApiUrl + "/shopify/deleteArticle?articleId=" + articleId;
// 构建DELETE请求
Request request = new Request.Builder()
.url(deleteUrl)
.delete()
.build();
// 发送请求
try (Response response = okHttpClient.newCall(request).execute()) {
if (response.isSuccessful()) {
String responseBody = response.body().string();
JSONObject jsonResponse = JSONObject.parseObject(responseBody);
int code = jsonResponse.getIntValue("code");
String message = jsonResponse.getString("message");
// if (code != 200) {
// return BaseResponse.error(ReturnCodeEnum.ERROR, message);
// } else {
// return BaseResponse.success(jsonResponse.get("data"));
// }
} else {
// return BaseResponse.error(ReturnCodeEnum.SYSTEM_ERROR);
}
} catch (IOException e) {
e.printStackTrace();
// return BaseResponse.error(ReturnCodeEnum.SYSTEM_ERROR);
}
}
@Override
public String getPlatform() {
return "shopify";
}
private static String generateUniqueHandle(String title) {
// 创建URL友好的handle
String cleanTitle = title.toLowerCase()
.replaceAll("[^a-zA-Z0-9\\u4e00-\\u9fa5\\s-]", "") // 保留中文字符
.replaceAll("\\s+", "-")
.replaceAll("-+", "-")
.replaceAll("^-|-$", "");
// 限制长度并确保唯一性
if (cleanTitle.length() > 40) {
cleanTitle = cleanTitle.substring(0, 40);
}
// 添加时间戳确保唯一性
String timestamp = String.valueOf(System.currentTimeMillis() % 100000);
return cleanTitle + "-" + timestamp;
}
}
... ...
// 修改 WordPress.java 文件,实现 deleteArticle 方法
package com.aigeo.util.article;
import com.aigeo.entity.CreateArticleDTO;
import com.aigeo.entity.UpdateArticleDTO;
import com.alibaba.fastjson2.JSONObject;
import okhttp3.*;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
@Component
public class WordPress implements ArticlePlatformService {
private static final OkHttpClient okHttpClient = new OkHttpClient();
private static final String BASE_URL = "https://web1.szcxybz.com/wp-json/wp/v2/posts";
private static final String TOKEN_URL = "https://web1.szcxybz.com/wp-json/jwt-auth/v1/token";
private static String cachedToken = null;
private static long tokenExpiryTime = 0;
private static final long TOKEN_REFRESH_BUFFER = TimeUnit.MINUTES.toMillis(5);// 5分钟缓冲
private static final OkHttpClient httpClient = new OkHttpClient();
private static final String MEDIA_TYPE = "application/json; charset=utf-8";
private static final String USERNAME = "admin";
private static final String PASSWORD = "123456";
@Override
public void publishArticle(Object articleData, Integer companyId) {
// 获取有效的 token
String token = null;
try {
token = getValidToken();
} catch (IOException e) {
e.printStackTrace();
// return BaseResponse.error(ReturnCodeEnum.SYSTEM_ERROR);
}
// if (token == null) {
// System.out.println("无法获取有效的认证 token");
// return BaseResponse.error(ReturnCodeEnum.SYSTEM_ERROR);
// }
CreateArticleDTO createArticleDTO = (CreateArticleDTO) articleData;
String styledContent = createArticleDTO.getBody().replace("<style>", "<!-- Style block will be removed by WordPress -->")
.replace("</style>", "");
JSONObject contentObject = new JSONObject();
contentObject.put("raw", styledContent);
JSONObject jsonBody = new JSONObject();
jsonBody.put("title", createArticleDTO.getTitle());
jsonBody.put("content", contentObject);
jsonBody.put("status", "publish");
//jsonBody.put("author", author);
RequestBody body = RequestBody.create(
jsonBody.toString(),
MediaType.get(MEDIA_TYPE)
);
Request request = new Request.Builder()
.url(BASE_URL)
.post(body)
.addHeader("Authorization", "Bearer " + token)
.addHeader("Content-Type", "application/json")
.build();
try (Response response = okHttpClient.newCall(request).execute()) {
if (response.isSuccessful()) {
// System.out.println("响应内容: " + response.body().string());
String res = response.body().string();
// return BaseResponse.success(res);
} else {
System.out.println("发布失败: " + response.code());
System.out.println("错误信息: " + response.body().string());
// return BaseResponse.error(ReturnCodeEnum.ERROR,"发布失败");
}
} catch (IOException e) {
e.printStackTrace();
// return BaseResponse.error(ReturnCodeEnum.SYSTEM_ERROR);
}
}
@Override
public void updateArticle(Object articleData, Integer companyId) {
// 检查参数类型
// if (!(articleData instanceof UpdateArticleDTO)) {
// return BaseResponse.error(ReturnCodeEnum.ERROR, "参数类型错误");
// }
UpdateArticleDTO updateArticleDTO = (UpdateArticleDTO) articleData;
// 参数校验
// if (updateArticleDTO.getId() == null || updateArticleDTO.getId().isEmpty()) {
// return BaseResponse.error(ReturnCodeEnum.ERROR, "文章ID不能为空");
// }
// 获取有效的 token
String token = null;
try {
token = getValidToken();
} catch (IOException e) {
e.printStackTrace();
// return BaseResponse.error(ReturnCodeEnum.SYSTEM_ERROR);
}
// if (token == null) {
// System.out.println("无法获取有效的认证 token");
// return BaseResponse.error(ReturnCodeEnum.SYSTEM_ERROR);
// }
// 构建更新文章的URL
String updateUrl = BASE_URL + "/" + updateArticleDTO.getId();
// 构建请求体
JSONObject jsonBody = new JSONObject();
// 只添加非空字段进行更新
if (updateArticleDTO.getTitle() != null && !updateArticleDTO.getTitle().isEmpty()) {
jsonBody.put("title", updateArticleDTO.getTitle());
}
if (updateArticleDTO.getBody() != null && !updateArticleDTO.getBody().isEmpty()) {
String styledContent = updateArticleDTO.getBody().replace("<style>", "<!-- Style block will be removed by WordPress -->")
.replace("</style>", "");
JSONObject contentObject = new JSONObject();
contentObject.put("raw", styledContent);
jsonBody.put("content", contentObject);
}
// 可选字段
if (updateArticleDTO.getSummary() != null) {
jsonBody.put("excerpt", updateArticleDTO.getSummary());
}
// 添加状态字段(如果需要)
jsonBody.put("status", "publish");
RequestBody body = RequestBody.create(
jsonBody.toString(),
MediaType.get(MEDIA_TYPE)
);
// 构建PUT请求
Request request = new Request.Builder()
.url(updateUrl)
.put(body) // 使用PUT方法更新文章
.addHeader("Authorization", "Bearer " + token)
.addHeader("Content-Type", "application/json")
.build();
try (Response response = okHttpClient.newCall(request).execute()) {
if (response.isSuccessful()) {
String res = response.body().string();
// return BaseResponse.success(res);
} else {
System.out.println("更新文章失败: " + response.code());
System.out.println("错误信息: " + response.body().string());
// return BaseResponse.error(ReturnCodeEnum.ERROR, "更新文章失败,状态码: " + response.code());
}
} catch (IOException e) {
e.printStackTrace();
// return BaseResponse.error(ReturnCodeEnum.SYSTEM_ERROR);
}
}
@Override
public void deleteArticle(String articleId, Integer companyId) {
// 获取有效的 token
String token = null;
try {
token = getValidToken();
} catch (IOException e) {
e.printStackTrace();
// return BaseResponse.error(ReturnCodeEnum.SYSTEM_ERROR);
}
if (token == null) {
System.out.println("无法获取有效的认证 token");
// return BaseResponse.error(ReturnCodeEnum.SYSTEM_ERROR);
}
// 构建删除文章的URL,将文章ID附加到基础URL后面
String deleteUrl = BASE_URL + "/" + articleId;
// 构建DELETE请求
Request request = new Request.Builder()
.url(deleteUrl)
.delete()
.addHeader("Authorization", "Bearer " + token)
.addHeader("Content-Type", "application/json")
.build();
try (Response response = okHttpClient.newCall(request).execute()) {
if (response.isSuccessful()) {
String res = response.body().string();
// return BaseResponse.success(res);
} else {
System.out.println("删除文章失败: " + response.code());
System.out.println("错误信息: " + response.body().string());
// return BaseResponse.error(ReturnCodeEnum.ERROR, "删除文章失败,状态码: " + response.code());
}
} catch (IOException e) {
e.printStackTrace();
// return BaseResponse.error(ReturnCodeEnum.SYSTEM_ERROR);
}
}
@Override
public String getPlatform() {
return "wordpress";
}
private static String getValidToken() throws IOException {
// 检查是否有缓存的 token 且未过期
if (cachedToken != null && System.currentTimeMillis() < (tokenExpiryTime - TOKEN_REFRESH_BUFFER)) {
return cachedToken;
}
System.out.println("token过期,重新获取token");
// 获取新 token
String newToken = fetchNewToken();
if (newToken != null) {
cachedToken = newToken;
// 假设 token 有效期为 24 小时,实际应根据返回的过期时间设置
tokenExpiryTime = System.currentTimeMillis() + TimeUnit.HOURS.toMillis(2);
}
return newToken;
}
// 获取新的 JWT token
private static String fetchNewToken() throws IOException {
JSONObject loginData = new JSONObject();
loginData.put("username", USERNAME);
loginData.put("password", PASSWORD);
RequestBody body = RequestBody.create(
loginData.toString(),
MediaType.get(MEDIA_TYPE)
);
Request request = new Request.Builder()
.url(TOKEN_URL)
.post(body)
.addHeader("Content-Type", "application/json")
.build();
try (Response response = httpClient.newCall(request).execute()) {
if (response.isSuccessful()) {
String responseBody = response.body().string();
JSONObject tokenResponse = JSONObject.parseObject(responseBody);
// 实际项目中应该从响应中获取真正的过期时间
// tokenResponse.getLong("expires_in") 或类似字段
return tokenResponse.getString("token");
} else {
System.out.println("获取 token 失败: " + response.code());
System.out.println("错误信息: " + response.body().string());
return null;
}
}
}
}
... ...