From bd4ff9d24a7eff619777edf3bae312a75cd59b68 Mon Sep 17 00:00:00 2001 From: yimfeng Date: Fri, 17 Sep 2021 19:45:43 +0800 Subject: [PATCH 1/8] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=B8=A6=E6=9C=89?= =?UTF-8?q?=E5=9B=BE=E7=89=87xmind=E5=AF=BC=E5=85=A5=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- case-server/pom.xml | 10 ++ .../controller/UploadController.java | 11 +- .../xiaoju/framework/service/FileService.java | 5 +- .../service/impl/FileServiceImpl.java | 41 +++++- .../com/xiaoju/framework/util/TreeUtil.java | 138 +++++++++++++++++- 5 files changed, 191 insertions(+), 14 deletions(-) diff --git a/case-server/pom.xml b/case-server/pom.xml index 28e1b9f..fd070cf 100644 --- a/case-server/pom.xml +++ b/case-server/pom.xml @@ -159,6 +159,16 @@ 0.4.11 + + org.springframework + spring-web + 5.1.6.RELEASE + + + org.springframework + spring-test + + diff --git a/case-server/src/main/java/com/xiaoju/framework/controller/UploadController.java b/case-server/src/main/java/com/xiaoju/framework/controller/UploadController.java index cfc98a6..6de144e 100644 --- a/case-server/src/main/java/com/xiaoju/framework/controller/UploadController.java +++ b/case-server/src/main/java/com/xiaoju/framework/controller/UploadController.java @@ -60,13 +60,17 @@ public class UploadController { * @param requirementId 需求idStr * @return 响应体 */ + + @Value("${web.upload-path}") + private String uploadPath; + @PostMapping(value = "/import", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public Response importXmind(@RequestParam MultipartFile file, String creator, String bizId, - Long productLineId, String title, String description, Integer channel, String requirementId) { + Long productLineId, String title, String description, Integer channel, String requirementId, HttpServletRequest request) { FileImportReq req = new FileImportReq(file, creator, productLineId, title, description, channel, requirementId, bizId); req.validate(); try { - return Response.success(fileService.importXmindFile(req)); + return Response.success(fileService.importXmindFile(req, request, uploadPath)); } catch (CaseServerException e) { throw new CaseServerException(e.getLocalizedMessage(), e.getStatus()); } catch (Exception e) { @@ -76,8 +80,7 @@ public Response importXmind(@RequestParam MultipartFile file, String creat } } - @Value("${web.upload-path}") - private String uploadPath; + @PostMapping(value = "/uploadAttachment", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public JSONObject uploadAttachment(@RequestParam MultipartFile file, HttpServletRequest request) { diff --git a/case-server/src/main/java/com/xiaoju/framework/service/FileService.java b/case-server/src/main/java/com/xiaoju/framework/service/FileService.java index dd3c5f0..840684b 100644 --- a/case-server/src/main/java/com/xiaoju/framework/service/FileService.java +++ b/case-server/src/main/java/com/xiaoju/framework/service/FileService.java @@ -3,6 +3,8 @@ import com.xiaoju.framework.entity.request.cases.FileImportReq; import com.xiaoju.framework.entity.response.cases.ExportXmindResp; +import javax.servlet.http.HttpServletRequest; + /** * 文件上传与导出服务接口 * @@ -15,10 +17,11 @@ public interface FileService { * 导入x-mind文件生成case * * @param req 请求体 + * @param request * @return 生成的case-id * @throws Exception 任何可能的异常 */ - Long importXmindFile(FileImportReq req) throws Exception; + Long importXmindFile(FileImportReq req, HttpServletRequest request, String uploadPath) throws Exception; /** * 导出xmind内容 diff --git a/case-server/src/main/java/com/xiaoju/framework/service/impl/FileServiceImpl.java b/case-server/src/main/java/com/xiaoju/framework/service/impl/FileServiceImpl.java index 24068c6..7641af1 100644 --- a/case-server/src/main/java/com/xiaoju/framework/service/impl/FileServiceImpl.java +++ b/case-server/src/main/java/com/xiaoju/framework/service/impl/FileServiceImpl.java @@ -27,11 +27,12 @@ import org.springframework.util.StringUtils; import javax.annotation.Resource; -import javax.print.Doc; +import javax.servlet.http.HttpServletRequest; import java.io.*; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import static com.xiaoju.framework.constants.SystemConstant.POINT; import static com.xiaoju.framework.constants.XmindConstant.*; @@ -55,9 +56,8 @@ public class FileServiceImpl implements FileService { @Override @Transactional(rollbackFor = Exception.class) - public Long importXmindFile(FileImportReq req) throws Exception { + public Long importXmindFile(FileImportReq req, HttpServletRequest request, String uploadPath) throws Exception { String fileName = req.getFile().getOriginalFilename(); - if (!StringUtils.isEmpty(fileName)) { // 得到上传文件的扩展名 String suffix = fileName.substring(fileName.lastIndexOf(POINT) + 1).toLowerCase(); @@ -92,7 +92,7 @@ public Long importXmindFile(FileImportReq req) throws Exception { // 导入用例 File jsonFile = new File((desc + CONTENT_JSON).replace("/", File.separator)); - CaseCreateReq caseCreateReq = jsonFile.exists() ? buildCaseByJson(req, desc) : buildCaseByXml(req, desc); + CaseCreateReq caseCreateReq = jsonFile.exists() ? buildCaseByJson(req, desc) : buildCaseByXml(req, desc, request, uploadPath); return caseService.insertOrDuplicateCase(caseCreateReq); } throw new CaseServerException("传入的文件名非法", StatusCode.FILE_IMPORT_ERROR); @@ -158,7 +158,7 @@ private void writeManifestXml(String path){ Document document = DocumentHelper.createDocument(); // 2、创建根节点root Element root = document.addElement("manifest").addAttribute("xmlns",XMIND_MAINFEST_XMLNS); - // 3、生成子节点及子节点内容 + // 3、生成子节点及子节点内容,此处应该添加图片属性(2021/09/06) root.addElement("file-entry") .addAttribute("full-path","content.xml") .addAttribute("media-type","text/xml"); @@ -210,11 +210,13 @@ private Map createFile(Long id) } String path = creteFolder(testCase); // 创建要写入的文件夹 + // 此处需要新加一个文件夹,命名为attachments,里面存放图片 + writeAttachments(path); //写入content.xml内容 writeContentXml(testCase,path); //写Meta文件 writeMetaXml(path); - //写MainFest文件 + //写MainFest文件,需要在此处添加文件夹中的问题信息 writeManifestXml(path); Map pathMap = new HashMap<>(); @@ -223,6 +225,12 @@ private Map createFile(Long id) return pathMap; } + // 将照片拷贝到path文件夹里面 + private void writeAttachments(String path){ + String targetPath = path + "/attachments"; + + } + //拼接xml内容 private void writeContentXml(TestCase testCase,String path){ // 1、创建document对象 @@ -237,6 +245,7 @@ private void writeContentXml(TestCase testCase,String path){ .addAttribute("timestamp",XMIND_CREATED_VERSION); // 给sheet添加属性timestamp // 获得全部json数据,此时的json数据中有图片的链接地址,需要把image取出来 JSONObject rootObj = JSON.parseObject(testCase.getCaseContent()).getJSONObject(ROOT); + System.out.println("case中的内容:" + testCase.getCaseContent()); Element topic = sheet.addElement("topic") // 给sheet添加新的节点topic .addAttribute("id",rootObj.getJSONObject(DATA).getString("id")) // 获得id .addAttribute("modified-by","didi") // 获得用户名 @@ -290,12 +299,15 @@ private CaseCreateReq buildCaseByJson(FileImportReq request, String fileName) { } //xmind8从content文件读取用例内容 - public CaseCreateReq buildCaseByXml(FileImportReq request, String fileName) throws Exception { + public CaseCreateReq buildCaseByXml(FileImportReq request, String fileName, HttpServletRequest requests, String uploadPath) throws Exception { JSONArray jsonArray = new JSONArray(); String fileXml = "content.xml"; + String picXml = "attachments"; // 存放图片的文件夹 + String picName = (fileName + picXml).replace("/", File.separator); fileName = (fileName + fileXml).replace("/", File.separator); File file = new File(fileName); + File file1 = new File(picName); if(!file.exists()) // 判断文件是否存在 throw new CaseServerException("导入失败,文件不存在", StatusCode.FILE_IMPORT_ERROR); SAXReader reade = new SAXReader(); @@ -306,7 +318,20 @@ public CaseCreateReq buildCaseByXml(FileImportReq request, String fileName) thro String eleName = childElement.getName(); if(eleName.equalsIgnoreCase("sheet")) { - jsonArray = TreeUtil.importDataByXml(childElement); + // 如果包含图片的文件夹存在,则重写importDataXml方法,将file1添加进去 + if(file1.exists()){ + if(file1.isDirectory()){ + System.out.println("有图片信息"); + // 此时需要将本地文件传到网上 + jsonArray = TreeUtil.importDataByXml1(request, childElement, picName, requests, uploadPath); + } + } + // 如果包含图片的文件夹不存在,则直接调用importDataByXml方法,不需要再传入file1这个参数 + else{ + System.out.println("没有图片信息"); + jsonArray = TreeUtil.importDataByXml(childElement); + } + } return buildCaseCreateReq(request, jsonArray); } diff --git a/case-server/src/main/java/com/xiaoju/framework/util/TreeUtil.java b/case-server/src/main/java/com/xiaoju/framework/util/TreeUtil.java index 444fe52..79cd186 100644 --- a/case-server/src/main/java/com/xiaoju/framework/util/TreeUtil.java +++ b/case-server/src/main/java/com/xiaoju/framework/util/TreeUtil.java @@ -4,12 +4,27 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.xiaoju.framework.constants.enums.ProgressEnum; +import com.xiaoju.framework.controller.UploadController; +import com.xiaoju.framework.entity.request.cases.FileImportReq; import com.xiaoju.framework.entity.xmind.*; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringEscapeUtils; +import org.apache.http.entity.ContentType; import org.dom4j.Element; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.mock.web.MockMultipartFile; import org.springframework.util.StringUtils; - +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.text.SimpleDateFormat; import java.util.*; @@ -22,6 +37,12 @@ */ public class TreeUtil { + /** + * 常量 + */ + private static final Logger LOGGER = LoggerFactory.getLogger(TreeUtil.class); + + // 剥离出progress的内容 public static JSONObject parse(String caseContent) { JSONObject retContent = new JSONObject(); @@ -411,6 +432,121 @@ else if (element.getName().equalsIgnoreCase("title")) { } + // 添加一个新的方法,接口中有带有图片的文件夹名属性 + public static JSONArray importDataByXml1(FileImportReq request, Element e, String fileName, HttpServletRequest requests, String uploadPath) throws IOException { + JSONArray jsonArray = new JSONArray(); + List elementList = e.elements(); + if(elementList.size() == 0) + return jsonArray; + for(Element element1:elementList) + { + if(element1.getName().equalsIgnoreCase("topic")) + { + JSONArray childrenNext = new JSONArray(); + JSONObject root = new JSONObject(); + JSONObject dataObj = new JSONObject(); + List newList = element1.elements(); + Map imageSize = new HashMap<>(); + String text = ""; + String image = ""; + String picPath = ""; + Integer priorityId = 0; + String created = element1.attributeValue("timestamp"); + String id = element1.attributeValue("id"); + + for (Element element : newList) { + // 获取xml里面的图片大小信息 + if(element.getName().equalsIgnoreCase("img")){ // 添加imagesize属性 + // 需要将图片传到云空间中,然后将返回的链接导入 + System.out.println("xhtml:img可以使用,其中element中的内容为:" + element); + imageSize.put("width", element.attributeValue("width")); + imageSize.put("height", element.attributeValue("height")); + String path = element.attributeValue("src"); + String[] strs = path.split("/"); + int len = strs.length; + fileName = fileName + "/"; + image = strs[len-1]; // 此时image为图片所在的本地位置 + // 将文件传入到temp文件下,因此需要将文件进行转换,将file文件类型转化为MultipartFile类型,然后进行上传 + File file = new File(fileName + image); + FileInputStream fileInputStream = new FileInputStream(file); + MultipartFile multipartFile = new MockMultipartFile(file.getName(), file.getName(), + ContentType.APPLICATION_OCTET_STREAM.toString(), fileInputStream); + + // 将MultipartFile文件进行上传 + JSONObject ret = new JSONObject(); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd/"); + String format = sdf.format(new Date()); + File folder = new File(uploadPath + format);// 文件夹的名字 + if (!folder.isDirectory()) { // 如果文件夹为空,则新建文件夹 + folder.mkdirs(); + } + // 对上传的文件重命名,避免文件重名 + String oldName = multipartFile.getOriginalFilename(); // 获取文件的名字 + String newName = UUID.randomUUID().toString() + + oldName.substring(oldName.lastIndexOf("."), oldName.length()); // 生成新的随机的文件名字 + File newFile = new File(folder, newName); + try { + multipartFile.transferTo(new File(folder, newName)); + // 返回上传文件的访问路径 + // request.getScheme()可获取请求的协议名,request.getServerName()可获取请求的域名,request.getServerPort()可获取请求的端口号 + String filePath = requests.getScheme() + "://" + requests.getServerName() + + ":" + requests.getServerPort() + "/" + format + newName; + picPath = filePath; + JSONArray datas = new JSONArray(); + JSONObject data = new JSONObject(); + data.put("url", filePath); + ret.put("success", 1); + datas.add(data); + ret.put("data", datas); + } catch (IOException err) { + LOGGER.error("上传文件失败, 请重试。", err); + ret.put("success", 0); + ret.put("data", ""); + } + } + // 获取xml里面中的图片importDataByXml1 + + else if (element.getName().equalsIgnoreCase("title")) { + //标题 + text = element.getText(); + }else if (element.getName().equalsIgnoreCase("marker-refs")) { + // 优先级 + priorityId = getPriorityByElement(element); + }else if (element.getName().equalsIgnoreCase("children")) { + //子节点 + List elementList1 = element.elements(); + for(Element childEle:elementList1) + { + if(childEle.getName().equalsIgnoreCase("topics")) + { + JSONArray jsonArray1 = importDataByXml1(request, childEle, fileName, requests, uploadPath); + if(jsonArray1.size()>0){ + childrenNext.addAll(jsonArray1); + } + } + } + } else { + continue; + } + } + + dataObj.put("created", created); + dataObj.put("id", id); + dataObj.put("image", picPath); // 2021/08/13 + dataObj.put("imageSize", imageSize); // 2021/08/20 + dataObj.put("text", text); + dataObj.put("priority", priorityId); + root.put("data",dataObj); + if(childrenNext.size() != 0) { + root.put("children",childrenNext); + } + jsonArray.add(root); + } + } + return jsonArray; + + } + //根据xml文件获取优先级 private static Integer getPriorityByElement(Element element) { From 98c2900102cac569aacc0a5fe2b5c13041667856 Mon Sep 17 00:00:00 2001 From: yimfeng Date: Sun, 26 Sep 2021 18:07:11 +0800 Subject: [PATCH 2/8] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=92=A4=E9=94=80?= =?UTF-8?q?=E5=92=8C=E6=81=A2=E5=A4=8D=E5=BF=AB=E6=8D=B7=E9=94=AEbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/xiaoju/framework/handler/Room.java | 46 +++++++++++-------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/case-server/src/main/java/com/xiaoju/framework/handler/Room.java b/case-server/src/main/java/com/xiaoju/framework/handler/Room.java index 2f8b2e9..2b9144b 100644 --- a/case-server/src/main/java/com/xiaoju/framework/handler/Room.java +++ b/case-server/src/main/java/com/xiaoju/framework/handler/Room.java @@ -187,32 +187,41 @@ private void internalHandleMessage(Player p, String msg, private void undo() { roomLock.lock(); - undoPosition --; - redoPosition --; - broadcastRoomMessage(CaseMessageType.EDITOR, undoDiffs.get(undoPosition)); - try { - JsonNode target = JsonPatch.apply(jsonMapper.readTree(undoDiffs.get(undoPosition)), jsonMapper.readTree(testCaseContent)); - testCaseContent = target.toString(); - } catch (Exception e) { - roomLock.unlock(); - LOGGER.error("undo json parse error。", e); + if(undoPosition == 0) + LOGGER.error("不能再进行undoPosition操作"); + else{ + undoPosition --; + redoPosition --; + broadcastRoomMessage(CaseMessageType.EDITOR, undoDiffs.get(undoPosition)); + try { + JsonNode target = JsonPatch.apply(jsonMapper.readTree(undoDiffs.get(undoPosition)), jsonMapper.readTree(testCaseContent)); + testCaseContent = target.toString(); + } catch (Exception e) { + roomLock.unlock(); + LOGGER.error("undo json parse error。", e); + } } roomLock.unlock(); } private void redo() { roomLock.lock(); - broadcastRoomMessage(CaseMessageType.EDITOR, redoDiffs.get(redoPosition)); - try { - JsonNode target = JsonPatch.apply(jsonMapper.readTree(redoDiffs.get(undoPosition)), jsonMapper.readTree(testCaseContent)); - testCaseContent = target.toString(); - } catch (Exception e) { - roomLock.unlock(); - LOGGER.error("redo json parse error。", e); + if(redoPosition == undoDiffs.size()) + LOGGER.error("不能再进行redoPosition操作"); + else{ + broadcastRoomMessage(CaseMessageType.EDITOR, redoDiffs.get(redoPosition)); + try { + JsonNode target = JsonPatch.apply(jsonMapper.readTree(redoDiffs.get(undoPosition)), jsonMapper.readTree(testCaseContent)); + testCaseContent = target.toString(); + } catch (Exception e) { + roomLock.unlock(); + LOGGER.error("redo json parse error。", e); + } + + undoPosition ++; + redoPosition ++; } - undoPosition ++; - redoPosition ++; roomLock.unlock(); } @@ -505,4 +514,5 @@ public void sendRoomMessageAsync(String content) { this.getBufferedMessages().add(content); } } + } From 7919adcde8e97139aaa8af0c91b53562bc02c5d1 Mon Sep 17 00:00:00 2001 From: yimfeng Date: Fri, 29 Oct 2021 18:09:27 +0800 Subject: [PATCH 3/8] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E5=B8=A6=E6=9C=89=E5=9B=BE=E7=89=87=E7=9A=84xmind=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/xiaoju/framework/handler/Room.java | 14 +- .../xiaoju/framework/handler/WebSocket.java | 24 +- .../service/impl/FileServiceImpl.java | 54 +++-- .../com/xiaoju/framework/util/TreeUtil.java | 210 ++++++++++++++++-- 4 files changed, 249 insertions(+), 53 deletions(-) diff --git a/case-server/src/main/java/com/xiaoju/framework/handler/Room.java b/case-server/src/main/java/com/xiaoju/framework/handler/Room.java index 2b9144b..df3e5fb 100644 --- a/case-server/src/main/java/com/xiaoju/framework/handler/Room.java +++ b/case-server/src/main/java/com/xiaoju/framework/handler/Room.java @@ -113,6 +113,7 @@ public String getTestCaseContent() { return testCaseContent; } + // 创建并添加一个新用户并进行广播 public Player createAndAddPlayer(Client client) { if (players.size() >= MAX_PLAYER_COUNT) { throw new IllegalStateException("Maximum player count (" @@ -190,10 +191,10 @@ private void undo() { if(undoPosition == 0) LOGGER.error("不能再进行undoPosition操作"); else{ - undoPosition --; - redoPosition --; - broadcastRoomMessage(CaseMessageType.EDITOR, undoDiffs.get(undoPosition)); try { + undoPosition --; + redoPosition --; + broadcastRoomMessage(CaseMessageType.EDITOR, undoDiffs.get(undoPosition)); JsonNode target = JsonPatch.apply(jsonMapper.readTree(undoDiffs.get(undoPosition)), jsonMapper.readTree(testCaseContent)); testCaseContent = target.toString(); } catch (Exception e) { @@ -209,8 +210,8 @@ private void redo() { if(redoPosition == undoDiffs.size()) LOGGER.error("不能再进行redoPosition操作"); else{ - broadcastRoomMessage(CaseMessageType.EDITOR, redoDiffs.get(redoPosition)); try { + broadcastRoomMessage(CaseMessageType.EDITOR, redoDiffs.get(redoPosition)); JsonNode target = JsonPatch.apply(jsonMapper.readTree(redoDiffs.get(undoPosition)), jsonMapper.readTree(testCaseContent)); testCaseContent = target.toString(); } catch (Exception e) { @@ -255,11 +256,10 @@ private void broadcastMessage(String msg) { try { JsonNode request = jsonMapper.readTree(msg.substring(seperateIndex + 1)); ArrayNode patch = (ArrayNode) request.get("patch"); - long currentVersion = ((JsonNode) request.get("case")).get("base").asLong(); - String tmpTestCaseContent = ((JsonNode) request.get("case")).toString().replace("\"base\":" + currentVersion, "\"base\":" + (currentVersion + 1)); + long currentVersion = ((JsonNode) request.get("case")).get("base").asLong(); // 获得当前的Version版本号 + String tmpTestCaseContent = ((JsonNode) request.get("case")).toString().replace("\"base\":" + currentVersion, "\"base\":" + (currentVersion + 1)); // 临时的content在之前的version版本号上+1 ArrayNode patchReverse = (ArrayNode) JsonDiff.asJson(jsonMapper.readTree(tmpTestCaseContent), jsonMapper.readTree(testCaseContent==null?testCase.getCaseContent():testCaseContent), EnumSet.of(ADD_ORIGINAL_VALUE_ON_REPLACE, OMIT_MOVE_OPERATION)); - testCaseContent = tmpTestCaseContent; ArrayNode patchNew = patchTraverse(patch); diff --git a/case-server/src/main/java/com/xiaoju/framework/handler/WebSocket.java b/case-server/src/main/java/com/xiaoju/framework/handler/WebSocket.java index 0f52b6b..19d6b6f 100644 --- a/case-server/src/main/java/com/xiaoju/framework/handler/WebSocket.java +++ b/case-server/src/main/java/com/xiaoju/framework/handler/WebSocket.java @@ -86,10 +86,10 @@ public static Room getRoom(boolean create, long id) { if (rooms.get(id) == null) { synchronized (roomLock) { // TODO: 2021/9/2 此处使用的全局锁,可以优化为局部锁 if (rooms.get(id) == null) { - if (id > Integer.MAX_VALUE) { + if (id > Integer.MAX_VALUE) { // 查看id的大小,如果大于最大值,则表示此id是record,room将recordroom加入 rooms.put(id, new RecordRoom(id)); } else { - rooms.put(id, new CaseRoom(id)); + rooms.put(id, new CaseRoom(id)); // 否则将caseRoom加入到rooms } LOGGER.info(Thread.currentThread().getName() + ": 新建Room成功,caseid=" + BitBaseUtil.getLow32(id) + ", record id: " + BitBaseUtil.getHigh32(id)); } @@ -111,12 +111,14 @@ public void onOpen(@PathParam(value = "caseId") String caseId, this.recordId = recordId; this.isCore = isCore; + // 连基本的任务都不是,直接报错 if (CaseWsMessages.UNDEFINED.getMsg().equals(caseId)) { throw new CaseServerException("用例id为空", StatusCode.WS_UNKNOWN_ERROR); } LOGGER.info(Thread.currentThread().getName() + ": [websocket-onOpen 开启新的session][{}]", toString()); + // 开启新的session,下面是创建新的client,record以及room final Client client = new Client(session, recordId, user); long record = recordId.equals(CaseWsMessages.UNDEFINED.getMsg()) ? 0l : Long.valueOf(recordId); final Room room = getRoom(true, BitBaseUtil.mergeLong(record, Long.valueOf(caseId))); @@ -126,9 +128,9 @@ long record = recordId.equals(CaseWsMessages.UNDEFINED.getMsg()) ? 0l : Long.val public void run() { try { try { - player = room.createAndAddPlayer(client); - if (room.getLock()) { - player.sendRoomMessageAsync("2lock"); + player = room.createAndAddPlayer(client); // 给room添加一个新的client + if (room.getLock()) { // 如果room被锁住了 + player.sendRoomMessageAsync("2lock"); // 异步的发送lock的消息 } LOGGER.info(Thread.currentThread().getName() + ": player " + client.getClientName() + " 加入: " + player); } catch (IllegalStateException e) { @@ -192,17 +194,17 @@ public void run() { char messageType = message.charAt(0); String messageContent = message.substring(1); switch (messageType) { - case '0': // 处理ping/pong消息 - if (messageContent.equals(CaseWsMessages.PING.getMsg())) { + case '0': // 处理ping/pong消息,这个是一直在进行的 + if (messageContent.equals(CaseWsMessages.PING.getMsg())) { // 如果messageContent是ping room.cs.get(session).sendMessage(CaseMessageType.PING, CaseWsMessages.PONG.getMsg()); - } else if (messageContent.equals(CaseWsMessages.PONG.getMsg())) { + } else if (messageContent.equals(CaseWsMessages.PONG.getMsg())) { // 如果messageContent是pong player.clearPingCount(); } else { LOGGER.error(Thread.currentThread().getName() + "ping pong 信息有误。消息是:" + message); } break; - case '1': // 处理编辑消息 + case '1': // 处理编辑消息,包括对信息的编辑以及撤销等操作 LOGGER.info(Thread.currentThread().getName() + ": 收到消息... onMessage: " + message.trim()); if (player != null) { //todo:此处分隔符待优化 @@ -212,7 +214,7 @@ public void run() { } break; - case '2': // 处理控制消息 + case '2': // 处理控制消息,进行对case加锁 LOGGER.info(Thread.currentThread().getName() + ": 收到控制消息... onMessage: " + message.trim()); if (messageContent.equals("lock")) { // lock消息 @@ -281,5 +283,7 @@ public void onError(Session session, Throwable e) { } } + + } diff --git a/case-server/src/main/java/com/xiaoju/framework/service/impl/FileServiceImpl.java b/case-server/src/main/java/com/xiaoju/framework/service/impl/FileServiceImpl.java index 7641af1..821a028 100644 --- a/case-server/src/main/java/com/xiaoju/framework/service/impl/FileServiceImpl.java +++ b/case-server/src/main/java/com/xiaoju/framework/service/impl/FileServiceImpl.java @@ -9,6 +9,7 @@ import com.xiaoju.framework.entity.request.cases.CaseCreateReq; import com.xiaoju.framework.entity.request.cases.FileImportReq; import com.xiaoju.framework.entity.response.cases.ExportXmindResp; +import com.xiaoju.framework.handler.RecordRoom; import com.xiaoju.framework.mapper.TestCaseMapper; import com.xiaoju.framework.service.CaseService; import com.xiaoju.framework.service.FileService; @@ -29,10 +30,7 @@ import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.io.*; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import static com.xiaoju.framework.constants.SystemConstant.POINT; import static com.xiaoju.framework.constants.XmindConstant.*; @@ -46,6 +44,8 @@ @Service public class FileServiceImpl implements FileService { + private static final Logger LOGGER = LoggerFactory.getLogger(FileServiceImpl.class); + @Resource private CaseService caseService; @@ -92,7 +92,8 @@ public Long importXmindFile(FileImportReq req, HttpServletRequest request, Strin // 导入用例 File jsonFile = new File((desc + CONTENT_JSON).replace("/", File.separator)); - CaseCreateReq caseCreateReq = jsonFile.exists() ? buildCaseByJson(req, desc) : buildCaseByXml(req, desc, request, uploadPath); + LOGGER.info("[jsonFile是否存在]" + jsonFile.exists()); + CaseCreateReq caseCreateReq = jsonFile.exists() ? buildCaseByJson(req, desc, request, uploadPath) : buildCaseByXml(req, desc, request, uploadPath); return caseService.insertOrDuplicateCase(caseCreateReq); } throw new CaseServerException("传入的文件名非法", StatusCode.FILE_IMPORT_ERROR); @@ -210,8 +211,6 @@ private Map createFile(Long id) } String path = creteFolder(testCase); // 创建要写入的文件夹 - // 此处需要新加一个文件夹,命名为attachments,里面存放图片 - writeAttachments(path); //写入content.xml内容 writeContentXml(testCase,path); //写Meta文件 @@ -225,18 +224,19 @@ private Map createFile(Long id) return pathMap; } - // 将照片拷贝到path文件夹里面 - private void writeAttachments(String path){ - String targetPath = path + "/attachments"; - - } //拼接xml内容 private void writeContentXml(TestCase testCase,String path){ // 1、创建document对象 Document document = DocumentHelper.createDocument(); // 2、创建根节点root - Element root = document.addElement("xmap-content"); + Element root = document.addElement("xhtml:image") + .addAttribute("xmlns:xhtml", "http://www.w3.org/1999/xhtml") + .addNamespace("fo", "http://www.w3.org/1999/XSL/Format") + .addNamespace("svg", "http://www.w3/org/2000/svg") // 在此处svg:添加命名空间 + .addNamespace("xhtml", "http://www.w3.org/1999/xhtml") // 在此为xhtml:添加命名空间 + .addNamespace("xlink", "http://www.w3.org/1999/xlink"); + // 3、生成子节点及子节点内容 Element sheet = root.addElement("sheet") .addAttribute("id",ZEN_ROOT_VERSION) // 给sheet添加属性id @@ -245,12 +245,12 @@ private void writeContentXml(TestCase testCase,String path){ .addAttribute("timestamp",XMIND_CREATED_VERSION); // 给sheet添加属性timestamp // 获得全部json数据,此时的json数据中有图片的链接地址,需要把image取出来 JSONObject rootObj = JSON.parseObject(testCase.getCaseContent()).getJSONObject(ROOT); - System.out.println("case中的内容:" + testCase.getCaseContent()); + LOGGER.info("case中的内容:" + testCase.getCaseContent()); Element topic = sheet.addElement("topic") // 给sheet添加新的节点topic .addAttribute("id",rootObj.getJSONObject(DATA).getString("id")) // 获得id .addAttribute("modified-by","didi") // 获得用户名 - .addAttribute("timestamp",rootObj.getJSONObject(DATA).getString("created")) // 获得创建时间戳 - .addAttribute("image",rootObj.getJSONObject(DATA).getString("image")); // 新加的,获得图片2021/08/12 + .addAttribute("timestamp",rootObj.getJSONObject(DATA).getString("created")); // 获得创建时间戳 + Element title = topic.addElement("title"); String text = rootObj.getJSONObject(DATA).getString("text"); @@ -261,7 +261,7 @@ private void writeContentXml(TestCase testCase,String path){ } title.setText(text); // 加入标题 // 在xml里面的children添加数据,但是对于图片来说,它的key是image,而不是children - TreeUtil.exportDataToXml(rootObj.getJSONArray("children"), topic); + TreeUtil.exportDataToXml(rootObj.getJSONArray("children"), topic, path); String targetPath = path + "/content.xml"; //写入xml writeXml(targetPath,document); @@ -284,16 +284,27 @@ private String creteFolder(TestCase testCase){ return desPath; } - private CaseCreateReq buildCaseByJson(FileImportReq request, String fileName) { + private CaseCreateReq buildCaseByJson(FileImportReq request, String fileName, HttpServletRequest requests, String uploadPath) throws IOException { // 开始读取文件中的json内容了 String s = FileUtil.readJsonFile(fileName); JSONArray parseArray = JSONObject.parseArray(s); JSONObject getObj = parseArray.getJSONObject(0); JSONObject rootTopic = getObj.getJSONObject("rootTopic"); + String picXml = "resources"; + String picName = (fileName + picXml).replace("/", File.separator); + File file = new File(picName); + // case-content设置 JSONArray jsonArray = new JSONArray(); - TreeUtil.importDataByJson(jsonArray, rootTopic); + if(file.exists()){ + if(file.isDirectory()){ + TreeUtil.importDataByJson1(jsonArray, rootTopic, picName, requests, uploadPath); + } + } + else { + TreeUtil.importDataByJson(jsonArray, rootTopic); + } return buildCaseCreateReq(request, jsonArray); } @@ -321,14 +332,14 @@ public CaseCreateReq buildCaseByXml(FileImportReq request, String fileName, Http // 如果包含图片的文件夹存在,则重写importDataXml方法,将file1添加进去 if(file1.exists()){ if(file1.isDirectory()){ - System.out.println("有图片信息"); + LOGGER.info("有图片信息"); // 此时需要将本地文件传到网上 jsonArray = TreeUtil.importDataByXml1(request, childElement, picName, requests, uploadPath); } } // 如果包含图片的文件夹不存在,则直接调用importDataByXml方法,不需要再传入file1这个参数 else{ - System.out.println("没有图片信息"); + LOGGER.info("没有图片信息"); jsonArray = TreeUtil.importDataByXml(childElement); } @@ -364,4 +375,5 @@ private CaseCreateReq buildCaseCreateReq(FileImportReq request, JSONArray jsonAr testCase.setBizId(request.getBizId()); return testCase; } + } diff --git a/case-server/src/main/java/com/xiaoju/framework/util/TreeUtil.java b/case-server/src/main/java/com/xiaoju/framework/util/TreeUtil.java index 79cd186..88f3b60 100644 --- a/case-server/src/main/java/com/xiaoju/framework/util/TreeUtil.java +++ b/case-server/src/main/java/com/xiaoju/framework/util/TreeUtil.java @@ -4,13 +4,23 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.xiaoju.framework.constants.enums.ProgressEnum; +import com.xiaoju.framework.constants.enums.StatusCode; import com.xiaoju.framework.controller.UploadController; +import com.xiaoju.framework.entity.exception.CaseServerException; import com.xiaoju.framework.entity.request.cases.FileImportReq; import com.xiaoju.framework.entity.xmind.*; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringEscapeUtils; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.ContentType; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.dom4j.Document; +import org.dom4j.DocumentHelper; import org.dom4j.Element; +import org.dom4j.Namespace; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; @@ -19,11 +29,11 @@ import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; +import java.net.HttpURLConnection; +import java.net.URL; import javax.servlet.http.HttpServletRequest; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; +import java.io.*; import java.text.SimpleDateFormat; import java.util.*; @@ -290,26 +300,77 @@ public static void mergeExecRecord(JSONObject caseContent, JSONObject execConten } // 导出json内容到xml - public static void exportDataToXml(JSONArray children, Element rootTopic) { + public static void exportDataToXml(JSONArray children, Element rootTopic, String path){ if(children.size() == 0) return; + + Document document = rootTopic.getDocument(); + LOGGER.info("rootTopic中的内容为: " + rootTopic); + LOGGER.info("document中的内容为:" + document); Element children1 = rootTopic.addElement("children"); Element topics = children1.addElement("topics").addAttribute("type","attached"); for (Object o : children) { JSONObject dataObj = ((JSONObject) o).getJSONObject("data"); + + Element topic = topics.addElement("topic") .addAttribute("id",dataObj.getString("id")) .addAttribute("modified-by","didi") .addAttribute("timestamp",dataObj.getString("created")) - .addAttribute("imageTitle", dataObj.getString("imageTitle")) - .addAttribute("image",dataObj.getString("image")); // 2021/08/13 + .addAttribute("imageTitle", dataObj.getString("imageTitle")); +// .addAttribute("image",dataObj.getString("image")); // 2021/08/13 JSONObject dataObj1 = dataObj.getJSONObject("imageSize"); + String picPath = dataObj.getString("image"); + if(picPath != null && picPath.length() != 0){ + String targetPath = path + "/attachments"; + + // 创建一个新的文件夹 + File file = new File(targetPath); + if(!file.isDirectory()){ + file.mkdir(); + } + try{ + String[] strs = picPath.split("/"); + int size = strs.length; + String fileName = strs[size - 1]; + LOGGER.info("picPath路径为:" + picPath); + LOGGER.info("outfile的内容为:" + file + "/" + fileName); + + if(dataObj1 != null && dataObj1.getString("width") != null){ + LOGGER.info("topic1的内容为:" + topic); + LOGGER.info("dataonj1中有内容, 其中width:" + dataObj1.getString("width") + " ,height:" + dataObj1.getString("height")); + Element imageSize = topic.addElement("xhtml:img") + .addAttribute("svg:height", dataObj1.getString("height")) + .addAttribute("svg:width", dataObj1.getString("width")) + .addAttribute("xhtml:src", "xap:attachments/" + fileName); + + } - if(dataObj1 != null){ - Element imageSize = topic.addElement("imageSize") - .addAttribute("width", dataObj1.getString("width")) - .addAttribute("height", dataObj1.getString("height")); + FileOutputStream outFile = new FileOutputStream(file + "/" + fileName); + URL httpUrl=new URL(picPath); + HttpURLConnection conn=(HttpURLConnection) httpUrl.openConnection(); + //以Post方式提交表单,默认get方式 + conn.setRequestMethod("GET"); + conn.setDoInput(true); + conn.setDoOutput(true); + // post方式不能使用缓存 + conn.setUseCaches(false); + //连接指定的资源 + conn.connect(); + //获取网络输入流 + InputStream inputStream=conn.getInputStream(); + BufferedInputStream bis = new BufferedInputStream(inputStream); + byte b [] = new byte[1024]; + int len = 0; + while((len=bis.read(b))!=-1){ + outFile.write(b, 0, len); + } + LOGGER.info("下载完成..."); + } + catch (Exception e) { + e.printStackTrace(); + } } Element title = topic.addElement("title"); @@ -323,13 +384,13 @@ public static void exportDataToXml(JSONArray children, Element rootTopic) { String priority = getPriorityByJson(dataObj); if(priority != null && !priority.equals("")){ - Element marker_refs = topic.addElement("marker-refs"); + Element marker_refs = topic.addElement("marker-refs"); marker_refs.addElement("marker-ref") .addAttribute("marker-id",priority); } JSONArray childChildren = ((JSONObject) o).getJSONArray("children"); if (childChildren != null && childChildren.size() > 0) { - exportDataToXml(childChildren, topic); + exportDataToXml(childChildren, topic, path); } } } @@ -362,6 +423,90 @@ public static void importDataByJson(JSONArray children, JSONObject rootTopic) { } } + public static void importDataByJson1(JSONArray children, JSONObject rootTopic, String fileName, HttpServletRequest requests, String uploadPath) throws IOException { + String vaildName = fileName; + JSONObject rootObj = new JSONObject(); + JSONObject dataObj = new JSONObject(); + JSONArray childrenNext = new JSONArray(); + dataObj.put("text", rootTopic.getString("title")); + dataObj.put("created", System.currentTimeMillis()); + dataObj.put("id", rootTopic.getString("id")); + if(rootTopic.containsKey("image")){ // 添加imagesize属性 + // 需要将图片传到云空间中,然后将返回的链接导入 + Map imageSize = new HashMap<>(); + imageSize.put("width", "400"); + imageSize.put("height", "184"); + String image = ""; + String picPath = ""; + String path = rootTopic.getJSONObject("image").getString("src"); + String[] strs = path.split("/"); + int len = strs.length; + fileName = fileName + "/"; + image = strs[len-1]; // 此时image为图片所在的本地位置 + // 将文件传入到temp文件下,因此需要将文件进行转换,将file文件类型转化为MultipartFile类型,然后进行上传 + File file = new File(fileName + image); + FileInputStream fileInputStream = new FileInputStream(file); + MultipartFile multipartFile = new MockMultipartFile(file.getName(), file.getName(), + ContentType.APPLICATION_OCTET_STREAM.toString(), fileInputStream); + + // 将MultipartFile文件进行上传 + JSONObject ret = new JSONObject(); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd/"); + String format = sdf.format(new Date()); + File folder = new File(uploadPath + format);// 文件夹的名字 + if (!folder.isDirectory()) { // 如果文件夹为空,则新建文件夹 + folder.mkdirs(); + } + // 对上传的文件重命名,避免文件重名 + String oldName = multipartFile.getOriginalFilename(); // 获取文件的名字 + String newName = UUID.randomUUID().toString() + + oldName.substring(oldName.lastIndexOf("."), oldName.length()); // 生成新的随机的文件名字 + File newFile = new File(folder, newName); + LOGGER.info("newFile的名字为" + newFile); + try { + multipartFile.transferTo(newFile); + // 返回上传文件的访问路径 + // request.getScheme()可获取请求的协议名,request.getServerName()可获取请求的域名,request.getServerPort()可获取请求的端口号 + String filePath = requests.getScheme() + "://" + requests.getServerName() + + ":" + requests.getServerPort() + "/" + format + newName; + LOGGER.info("filepath的路径为:" + filePath); + picPath = filePath; + JSONArray datas = new JSONArray(); + JSONObject data = new JSONObject(); + data.put("url", filePath); + ret.put("success", 1); + datas.add(data); + ret.put("data", datas); + } catch (IOException err) { + LOGGER.error("上传文件失败, 请重试。", err); + ret.put("success", 0); + ret.put("data", ""); + } + dataObj.put("image", picPath); + dataObj.put("imageSize", imageSize); + } + + Integer priority = getPriorityByJsonArray(rootTopic.getJSONArray("markers")); + + if(priority != 0) + { + dataObj.put("priority",priority); + } + + + rootObj.put("data", dataObj); + rootObj.put("children", childrenNext); + if (children != null) { + children.add(rootObj); + } + if (rootTopic.containsKey("children") && rootTopic.getJSONObject("children").containsKey("attached")) { + JSONArray jsonArray = rootTopic.getJSONObject("children").getJSONArray("attached"); + for (int i = 0; i < jsonArray.size(); i++) { + importDataByJson1(childrenNext, (JSONObject) jsonArray.get(i), vaildName, requests, uploadPath); + } + } + } + //导入xml内容 public static JSONArray importDataByXml(Element e) { JSONArray jsonArray = new JSONArray(); @@ -458,7 +603,7 @@ public static JSONArray importDataByXml1(FileImportReq request, Element e, Strin // 获取xml里面的图片大小信息 if(element.getName().equalsIgnoreCase("img")){ // 添加imagesize属性 // 需要将图片传到云空间中,然后将返回的链接导入 - System.out.println("xhtml:img可以使用,其中element中的内容为:" + element); + LOGGER.info("xhtml:img可以使用,其中element中的内容为:" + element); imageSize.put("width", element.attributeValue("width")); imageSize.put("height", element.attributeValue("height")); String path = element.attributeValue("src"); @@ -485,12 +630,14 @@ public static JSONArray importDataByXml1(FileImportReq request, Element e, Strin String newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."), oldName.length()); // 生成新的随机的文件名字 File newFile = new File(folder, newName); + LOGGER.info("newFile的名字为" + newFile); try { - multipartFile.transferTo(new File(folder, newName)); + multipartFile.transferTo(newFile); // 返回上传文件的访问路径 // request.getScheme()可获取请求的协议名,request.getServerName()可获取请求的域名,request.getServerPort()可获取请求的端口号 String filePath = requests.getScheme() + "://" + requests.getServerName() + ":" + requests.getServerPort() + "/" + format + newName; + LOGGER.info("filepath的路径为:" + filePath); picPath = filePath; JSONArray datas = new JSONArray(); JSONObject data = new JSONObject(); @@ -619,5 +766,38 @@ private static Map getAllPriority(){ priorityIds.put("priority-9", 3); return priorityIds; } - + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode() {} + TreeNode(int val) { this.val = val; } + TreeNode(int val, TreeNode left, TreeNode right) { + this.val = val; + this.left = left; + this.right = right; + } + } + public String multiply(String num1, String num2) { + int len1 = num1.length(), len2 = num2.length(); + if(len1 == 0 || num1 == "0" || len2 == 0 || num2 == "0") + return "0"; + int[] ans = new int[len1+len2+1]; + for(int i = len1 - 1; i >= 0; i--){ + for(int j = len2 - 1; j >= 0; j--){ + int val1 = num1.charAt(i) - '0'; + int val2 = num2.charAt(j) - '0'; + int val = val1 * val2 + ans[i+j+1]; + ans[i+j+1] = val % 10; + ans[i+j] += val / 10; + } + } + int left = 0; + while(left < len1 + len2 + 1 && ans[left] == 0) + left++; + StringBuilder str = new StringBuilder(); + for(int i = left; i < len1 + len2; i++) + str.append(ans[i]); + return str.toString(); + } } From 06ba73fdcbe0c974cda551383e965b8cba8dbccc Mon Sep 17 00:00:00 2001 From: yimfeng Date: Tue, 2 Nov 2021 14:41:25 +0800 Subject: [PATCH 4/8] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E5=B8=A6=E6=9C=89=E5=9B=BE=E7=89=87=E7=9A=84xmind=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/FileServiceImpl.java | 28 +--- .../com/xiaoju/framework/util/TreeUtil.java | 149 +----------------- 2 files changed, 11 insertions(+), 166 deletions(-) diff --git a/case-server/src/main/java/com/xiaoju/framework/service/impl/FileServiceImpl.java b/case-server/src/main/java/com/xiaoju/framework/service/impl/FileServiceImpl.java index 821a028..8359c28 100644 --- a/case-server/src/main/java/com/xiaoju/framework/service/impl/FileServiceImpl.java +++ b/case-server/src/main/java/com/xiaoju/framework/service/impl/FileServiceImpl.java @@ -235,7 +235,7 @@ private void writeContentXml(TestCase testCase,String path){ .addNamespace("fo", "http://www.w3.org/1999/XSL/Format") .addNamespace("svg", "http://www.w3/org/2000/svg") // 在此处svg:添加命名空间 .addNamespace("xhtml", "http://www.w3.org/1999/xhtml") // 在此为xhtml:添加命名空间 - .addNamespace("xlink", "http://www.w3.org/1999/xlink"); + .addNamespace("xlink", "http://www.w3.org/1999/xlink"); // 在此为xlink:添加命名空间 // 3、生成子节点及子节点内容 Element sheet = root.addElement("sheet") @@ -293,18 +293,10 @@ private CaseCreateReq buildCaseByJson(FileImportReq request, String fileName, Ht String picXml = "resources"; String picName = (fileName + picXml).replace("/", File.separator); - File file = new File(picName); // case-content设置 JSONArray jsonArray = new JSONArray(); - if(file.exists()){ - if(file.isDirectory()){ - TreeUtil.importDataByJson1(jsonArray, rootTopic, picName, requests, uploadPath); - } - } - else { - TreeUtil.importDataByJson(jsonArray, rootTopic); - } + TreeUtil.importDataByJson(jsonArray, rootTopic, picName, requests, uploadPath); return buildCaseCreateReq(request, jsonArray); } @@ -318,7 +310,6 @@ public CaseCreateReq buildCaseByXml(FileImportReq request, String fileName, Http String picName = (fileName + picXml).replace("/", File.separator); fileName = (fileName + fileXml).replace("/", File.separator); File file = new File(fileName); - File file1 = new File(picName); if(!file.exists()) // 判断文件是否存在 throw new CaseServerException("导入失败,文件不存在", StatusCode.FILE_IMPORT_ERROR); SAXReader reade = new SAXReader(); @@ -329,20 +320,7 @@ public CaseCreateReq buildCaseByXml(FileImportReq request, String fileName, Http String eleName = childElement.getName(); if(eleName.equalsIgnoreCase("sheet")) { - // 如果包含图片的文件夹存在,则重写importDataXml方法,将file1添加进去 - if(file1.exists()){ - if(file1.isDirectory()){ - LOGGER.info("有图片信息"); - // 此时需要将本地文件传到网上 - jsonArray = TreeUtil.importDataByXml1(request, childElement, picName, requests, uploadPath); - } - } - // 如果包含图片的文件夹不存在,则直接调用importDataByXml方法,不需要再传入file1这个参数 - else{ - LOGGER.info("没有图片信息"); - jsonArray = TreeUtil.importDataByXml(childElement); - } - + jsonArray = TreeUtil.importDataByXml(request, childElement, picName, requests, uploadPath); } return buildCaseCreateReq(request, jsonArray); } diff --git a/case-server/src/main/java/com/xiaoju/framework/util/TreeUtil.java b/case-server/src/main/java/com/xiaoju/framework/util/TreeUtil.java index 88f3b60..a873bac 100644 --- a/case-server/src/main/java/com/xiaoju/framework/util/TreeUtil.java +++ b/case-server/src/main/java/com/xiaoju/framework/util/TreeUtil.java @@ -318,7 +318,6 @@ public static void exportDataToXml(JSONArray children, Element rootTopic, String .addAttribute("modified-by","didi") .addAttribute("timestamp",dataObj.getString("created")) .addAttribute("imageTitle", dataObj.getString("imageTitle")); -// .addAttribute("image",dataObj.getString("image")); // 2021/08/13 JSONObject dataObj1 = dataObj.getJSONObject("imageSize"); String picPath = dataObj.getString("image"); @@ -395,35 +394,7 @@ public static void exportDataToXml(JSONArray children, Element rootTopic, String } } - //根据xmind解压的json文件导入xmind内容 - public static void importDataByJson(JSONArray children, JSONObject rootTopic) { - JSONObject rootObj = new JSONObject(); - JSONObject dataObj = new JSONObject(); - JSONArray childrenNext = new JSONArray(); - dataObj.put("text", rootTopic.getString("title")); - dataObj.put("created", System.currentTimeMillis()); - dataObj.put("id", rootTopic.getString("id")); - - Integer priority = getPriorityByJsonArray(rootTopic.getJSONArray("markers")); - - if(priority != 0) - { - dataObj.put("priority",priority); - } - rootObj.put("data", dataObj); - rootObj.put("children", childrenNext); - if (children != null) { - children.add(rootObj); - } - if (rootTopic.containsKey("children") && rootTopic.getJSONObject("children").containsKey("attached")) { - JSONArray jsonArray = rootTopic.getJSONObject("children").getJSONArray("attached"); - for (int i = 0; i < jsonArray.size(); i++) { - importDataByJson(childrenNext, (JSONObject) jsonArray.get(i)); - } - } - } - - public static void importDataByJson1(JSONArray children, JSONObject rootTopic, String fileName, HttpServletRequest requests, String uploadPath) throws IOException { + public static void importDataByJson(JSONArray children, JSONObject rootTopic, String fileName, HttpServletRequest requests, String uploadPath) throws IOException { String vaildName = fileName; JSONObject rootObj = new JSONObject(); JSONObject dataObj = new JSONObject(); @@ -492,8 +463,6 @@ public static void importDataByJson1(JSONArray children, JSONObject rootTopic, S { dataObj.put("priority",priority); } - - rootObj.put("data", dataObj); rootObj.put("children", childrenNext); if (children != null) { @@ -502,83 +471,14 @@ public static void importDataByJson1(JSONArray children, JSONObject rootTopic, S if (rootTopic.containsKey("children") && rootTopic.getJSONObject("children").containsKey("attached")) { JSONArray jsonArray = rootTopic.getJSONObject("children").getJSONArray("attached"); for (int i = 0; i < jsonArray.size(); i++) { - importDataByJson1(childrenNext, (JSONObject) jsonArray.get(i), vaildName, requests, uploadPath); + importDataByJson(childrenNext, (JSONObject) jsonArray.get(i), vaildName, requests, uploadPath); } } } - //导入xml内容 - public static JSONArray importDataByXml(Element e) { - JSONArray jsonArray = new JSONArray(); - List elementList = e.elements(); - if(elementList.size() == 0) - return jsonArray; - for(Element element1:elementList) - { - if(element1.getName().equalsIgnoreCase("topic")) - { - JSONArray childrenNext = new JSONArray(); - JSONObject root = new JSONObject(); - JSONObject dataObj = new JSONObject(); - List newList = element1.elements(); - Map imageSize = new HashMap<>(); - String text = ""; - Integer priorityId = 0; - String created = element1.attributeValue("timestamp"); - String id = element1.attributeValue("id"); - // 2021/08/13 - String image = element1.attributeValue("image"); - String imageTitle = element1.attributeValue("imageTitle"); - - for (Element element : newList) { - if(element.getName().equalsIgnoreCase("imageSize")){ // 添加imagesize属性 - imageSize.put("width", element.attributeValue("width")); - imageSize.put("height", element.attributeValue("height")); - } - else if (element.getName().equalsIgnoreCase("title")) { - //标题 - text = element.getText(); - }else if (element.getName().equalsIgnoreCase("marker-refs")) { - // 优先级 - priorityId = getPriorityByElement(element); - }else if (element.getName().equalsIgnoreCase("children")) { - //子节点 - List elementList1 = element.elements(); - for(Element childEle:elementList1) - { - if(childEle.getName().equalsIgnoreCase("topics")) - { - JSONArray jsonArray1 = importDataByXml(childEle); - if(jsonArray1.size()>0){ - childrenNext.addAll(jsonArray1); - } - } - } - } else { - continue; - } - } - - dataObj.put("created", created); - dataObj.put("id", id); - dataObj.put("image", image); // 2021/08/13 - dataObj.put("imageTitle", imageTitle); // 2021/08/17 - dataObj.put("imageSize", imageSize); // 2021/08/20 - dataObj.put("text", text); - dataObj.put("priority", priorityId); - root.put("data",dataObj); - if(childrenNext.size() != 0) { - root.put("children",childrenNext); - } - jsonArray.add(root); - } - } - return jsonArray; - - } - // 添加一个新的方法,接口中有带有图片的文件夹名属性 - public static JSONArray importDataByXml1(FileImportReq request, Element e, String fileName, HttpServletRequest requests, String uploadPath) throws IOException { + //导入xml内容 + public static JSONArray importDataByXml(FileImportReq request, Element e, String fileName, HttpServletRequest requests, String uploadPath) throws IOException { JSONArray jsonArray = new JSONArray(); List elementList = e.elements(); if(elementList.size() == 0) @@ -651,6 +551,7 @@ public static JSONArray importDataByXml1(FileImportReq request, Element e, Strin ret.put("data", ""); } } + // 获取xml里面中的图片importDataByXml1 else if (element.getName().equalsIgnoreCase("title")) { @@ -666,7 +567,7 @@ else if (element.getName().equalsIgnoreCase("title")) { { if(childEle.getName().equalsIgnoreCase("topics")) { - JSONArray jsonArray1 = importDataByXml1(request, childEle, fileName, requests, uploadPath); + JSONArray jsonArray1 = importDataByXml(request, childEle, fileName, requests, uploadPath); if(jsonArray1.size()>0){ childrenNext.addAll(jsonArray1); } @@ -679,8 +580,8 @@ else if (element.getName().equalsIgnoreCase("title")) { dataObj.put("created", created); dataObj.put("id", id); - dataObj.put("image", picPath); // 2021/08/13 - dataObj.put("imageSize", imageSize); // 2021/08/20 + dataObj.put("image", picPath); + dataObj.put("imageSize", imageSize); dataObj.put("text", text); dataObj.put("priority", priorityId); root.put("data",dataObj); @@ -766,38 +667,4 @@ private static Map getAllPriority(){ priorityIds.put("priority-9", 3); return priorityIds; } - public class TreeNode { - int val; - TreeNode left; - TreeNode right; - TreeNode() {} - TreeNode(int val) { this.val = val; } - TreeNode(int val, TreeNode left, TreeNode right) { - this.val = val; - this.left = left; - this.right = right; - } - } - public String multiply(String num1, String num2) { - int len1 = num1.length(), len2 = num2.length(); - if(len1 == 0 || num1 == "0" || len2 == 0 || num2 == "0") - return "0"; - int[] ans = new int[len1+len2+1]; - for(int i = len1 - 1; i >= 0; i--){ - for(int j = len2 - 1; j >= 0; j--){ - int val1 = num1.charAt(i) - '0'; - int val2 = num2.charAt(j) - '0'; - int val = val1 * val2 + ans[i+j+1]; - ans[i+j+1] = val % 10; - ans[i+j] += val / 10; - } - } - int left = 0; - while(left < len1 + len2 + 1 && ans[left] == 0) - left++; - StringBuilder str = new StringBuilder(); - for(int i = left; i < len1 + len2; i++) - str.append(ans[i]); - return str.toString(); - } } From 645d52d3ebc3e78b931c333e589bfd94d2d4e010 Mon Sep 17 00:00:00 2001 From: yimfeng Date: Tue, 2 Nov 2021 15:45:02 +0800 Subject: [PATCH 5/8] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E5=B8=A6=E6=9C=89=E5=9B=BE=E7=89=87=E7=9A=84xmind=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/xiaoju/framework/handler/Room.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/case-server/src/main/java/com/xiaoju/framework/handler/Room.java b/case-server/src/main/java/com/xiaoju/framework/handler/Room.java index df3e5fb..6458195 100644 --- a/case-server/src/main/java/com/xiaoju/framework/handler/Room.java +++ b/case-server/src/main/java/com/xiaoju/framework/handler/Room.java @@ -113,7 +113,12 @@ public String getTestCaseContent() { return testCaseContent; } + // 创建并添加一个新用户并进行广播 + + public void setTestCaseContent(String content) { + testCaseContent = content; + } public Player createAndAddPlayer(Client client) { if (players.size() >= MAX_PLAYER_COUNT) { throw new IllegalStateException("Maximum player count (" @@ -200,6 +205,7 @@ private void undo() { } catch (Exception e) { roomLock.unlock(); LOGGER.error("undo json parse error。", e); + return; } } roomLock.unlock(); @@ -217,6 +223,7 @@ private void redo() { } catch (Exception e) { roomLock.unlock(); LOGGER.error("redo json parse error。", e); + return; } undoPosition ++; From cede57d9409f88bbfcfffccb26409bbc74c5634f Mon Sep 17 00:00:00 2001 From: yimfeng Date: Tue, 2 Nov 2021 16:24:15 +0800 Subject: [PATCH 6/8] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E5=B8=A6=E6=9C=89=E5=9B=BE=E7=89=87=E7=9A=84xmind=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/xiaoju/framework/handler/Room.java | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/case-server/src/main/java/com/xiaoju/framework/handler/Room.java b/case-server/src/main/java/com/xiaoju/framework/handler/Room.java index 6458195..8f42c24 100644 --- a/case-server/src/main/java/com/xiaoju/framework/handler/Room.java +++ b/case-server/src/main/java/com/xiaoju/framework/handler/Room.java @@ -12,7 +12,6 @@ import com.xiaoju.framework.service.CaseBackupService; import com.xiaoju.framework.service.RecordService; import com.xiaoju.framework.util.BitBaseUtil; -import lombok.extern.flogger.Flogger; import org.apache.poi.util.StringUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,7 +19,6 @@ import javax.websocket.Session; import java.util.*; -import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantLock; @@ -43,7 +41,7 @@ public abstract class Room { private static final int TIMER_DELAY = 30; private TimerTask activeBroadcastTimerTask; - private static final int MAX_PLAYER_COUNT = 100; + private static final int MAX_PLAYER_COUNT = 10; public final List players = new ArrayList<>(); public final List undoDiffs = new LinkedList<>(); @@ -51,6 +49,8 @@ public abstract class Room { private Integer undoPosition; private Integer redoPosition; + protected Integer lastUndoCounts; + public final Map cs = new ConcurrentHashMap<>(); public static TestCaseMapper caseMapper; @@ -93,6 +93,7 @@ public Room(Long id) { } undoPosition = undoDiffs.size(); redoPosition = redoDiffs.size(); + lastUndoCounts = 0; } private TimerTask createBroadcastTimerTask() { @@ -113,12 +114,10 @@ public String getTestCaseContent() { return testCaseContent; } - - // 创建并添加一个新用户并进行广播 - public void setTestCaseContent(String content) { testCaseContent = content; } + public Player createAndAddPlayer(Client client) { if (players.size() >= MAX_PLAYER_COUNT) { throw new IllegalStateException("Maximum player count (" @@ -177,14 +176,16 @@ protected void broadcastRoomMessage(CaseMessageType type, String content) { } private void internalHandleMessage(Player p, String msg, - long msgId) { + long msgId) { p.setLastReceivedMessageId(msgId); //todo: testCase.apply(msg) 新增如上的方法. if (msg.endsWith("undo")) { undo(); + lastUndoCounts ++; } else if (msg.endsWith("redo")) { redo(); + lastUndoCounts --; } else { broadcastMessage(msg); @@ -248,6 +249,12 @@ private void internalHandleCtrlMessage(String msg) { } } + public void leavebroadcastMessageForHttp(String msg) { + for (Player p : players) { + p.getClient().sendMessage(CaseMessageType.EDITOR, msg); + } + } + private void broadcastMessage(String msg) { if (!BUFFER_MESSAGES) { String msgStr = msg.toString(); @@ -398,7 +405,7 @@ public static final class Player { private Integer pingCount; -// private Integer undoPosition; + // private Integer undoPosition; // private Integer redoPosition; private Integer undoCount; private Integer redoCount; From a6bb0b372a670e849c7c52018a9fc1dae0756ba8 Mon Sep 17 00:00:00 2001 From: yimfeng Date: Tue, 2 Nov 2021 17:26:18 +0800 Subject: [PATCH 7/8] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E5=B8=A6=E6=9C=89=E5=9B=BE=E7=89=87=E7=9A=84xmind=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/xiaoju/framework/handler/Room.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/case-server/src/main/java/com/xiaoju/framework/handler/Room.java b/case-server/src/main/java/com/xiaoju/framework/handler/Room.java index 8f42c24..ddeccbc 100644 --- a/case-server/src/main/java/com/xiaoju/framework/handler/Room.java +++ b/case-server/src/main/java/com/xiaoju/framework/handler/Room.java @@ -270,10 +270,11 @@ private void broadcastMessage(String msg) { try { JsonNode request = jsonMapper.readTree(msg.substring(seperateIndex + 1)); ArrayNode patch = (ArrayNode) request.get("patch"); - long currentVersion = ((JsonNode) request.get("case")).get("base").asLong(); // 获得当前的Version版本号 - String tmpTestCaseContent = ((JsonNode) request.get("case")).toString().replace("\"base\":" + currentVersion, "\"base\":" + (currentVersion + 1)); // 临时的content在之前的version版本号上+1 + long currentVersion = ((JsonNode) request.get("case")).get("base").asLong(); + String tmpTestCaseContent = ((JsonNode) request.get("case")).toString().replace("\"base\":" + currentVersion, "\"base\":" + (currentVersion + 1)); ArrayNode patchReverse = (ArrayNode) JsonDiff.asJson(jsonMapper.readTree(tmpTestCaseContent), jsonMapper.readTree(testCaseContent==null?testCase.getCaseContent():testCaseContent), EnumSet.of(ADD_ORIGINAL_VALUE_ON_REPLACE, OMIT_MOVE_OPERATION)); + testCaseContent = tmpTestCaseContent; ArrayNode patchNew = patchTraverse(patch); @@ -528,5 +529,4 @@ public void sendRoomMessageAsync(String content) { this.getBufferedMessages().add(content); } } - } From ec64721f0773cf2951d5a91cdec70c1937ba6396 Mon Sep 17 00:00:00 2001 From: yimfeng Date: Tue, 2 Nov 2021 18:00:42 +0800 Subject: [PATCH 8/8] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E5=B8=A6=E6=9C=89=E5=9B=BE=E7=89=87=E7=9A=84xmind=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/xiaoju/framework/handler/Room.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/case-server/src/main/java/com/xiaoju/framework/handler/Room.java b/case-server/src/main/java/com/xiaoju/framework/handler/Room.java index ddeccbc..808f2d7 100644 --- a/case-server/src/main/java/com/xiaoju/framework/handler/Room.java +++ b/case-server/src/main/java/com/xiaoju/framework/handler/Room.java @@ -251,7 +251,7 @@ private void internalHandleCtrlMessage(String msg) { public void leavebroadcastMessageForHttp(String msg) { for (Player p : players) { - p.getClient().sendMessage(CaseMessageType.EDITOR, msg); + p.getClient().sendMessage(CaseMessageType.EDITOR, msg); } }