一、思路
解析Swagger的接口返回值
使用代码将其转化为Word文档
二、实现
1.封装三个参数类
Table类
@Data public class Table { /** * 配置组 */ private String group; /** * 大标题 */ private String title; /** * 小标题 */ private String tag; /** * url */ private String url; /** * 响应参数格式 */ private String responseForm; /** * 请求方式 */ private String requestType; /** * 请求体 */ private List<Request> requestList; /** * 返回体 */ private List<Response> responseList; /** * 请求参数 */ private String requestParam; /** * 返回值 */ private String responseParam; }
Request类
@Data public class Request { /** * 请求参数 */ private String description; /** * 参数名 */ private String name; /** * 数据类型 */ private String type; /** * 参数类型 */ private String paramType; /** * 是否必填 */ private Boolean require; /** * 说明 */ private String remark; }
Response类
@Data @AllArgsConstructor @NoArgsConstructor public class Response { /** * 返回参数 */ private String description; /** * 参数名 */ private String name; /** * 说明 */ private String remark; }
2.解析swagger的接口返回值
解析接口 ,采用了hutool的HttpUtil进行接口访问,以及alibaba的JOSN
/** * 解析swagger2生成Word接口文档 * */ @GetMapping("/getInterfaceDoc") public void getInterfaceDoc() { // 组 String resp = HttpUtil.get(this.projectPath + "/swagger-resources"); JSONArray groupJsonArray = JSONArray.parseArray(resp); ArrayList<String> groupNames = new ArrayList<>(); for (Object o : groupJsonArray) { JSONObject group = (JSONObject) o; groupNames.add(group.getString("name")); } // 接口信息 JSONArray apiInfos = new JSONArray(); groupNames.forEach(group -> { Map<String, Object> param = new HashMap<>(); param.put("group", group); String result = HttpUtil.get(this.projectPath + "/v2/api-docs", param); JSONObject jsonObject = JSONObject.parseObject(result); jsonObject.put("group",group); apiInfos.add(jsonObject); System.out.println(jsonObject.getString("group")); }); List<Table> tables = dataCollectionUtil.generateInterfaceDoc(apiInfos); test(tables); }/** * 生成接口文档 */ public List<Table> generateInterfaceDoc(JSONArray apiInfos){ List<Table> list = new LinkedList(); for (Object info : apiInfos) { JSONObject api = (JSONObject) info; //解析paths // LinkedHashMap<String, LinkedHashMap> paths = (LinkedHashMap) api.getJSONObject("paths"); String group = api.getString("group"); LinkedHashMap<String, Object> paths = JSON.parseObject(api.getJSONObject("paths").toJSONString(),LinkedHashMap.class, Feature.OrderedField); if (paths != null) { Iterator<Map.Entry<String, Object>> iterator = paths.entrySet().iterator(); while (iterator.hasNext()) { Table table = new Table(); List<Request> requestList = new LinkedList<Request>(); String requestType = ""; Map.Entry<String, Object> next = iterator.next(); //得到url String url = next.getKey(); LinkedHashMap<String, Object> value = JSON.parseObject(next.getValue().toString(),LinkedHashMap.class, Feature.OrderedField); //得到请求方式,输出结果类似为 get/post/delete/put 这样 Set<String> requestTypes = value.keySet(); for (String str : requestTypes) { requestType += str + "/"; } Iterator<Map.Entry<String, Object>> it2 = value.entrySet().iterator(); //解析请求,得到请求类型 Map.Entry<String, Object> get = it2.next(); JSONObject getValue = (JSONObject)get.getValue(); String title = (String) ((List) getValue.get("tags")).get(0);//得到大标题 String tag = String.valueOf(getValue.get("summary")); //请求体 JSONArray parameters = getValue.getJSONArray("parameters"); // ArrayList parameters = (ArrayList) getValue.get("parameters"); if (parameters != null && parameters.size() > 0) { for (int i = 0; i < parameters.size(); i++) { Request request = new Request(); LinkedHashMap<String, Object> param = JSON.parseObject(parameters.get(i).toString(),LinkedHashMap.class, Feature.OrderedField); request.setDescription(String.valueOf(param.get("description"))); request.setName(String.valueOf(param.get("name"))); request.setType(String.valueOf(param.get("type"))); request.setParamType(String.valueOf(param.get("in"))); request.setRequire((Boolean) param.get("required")); requestList.add(request); } } //返回体,比较固定 List<Response> responseList = listResponse(); //模拟一次HTTP请求,封装请求体和返回体,如果是Restful的文档可以再补充 if (requestType.contains("post")) { Map<String, Object> stringStringMap = toPostBody(requestList); table.setRequestParam(stringStringMap.toString()); String post =HttpUtil.post(this.projectPath+ url, stringStringMap); table.setResponseParam(post); } else if (requestType.contains("get")) { String s = toGetHeader(requestList); table.setResponseParam(s); String getStr = HttpUtil.get(this.projectPath + url + s); table.setResponseParam(getStr); } //封装Table table.setGroup(group); table.setTitle(title); table.setUrl(url); table.setTag(tag); table.setResponseForm("application/json"); table.setRequestType(StringUtils.removeEnd(requestType, "/")); table.setRequestList(requestList); table.setResponseList(responseList); list.add(table); } } return list; } return null; } //封装返回信息,可能需求不一样,可以自定义 private List<Response> listResponse() { List<Response> responseList = new LinkedList<Response>(); responseList.add(new Response("受影响的行数", "counts", null)); responseList.add(new Response("结果说明信息", "msg", null)); responseList.add(new Response("是否成功", "success", null)); responseList.add(new Response("返回对象", "data", null)); responseList.add(new Response("错误代码", "errCode", null)); return responseList; } //封装post请求体 private Map<String, Object> toPostBody(List<Request> list) { Map<String, Object> map = new HashMap<>(16); if (list != null && list.size() > 0) { for (Request request : list) { String name = request.getName(); String type = request.getType(); switch (type) { case "string": map.put(name, "string"); break; case "integer": map.put(name, "0"); break; case "double": map.put(name, "0.0"); break; default: map.put(name, "null"); break; } } } return map; } //封装get请求头 private String toGetHeader(List<Request> list) { StringBuffer stringBuffer = new StringBuffer(); if (list != null && list.size() > 0) { for (Request request : list) { String name = request.getName(); String type = request.getType(); switch (type) { case "string": stringBuffer.append(name+"&=string"); break; case "integer": stringBuffer.append(name+"&=0"); break; case "double": stringBuffer.append(name+"&=0.0"); break; default: stringBuffer.append(name+"&=null"); break; } } } String s = stringBuffer.toString(); if ("".equalsIgnoreCase(s)){ return ""; } return "?" + StringUtils.removeStart(s, "&"); }
3.使用代码生成Word文档(没有使用原作者的JSP方法,因为项目中再集成很麻烦)
/** * 生成文档 * @param tables */ private void test(List<Table> tables) { // 创建文档 XWPFDocument document = new XWPFDocument(); // 添加标题 XWPFParagraph titleParagraph = document.createParagraph(); titleParagraph.setAlignment(ParagraphAlignment.CENTER); XWPFRun titleRun = titleParagraph.createRun(); titleRun.setText("后台API接口文档"); titleRun.setBold(true); titleRun.setFontSize(20); // 添加接口信息表格 // 获取接口详细信息数据 // for (int i = 0; i < interfaceList.size(); i++) { // Table table = interfaceList.get(i); createTable(document, tables); // } // 保存文档 try (FileOutputStream fileOutputStream = new FileOutputStream("F:/数据导入/后台API接口文档.docx")) { document.write(fileOutputStream); System.out.println("接口文档生成成功!"); } catch (Exception e) { e.printStackTrace(); } } /** * 在文档中添加一个表格,将接口详细信息填充到表格中 * * @param document 文档对象 */ private XWPFDocument createTable(XWPFDocument document, List<Table> tables) { tables.forEach(table -> { // 添加小标题 XWPFParagraph tagParagraph = document.createParagraph(); XWPFRun run = tagParagraph.createRun(); run.setText(table.getGroup()); run.setBold(true); run.setFontSize(16); // 添加表格 XWPFTable xwpfTable = document.createTable(table.getRequestList().size() + 5, 6); xwpfTable.setWidth("100%"); // 设置表头 setCellText(xwpfTable.getRow(0).getCell(0), table.getTag(),true); setCellText(xwpfTable.getRow(1).getCell(0), "URL"); setCellText(xwpfTable.getRow(2).getCell(0), "请求类型"); setCellText(xwpfTable.getRow(3).getCell(0), "返回值类型"); mergeCellsHorizontal(xwpfTable.getRow(0), 0, 5); setCellText(xwpfTable.getRow(4).getCell(0), "请求参数", true); setCellText(xwpfTable.getRow(4).getCell(1), "参数名", true); setCellText(xwpfTable.getRow(4).getCell(2), "数据类型", true); setCellText(xwpfTable.getRow(4).getCell(3), "参数类型", true); setCellText(xwpfTable.getRow(4).getCell(4), "是否必填", true); setCellText(xwpfTable.getRow(4).getCell(5), "说明", true); // 填充表格内容 mergeCellsHorizontal(xwpfTable.getRow(1), 1, 5); setCellText(xwpfTable.getRow(1).getCell(1), table.getUrl()); mergeCellsHorizontal(xwpfTable.getRow(2), 1, 5); setCellText(xwpfTable.getRow(2).getCell(1), table.getRequestType()); mergeCellsHorizontal(xwpfTable.getRow(3), 1, 5); setCellText(xwpfTable.getRow(3).getCell(1), table.getResponseForm()); for (int i = 0; i < table.getRequestList().size(); i++) { Request request = table.getRequestList().get(i); if (ObjectUtils.isEmpty(request)) { break; } XWPFTableRow row = xwpfTable.getRow(i + 5); setCellText(row.getCell(0), request.getDescription()); setCellText(row.getCell(1), request.getName()); setCellText(row.getCell(2), request.getType()); setCellText(row.getCell(3), request.getParamType()); setCellText(row.getCell(4), request.getRequire() ? "是" : "否"); setCellText(row.getCell(5), request.getRemark()); } // 返回 XWPFTableRow respRow = xwpfTable.createRow(); mergeCellsHorizontal(respRow, 0, 1); mergeCellsHorizontal(respRow, 2, 3); mergeCellsHorizontal(respRow, 4, 5); setCellText(respRow.getCell(0), "返回参数", true); setCellText(respRow.getCell(2), "参数名", true); setCellText(respRow.getCell(4), "说明", true); for (int i = 0; i < table.getResponseList().size(); i++) { Response response = table.getResponseList().get(i); XWPFTableRow dataRow = xwpfTable.createRow(); mergeCellsHorizontal(dataRow, 0, 1); mergeCellsHorizontal(dataRow, 2, 3); mergeCellsHorizontal(dataRow, 4, 5); setCellText(dataRow.getCell(0), response.getDescription()); setCellText(dataRow.getCell(2), response.getName()); setCellText(dataRow.getCell(4), response.getRemark()); } }); return document; } private void setCellText(XWPFTableCell cell, String text) { setCellTextCenterAlignment(cell); XWPFParagraph paragraph = cell.getParagraphs().get(0); XWPFRun run = paragraph.createRun(); run.setText(text); } private void setCellText(XWPFTableCell cell, String text, boolean izBold) { setCellTextCenterAlignment(cell); XWPFParagraph paragraph = cell.getParagraphs().get(0); XWPFRun run = paragraph.createRun(); run.setText(text); // run.setBold(izBold); cell.setColor("5881AF"); } /** * 单元格文字居中 * * @param cell */ private void setCellTextCenterAlignment(XWPFTableCell cell) { List<XWPFParagraph> paragraphs = cell.getParagraphs(); if (paragraphs.isEmpty()) { // 如果单元格中没有段落,则创建一个新的段落对象 XWPFParagraph paragraph = cell.addParagraph(); paragraph.setAlignment(ParagraphAlignment.CENTER); } else { // 否则,获取第一个段落对象并设置对齐方式 XWPFParagraph firstParagraph = paragraphs.get(0); firstParagraph.setAlignment(ParagraphAlignment.CENTER); } }/** * 合并单元格 * * @param row */ public void mergeCellsHorizontal(XWPFTableRow row, int fromCell, int toCell) { for (int cellIndex = fromCell; cellIndex <= toCell; cellIndex++) { XWPFTableCell cell = row.getCell(cellIndex); if (cellIndex == fromCell) { // The first merged cell is set with RESTART merge value cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART); } else { // Cells which join (merge) the first one, are set with CONTINUE cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE); } } }
4.示例
最后通过给某些标签加上目录结构即可