900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > java 转 docx 生成 html 含图片 word公式 wps公式 自动编号 表格

java 转 docx 生成 html 含图片 word公式 wps公式 自动编号 表格

时间:2024-05-20 11:35:29

相关推荐

java 转 docx 生成 html 含图片 word公式 wps公式 自动编号 表格

引言

思路word中的docx是 Office Open XML 标准的文档格式,所以可以通过apache 的poi解析,docx的文档组件在poi中的结构是这样的

第一步处理自动编号和XWPFRun与CTOMath的顺序问题

public static String parseDocxContentToHTML(InputStream input, ImageParse imageParser) throws IOException {if (input == null) {throw new RuntimeException("请输入要转的docx的文件");}StringBuilder content = new StringBuilder();Map<BigInteger, IWordNumber> wordNumberMap = new HashMap<BigInteger, IWordNumber>();XWPFDocument docx = new XWPFDocument(input);// 拿到所有的段落的表格,这两个属于同级无素List<IBodyElement> elements = docx.getBodyElements();for (IBodyElement body : elements) {if (body.getElementType().equals(BodyElementType.PARAGRAPH)) {handleParagraph(content, body, wordNumberMap, imageParser);} else if (body.getElementType().equals(BodyElementType.TABLE)) {handleTable(content, body, wordNumberMap, imageParser);}}return content.toString();}

第二步,分别处理段和表格

private static void handleParagraph(StringBuilder content, IBodyElement body, Map<BigInteger, IWordNumber> wordNumberMap, ImageParse imageParser) {XWPFParagraph p = (XWPFParagraph) body;if (p.isEmpty() || p.isWordWrap() || p.isPageBreak()) {return;}String tagName = "p";content.append("<" + tagName + ">");// 自动编号handleWordNumber(content, wordNumberMap, p);/*XWPFParagraph 有两个方法可以分别提出XWPFRun和CTOMath,但是不知道位置ParagraphChildOrderManager这个类是专门解决这个问题的*/ParagraphChildOrderManager runOrMaths = new ParagraphChildOrderManager(p);List<Object> childList = runOrMaths.getChildList();for (Object child : childList) {if (child instanceof XWPFRun) {handleParagraphRun(content, (XWPFRun) child, imageParser);} else if (child instanceof CTOMath) {handleParagraphOMath(content, (CTOMath) child, imageParser);}}content.append("</" + tagName + ">");}//可以把公式和XWPFRun按顺序遍历,用到了以CTP开头的底层方式,中间也参观了别的人实现,自己改造public class ParagraphChildOrderManager {public static int TYPE_RUN = 1;public static int TYPE_OMATH = 2;List<Integer> typeList = new ArrayList<>();XWPFParagraph p;public ParagraphChildOrderManager(XWPFParagraph paragraph) {this.p = paragraph;List<CTOMathPara> oMathParaList = paragraph.getCTP().getOMathParaList();//using a cursor to go through the paragraph from top to downXmlCursor xmlcursor = paragraph.getCTP().newCursor();while (xmlcursor.hasNextToken()) {XmlCursor.TokenType tokenType = xmlcursor.toNextToken();if (tokenType.isStart()) {if (xmlcursor.getName().getPrefix().equalsIgnoreCase("w") && xmlcursor.getName().getLocalPart().equalsIgnoreCase("r")) {typeList.add(TYPE_RUN);} else if (xmlcursor.getName().getLocalPart().equalsIgnoreCase("oMath")) {typeList.add(TYPE_OMATH);}} else if (tokenType.isEnd()) {xmlcursor.push();xmlcursor.toParent();if (xmlcursor.getName().getLocalPart().equalsIgnoreCase("p")) {break;}xmlcursor.pop();}}}public List<Object> getChildList() {List<Object> runsOrMathList = new ArrayList<>();List<XWPFRun> runs = p.getRuns();List<CTOMath> oMathList = p.getCTP().getOMathList();int totalRuns = runs.size() + oMathList.size();if (typeList.size() != totalRuns) {throw new RuntimeException(" word 文件解析公式有问题,请与管理员联系");}Queue<XWPFRun> runsQueue = new LinkedList<>(runs);Queue<CTOMath> mathQueue = new LinkedList<>(oMathList);for (int i = 0; i < typeList.size(); i++) {Integer type = typeList.get(i);if (type.equals(TYPE_RUN) && runs.size() > 0) {runsOrMathList.add(runsQueue.poll());} else if (type.equals(TYPE_OMATH) && mathQueue.size() > 0) {runsOrMathList.add(mathQueue.poll());}}return runsOrMathList;}}// 处理自动编号的代码如下private static void handleWordNumber(StringBuilder sb, Map<BigInteger, IWordNumber> wordNumberMap, XWPFParagraph p) {String prefix = null;if (wordNumberMap != null && p.getNumID() != null && p.getNumFmt() != null) {IWordNumber wn = wordNumberMap.get(p.getNumID());if (wn != null) {prefix = wn.nextNum();} else {IWordNumber newWordNumber = WordNumberFactory.getWordNumber(p.getNumFmt(), p.getNumLevelText());if (newWordNumber != null) {wordNumberMap.put(p.getNumID(), newWordNumber);prefix = newWordNumber.nextNum();}}}if (StringUtils.isNotBlank(prefix)) {sb.append(prefix);}}// 这里贴了数字和自动编号的实现,虽的类似,我就不贴了public class WordNumberFactory {public static IWordNumber getWordNumber(String numFmt, String numLevelText) {if ("decimal".equals(numFmt)) {return new DecimalNumber(numLevelText);} else if ("upperLetter".equals(numFmt)) {return new UpperLetterNumber(numLevelText);} else if ("japaneseCounting".equals(numFmt)) {return new JapaneseCountingNumber(numLevelText);}return null;}}public class DecimalNumber extends BaseNumber implements IWordNumber {int number = 0;public DecimalNumber(String splitChar) {super(splitChar);}@Overridepublic String nextNum() {number++;return number + this.splitChar;}}public class UpperLetterNumber extends BaseNumber implements IWordNumber {char number = 'A';public UpperLetterNumber(String splitChar) {super(splitChar);}@Overridepublic String nextNum() {String value = number + this.splitChar;number++;return value;}}public class JapaneseCountingNumber extends BaseNumber implements IWordNumber {String[] baseWord = {"十", "一", "二", "三", "四", "五", "六", "七", "八", "九"};String dot = "、";int count = 0;public JapaneseCountingNumber(String splitChar) {super(splitChar);}@Overridepublic String nextNum() {count++;int unit = 0;if (count > 99) {throw new RuntimeException("仅支持100以下的自动编码");}if (count > 19) {int ten = count / 10;unit = count % 10;if (unit == 0) {return baseWord[ten] + "十" + dot;} else {return baseWord[ten] + "十" + baseWord[unit] + dot;}}if (count > 10) {unit = count % 10;return "十" + baseWord[unit] + dot;}unit = count % 10;return baseWord[unit] + dot;}}public class BaseNumber {BigInteger numberId;String fmt;String splitChar = ".";public BaseNumber(String splitChar) {if (splitChar.startsWith("%1")) {this.splitChar = splitChar.replace("%1", "");}}@Overridepublic boolean equals(Object obj) {if (obj == null || this.getClass() != obj.getClass()) return false;BaseNumber bn = (BaseNumber) obj;if (bn.numberId == null || this.numberId == null) return false;if (bn.numberId == this.numberId) {return true;}return false;}@Overridepublic int hashCode() {return numberId == null ? 0 : numberId.hashCode();}}public interface IWordNumber {public String nextNum();}// 结束处理自动编号### 处理XWPFRunprivate static void handleParagraphRun(StringBuilder content, XWPFRun run, ImageParse imageParser) {//char[] runChars = run.toString().toCharArray();// 有内嵌的图片List<XWPFPicture> pics = run.getEmbeddedPictures();if (pics != null && pics.size() > 0) {handleParagraphRunsImage(content, pics, imageParser);} else if (isMath(run)) {// 处理wps的公式图片handleParagraphRunsImageMath(content, run, imageParser);} else {//处理文本handleParagraphRunsWithText(content, run);}}// 处理图片private static void handleParagraphRunsImage(StringBuilder content, List<XWPFPicture> pics, ImageParse imageParser) {for (XWPFPicture pic : pics) {String desc = pic.getDescription();String path = imageParser.parse(pic.getPictureData().getData(),pic.getPictureData().getFileName());log.debug("pic.getPictureData().getFileName()===" + pic.getPictureData().getFileName());CTPicture ctPicture = pic.getCTPicture();Node domNode = ctPicture.getDomNode();Node extNode = getChildChainNode(domNode, "pic:spPr", "a:ext");NamedNodeMap attributes = extNode.getAttributes();if (attributes != null && attributes.getNamedItem("cx") != null) {int width = WordMyUnits.emuToPx(new Double(attributes.getNamedItem("cx").getNodeValue()));int height = WordMyUnits.emuToPx(new Double(attributes.getNamedItem("cy").getNodeValue()));content.append(String.format("<img src=\"%s\" width=\"%d\" height=\"%d\" />", path, width, height));} else {content.append(String.format("<img src=\"%s\" />", path));}}}// 处理wps的内嵌的图片公式,里面有wmf to svg的工具类private static boolean isMath(XWPFRun run) {Node runNode = run.getCTR().getDomNode();Node objectNode = getChildNode(runNode, "w:object");if (objectNode == null) {return false;}Node shapeNode = getChildNode(objectNode, "v:shape");if (shapeNode == null) {return false;}Node imageNode = getChildNode(shapeNode, "v:imagedata");if (imageNode == null) {return false;}Node binNode = getChildNode(objectNode, "o:OLEObject");if (binNode == null) {return false;}return true;}private static void handleParagraphRunsImageMath(StringBuilder content, XWPFRun run, ImageParse imageParser) {Node runNode = run.getCTR().getDomNode();XWPFDocument runDocument = run.getDocument();Node objectNode = getChildNode(runNode, "w:object");if (objectNode == null) {return;}Node shapeNode = getChildNode(objectNode, "v:shape");if (shapeNode == null) {return;}Node imageNode = getChildNode(shapeNode, "v:imagedata");if (imageNode == null) {return;}Node binNode = getChildNode(objectNode, "o:OLEObject");if (binNode == null) {return;}NamedNodeMap shapeAttrs = shapeNode.getAttributes();// 图片在Word中显示的宽高String style = shapeAttrs.getNamedItem("style").getNodeValue();NamedNodeMap imageAttrs = imageNode.getAttributes();// 图片在Word中的IDString imageRid = imageAttrs.getNamedItem("r:id").getNodeValue();// 获取图片信息PackagePart imgPart = runDocument.getPartById(imageRid);// word/media/image4.wmfString fullName = imgPart.getPartName().getName();log.debug("pic.Match.fullName==" + fullName);String extName = imgPart.getPartName().getExtension();Pattern p = pile("\\w+\\." + extName);Matcher matcher = p.matcher(fullName);if (matcher.find()) {fullName = matcher.group(0);}log.debug("pic.Match.name==" + fullName);try {ByteArrayOutputStream out = new ByteArrayOutputStream();WmfUtils.toSvg(imgPart.getInputStream(), out);fullName = fullName.replace(extName, "svg");String path = imageParser.parse(new ByteArrayInputStream(out.toByteArray()), fullName);content.append("<img src=\"" + path + "\" style=\"" + style + "\"/>");} catch (IOException e) {e.printStackTrace();}}// 处理文本的html样式private static void handleParagraphRunsWithText(StringBuilder content, XWPFRun run) {String c = run.toString();c = escapeHtmlTag(c);if (c == null || c.length() == 0) {return;}if (run.getSubscript() != null) {VerticalAlign va = run.getSubscript();if (va.equals(VerticalAlign.SUBSCRIPT)) {c = "<sub>" + c + "</sub>";} else if (va.equals(VerticalAlign.SUPERSCRIPT)) {c = "<sup>" + c + "</sup>";}}if (run.isBold()) {c = "<b>" + c + "</b>";} else if (run.isItalic()) {c = "<i>" + c + "</i>";} else if (run.isStrikeThrough()) {c = "<strike>" + c + "</strike>";}if (run.getUnderline() != null && run.getUnderline() != UnderlinePatterns.NONE) {c = "<span style='text-decoration: underline;'>" + c + "</span>";}if (run.getColor() != null) {c = "<span style='color:#" + run.getColor().toLowerCase() + ";'>" + c + "</span>";}content.append(c);}private static String escapeHtmlTag(String text) {text = text.replace("&", "&amp;");text = text.replace("<", "&lt;");text = text.replace(">", "&gt;");return text;}

段处理完,该公式了 CTOMath,该公式是微软自己的公式

private static void handleParagraphOMath(StringBuilder content, CTOMath child, ImageParse imageParser) {String s = OmmlUtils.convertOmathToPng(child, imageParser);content.append(s);}// omml先转成node,再转成string ,再转成mathML的string,再用第三工具生成图片public class OmmlUtils {/*** 直接转node有等号会出问题,先转成xml的string,再转成mathML的字符串** @param node* @return* @throws IOException* @throws TransformerException*/private static String getMathMLFromNode(Node node) throws IOException, TransformerException {final String xslFile = "/OMML2MML.XSL";StreamSource streamSource = new StreamSource(OmmlUtils.class.getResourceAsStream(xslFile));String s = W3cNodeUtil.node2XmlStr(node);// encoding utf-16String mathML = W3cNodeUtil.xml2Xml(s, streamSource);mathML = mathML.replaceAll("xmlns:m=\"/officeDocument//math\"", "");mathML = mathML.replaceAll("xmlns:mml", "xmlns");mathML = mathML.replaceAll("mml:", "");return mathML;}public static String convertOmathToPng(XmlObject xmlObject, ImageParse imageParser) {Document document = null;try {String mathMLStr = getMathMLFromNode(xmlObject.getDomNode());document = W3cNodeUtil.xmlStr2Node(mathMLStr, "utf-16");return documentToImageHTML(document, imageParser);} catch (IOException e) {e.printStackTrace();} catch (TransformerException e) {e.printStackTrace();}return null;}private static String documentToImageHTML(Document document, ImageParse imageParser) {try {Converter mathMLConvert = Converter.getInstance();LayoutContextImpl localLayoutContextImpl = new LayoutContextImpl(LayoutContextImpl.getDefaultLayoutContext());localLayoutContextImpl.setParameter(Parameter.MATHSIZE, 18);ByteArrayOutputStream os = new ByteArrayOutputStream();mathMLConvert.convert(document, os, "image/png", localLayoutContextImpl);String pngName = imageParser.parse(os.toByteArray(), ".png");os.close();return "<img src=\"" + pngName + "\" align=\"absmiddle\"/>";} catch (IOException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();}return null;}}public class W3cNodeUtil {public static String node2XmlStr(Node node) {Transformer transformer = null;if (node == null) {throw new IllegalArgumentException("node 不能为空..");}try {transformer = TransformerFactory.newInstance().newTransformer();} catch (Exception e) {throw new RuntimeException(e.getMessage());}if (transformer != null) {try {StringWriter sw = new StringWriter();transformer.transform(new DOMSource(node), new StreamResult(sw));return sw.toString();} catch (TransformerException te) {throw new RuntimeException(te.getMessage());}}return null;}public static String xml2Xml(String xml, Source XSLSource) {Transformer transformer = null;if (xml == null) {throw new IllegalArgumentException("node 不能为空..");}try {if (XSLSource == null) {transformer = TransformerFactory.newInstance().newTransformer();} else {transformer = TransformerFactory.newInstance().newTransformer(XSLSource);}} catch (Exception e) {throw new RuntimeException(e.getMessage());}if (transformer != null) {try {Source source = new StreamSource(new StringReader(xml));StringWriter sw = new StringWriter();transformer.transform(source, new StreamResult(sw));return sw.toString();} catch (TransformerException te) {throw new RuntimeException(te.getMessage());}}return null;}public static Document xmlStr2Node(String xmlString, String encoding) {DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();Document doc = null;try {InputStream is = new ByteArrayInputStream(xmlString.getBytes(encoding));doc = dbf.newDocumentBuilder().parse(is);is.close();} catch (Exception e) {e.printStackTrace();}return doc;}private static Node getChildNode(Node node, String nodeName) {if (!node.hasChildNodes()) {return null;}NodeList childNodes = node.getChildNodes();for (int i = 0; i < childNodes.getLength(); i++) {Node childNode = childNodes.item(i);if (nodeName.equals(childNode.getNodeName())) {return childNode;}childNode = getChildNode(childNode, nodeName);if (childNode != null) {return childNode;}}return null;}public static Node getChildChainNode(Node node, String... nodeName) {Node childNode = node;for (int i = 0; i < nodeName.length; i++) {String tmp = nodeName[i];childNode = getChildNode(childNode, tmp);if (childNode == null) {return null;}}return childNode;}}public class WordMyUnits {public static final int EMU_PER_PX = 9525;public static final int emuToPx(double emu) {return (int) (emu/9525);}}

处理表格,表格就容易多了,

// 处理tableprivate static String handleTable(StringBuilder content, IBodyElement body, Map<BigInteger, IWordNumber> wordNumberMap, ImageParse imageParser) {XWPFTable table = (XWPFTable) body;List<XWPFTableRow> rows = table.getRows();content.append("<table class=\"paper-table\">");for (XWPFTableRow row : rows) {content.append("<tr>");List<XWPFTableCell> cells = row.getTableCells();for (XWPFTableCell cell : cells) {content.append("<td>");List<XWPFParagraph> paragraphs = cell.getParagraphs();for (XWPFParagraph paragraph : paragraphs) {handleParagraph(content, paragraph, wordNumberMap, imageParser);}content.append("</td>\n");}content.append("</tr>\n");}content.append("</table>\n");return null;}// 还有一个保存图片到硬盘上的类public class ImageParse {int number = 0;private String targetDir;private String baseUrl;public ImageParse(String targetDir, String baseUrl) {super();this.targetDir = targetDir;this.baseUrl = baseUrl;}public String parse(byte[] data, String extName) {return parse(new ByteArrayInputStream(data), extName);}public String parse(InputStream in, String extName) {if (extName.lastIndexOf(".") > -1) {extName = extName.substring(extName.lastIndexOf(".") + 1);}String filename = "image_" + (number++) + "." + extName;File target = new File(targetDir);if (!target.exists()) {target.mkdirs();}try {IOUtils.copy(in, new FileOutputStream(new File(target, filename)));} catch (IOException e) {e.printStackTrace();}return baseUrl + filename;}}public class WmfUtils {public static void main(String[] args) {String result = convert("D:\\06training\\docx\\image1.wmf");System.out.println(result);}@Deprecatedpublic static String convert2(String path) throws TranscoderException,IOException {String wmfPath = path;File wmf = new File(wmfPath);FileInputStream wmfStream = new FileInputStream(wmf);ByteArrayOutputStream imageOut = new ByteArrayOutputStream();int noOfByteRead = 0;while ((noOfByteRead = wmfStream.read()) != -1) {imageOut.write(noOfByteRead);}imageOut.flush();wmfStream.close();// wmf 转换为svgWMFTranscoder transcoder = new WMFTranscoder();// TranscodingHints hints = new TranscodingHints();// hints.put(WMFTranscoder.KEY_HEIGHT, 1000f);// hints.put(WMFTranscoder.KEY_WIDTH, 1500f);// transcoder.setTranscodingHints(hints);TranscoderInput input = new TranscoderInput(new ByteArrayInputStream(imageOut.toByteArray()));ByteArrayOutputStream svg = new ByteArrayOutputStream();TranscoderOutput output = new TranscoderOutput(svg);transcoder.transcode(input, output);String svgFile = FileExtNameUtils.replace(wmfPath, "wmf", "svg");FileOutputStream fileOut = new FileOutputStream(svgFile);fileOut.write(svg.toByteArray());fileOut.flush();fileOut.close();svg.close();// svg -> jpgImageTranscoder it = new JPEGTranscoder();it.addTranscodingHint(JPEGTranscoder.KEY_QUALITY, 0.5);ByteArrayOutputStream jpg = new ByteArrayOutputStream();it.transcode(new TranscoderInput(new ByteArrayInputStream(svg.toByteArray())), new TranscoderOutput(jpg));String jpgFile = FileExtNameUtils.replace(wmfPath, "wmf", "jpg");FileOutputStream jpgOut = new FileOutputStream(jpgFile);jpgOut.write(jpg.toByteArray());jpgOut.flush();jpgOut.close();jpg.close();// Filor.deleteFile(svgFile);// 删除掉中间文件return jpgFile;}public static String convert(String path) {try {String svgFile = FileExtNameUtils.replace(path, "wmf", "svg");wmfToSvg(path, svgFile);String jpgFile = FileExtNameUtils.replace(path, "wmf", "png");svgToJpg(svgFile, jpgFile);return jpgFile;} catch (Exception e) {e.printStackTrace();}return null;}/*** 将svg转化为JPG** @param src* @param dest*/public static String svgToJpg(String src, String dest) {FileOutputStream jpgOut = null;FileInputStream svgStream = null;ByteArrayOutputStream svgOut = null;ByteArrayInputStream svgInputStream = null;ByteArrayOutputStream jpg = null;try {// 获取到svg文件File svg = new File(src);svgStream = new FileInputStream(svg);svgOut = new ByteArrayOutputStream();// 获取到svg的streamint noOfByteRead = 0;while ((noOfByteRead = svgStream.read()) != -1) {svgOut.write(noOfByteRead);}JPEGTranscoder it = new JPEGTranscoder();it.addTranscodingHint(JPEGTranscoder.KEY_QUALITY, (float) 1);it.addTranscodingHint(ImageTranscoder.KEY_WIDTH, 200f);jpg = new ByteArrayOutputStream();svgInputStream = new ByteArrayInputStream(svgOut.toByteArray());it.transcode(new TranscoderInput(svgInputStream),new TranscoderOutput(jpg));jpgOut = new FileOutputStream(dest);jpgOut.write(jpg.toByteArray());} catch (Exception e) {e.printStackTrace();} finally {try {if (svgInputStream != null) {svgInputStream.close();}if (jpg != null) {jpg.close();}if (svgStream != null) {svgStream.close();}if (svgOut != null) {svgOut.close();}if (jpgOut != null) {jpgOut.flush();jpgOut.close();}} catch (IOException e) {e.printStackTrace();}}return dest;}public static void toSvg(InputStream in, OutputStream out) {try {WmfParser parser = new WmfParser();final SvgGdi gdi = new SvgGdi(false);parser.parse(in, gdi);Document doc = gdi.getDocument();//OutputStream out = new FileOutputStream(dest);//if (dest.endsWith(".svgz")) {// out = new GZIPOutputStream(out);// }output(doc, out);} catch (Exception e) {e.printStackTrace();}}/*** 将wmf转换为svg** @param src* @param dest*/public static void wmfToSvg(String src, String dest) {InputStream in = null;OutputStream out = null;try {in = new FileInputStream(src);out = new FileOutputStream(dest);} catch (FileNotFoundException e) {e.printStackTrace();}toSvg(in, out);}private static void output(Document doc, OutputStream out) throws Exception {TransformerFactory factory = TransformerFactory.newInstance();Transformer transformer = factory.newTransformer();transformer.setOutputProperty(OutputKeys.METHOD, "xml");transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");transformer.setOutputProperty(OutputKeys.INDENT, "yes");transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC,"-//W3C//DTD SVG 1.0//EN");transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,"/TR/2001/REC-SVG-20010904/DTD/svg10.dtd");transformer.transform(new DOMSource(doc), new StreamResult(out));out.flush();out.close();}}public class FileExtNameUtils {public static String replace(String wmfPath, String wmf, String jpg) {int index = wmfPath.lastIndexOf("wmf");if (index > -1) {return wmfPath.substring(0, index) + jpg + wmfPath.substring(index + 3);}return wmfPath;}}

用到的jar包

<dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>3.17</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>3.17</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml-schemas</artifactId><version>3.17</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>ooxml-schemas</artifactId><version>1.3</version></dependency><dependency><groupId>net.arnx</groupId><artifactId>wmf2svg</artifactId><version>0.9.8</version></dependency><dependency><groupId>org.apache.xmlgraphics</groupId><artifactId>batik-codec</artifactId><version>1.7</version></dependency><dependency><groupId>net.sourceforge.jeuclid</groupId><artifactId>jeuclid-core</artifactId><version>3.1.9</version></dependency><dependency><groupId>mons</groupId><artifactId>commons-lang3</artifactId><version>3.9</version></dependency>

中间也参观了好多网站,就不一一列出来了,当时找的也是晕头转向的,最后整理也是相当费时间

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。