前言(背景介绍):
Apache POI是Apache基金会下一个开源的项目,用来处理office系列的文档,能够创建和解析word、excel、ppt格式的文档。

其中对word文档的处理有两个技术,分别是HWPF(.doc)和XWPF(.docx)。如果你对这两个技术熟悉的话,就应该能明白使用java解析word文档的痛楚所在。

其中两个最大的问题在于:

第一是这两个类并没有统一的父类和接口(隔壁的XSSF和HSSF投过来鄙视的眼光),所以没法进行同一格式的接口式编程;

第二是官方API中并没有文档中图片相对位置的接口,这就导致了虽然你能获得文档中的所有图片,但是你并不能知道这些图片是在哪里,将来要展示图片就没法插入到正确的位置。

对于第一点,我是没什么办法,可以研究下其他相关技术,比如jacob,doc4j等看看有没有其他的解决方案,不过doc4j这货貌似只能处理2007文档(.docx)。

对于第二点,本文将给出笔者的解决方案,实际上,这也是我写本文的目的所在。

注意:简单求快的同学看第二章和第三章就行了;

一、预备知识

1.word文档的两种格式对应两种不同的存储方式

众所周知,word文档有两种存储格式:doc和docx

doc:习惯上称为Word2003,使用二进制储存数据;这个不是我们今天讨论的重点.

docx:word2007,使用xml来存储数据和格式.

可能你会问了,明明是docx结尾的文档,怎么成了xml格式了?

很简单:你随便选择一个docx文件,右键使用压缩工具打开,就能得到一个这样的目录结构:

所以你以为docx是一个完整的文档,其实它只是一个压缩文件。(docx:?_?)

2.Word文档中xml的定义格式:

从前面我们知道了docx文档使用压缩文件也就是xml来描述数据,那么word文档中的数据具体是怎么定义的呢?

出于篇幅的关系,这里不会详细地描述整个压缩的文档,这里只简单介绍下两个文件/文件夹:

一是word目录下的documen.xml文件,这个就是整个文档内容的定义;

二是word目录下的media文件夹,看名字也能猜出来这个文件夹里面是文档中的多媒体内容:

                                            图3:word/document.xml(定义文档内容)                                     图4:word/media文件夹下的内容

以下是document.xml文档的部分关键内容:

A:document整体结构定义:

  1. <w:document mc:ignorable="w14 w15 wp14" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" xmlns:wpscustomdata="http://www.wps.cn/officeDocument/2013/wpsCustomData">
  2. <w:body>
  3. <w:p>
  4. <w:ppr>
  5. <w:pstyle w:val="2">
  6. </w:pstyle>
  7. <w:keepnext w:val="0">
  8. </w:keepnext>
  9. <w:keeplines w:val="0">
  10. </w:keeplines>
  11. <w:widowcontrol>
  12. </w:widowcontrol>
  13. <w:suppresslinenumbers w:val="0">
  14. </w:suppresslinenumbers>
  15. <w:pbdr>
  16. <w:top w:color="auto" w:space="0" w:sz="0" w:val="none">
  17. </w:top>
  18. <w:left w:color="auto" w:space="0" w:sz="0" w:val="none">
  19. </w:left>
  20. <w:bottom w:color="auto" w:space="0" w:sz="0" w:val="none">
  21. </w:bottom>
  22. <w:right w:color="auto" w:space="0" w:sz="0" w:val="none">
  23. </w:right>
  24. </w:pbdr>

B:文档段落内容:

  1. <w:p>
  2. <w:ppr>
  3. <w:pstyle w:val="2">
  4. </w:pstyle>
  5. <w:keepnext w:val="0">
  6. </w:keepnext>
  7. <w:keeplines w:val="0">
  8. </w:keeplines>
  9. <w:widowcontrol>
  10. </w:widowcontrol>
  11. <w:suppresslinenumbers w:val="0">
  12. </w:suppresslinenumbers>
  13. <w:pbdr>
  14. <w:top w:color="auto" w:space="0" w:sz="0" w:val="none">
  15. </w:top>
  16. <w:left w:color="auto" w:space="0" w:sz="0" w:val="none">
  17. </w:left>
  18. <w:bottom w:color="auto" w:space="0" w:sz="0" w:val="none">
  19. </w:bottom>
  20. <w:right w:color="auto" w:space="0" w:sz="0" w:val="none">
  21. </w:right>
  22. </w:pbdr>
  23. <w:shd w:fill="FAFAFA" w:val="clear">
  24. </w:shd>
  25. <w:spacing w:after="150" w:afterautospacing="0" w:before="150" w:beforeautospacing="0" w:line="378" w:linerule="atLeast">
  26. </w:spacing>
  27. <w:ind w:firstline="0" w:left="0" w:right="0">
  28. </w:ind>
  29. <w:rpr>
  30. <w:rfonts w:ascii="Verdana" w:cs="Verdana" w:hansi="Verdana" w:hint="default">
  31. </w:rfonts>
  32. <w:i w:val="0">
  33. </w:i>
  34. <w:caps w:val="0">
  35. </w:caps>
  36. <w:color w:val="404040">
  37. </w:color>
  38. <w:spacing w:val="0">
  39. </w:spacing>
  40. <w:sz w:val="21">
  41. </w:sz>
  42. <w:szcs w:val="21">
  43. </w:szcs>
  44. </w:rpr>
  45. </w:ppr>
  46. <w:r>
  47. <w:rpr>
  48. <w:rfonts w:ascii="Verdana" w:cs="Verdana" w:hansi="Verdana" w:hint="default">
  49. </w:rfonts>
  50. <w:i w:val="0">
  51. </w:i>
  52. <w:caps w:val="0">
  53. </w:caps>
  54. <w:color w:val="404040">
  55. </w:color>
  56. <w:spacing w:val="0">
  57. </w:spacing>
  58. <w:sz w:val="21">
  59. </w:sz>
  60. <w:szcs w:val="21">
  61. </w:szcs>
  62. <w:bdr w:color="auto" w:space="0" w:sz="0" w:val="none">
  63. </w:bdr>
  64. <w:shd w:fill="FAFAFA" w:val="clear">
  65. </w:shd>
  66. </w:rpr>
  67. <w:t>
  68. 作者: Brian Dear
  69. </w:t>
  70. </w:r>
  71. </w:p>

C:图片内容定义:

  1. <w:r>
  2. <w:rpr>
  3. <w:rfonts w:ascii="Verdana" w:cs="Verdana" w:hansi="Verdana" w:hint="default">
  4. </w:rfonts>
  5. <w:i w:val="0">
  6. </w:i>
  7. <w:caps w:val="0">
  8. </w:caps>
  9. <w:color w:val="404040">
  10. </w:color>
  11. <w:spacing w:val="0">
  12. </w:spacing>
  13. <w:sz w:val="21">
  14. </w:sz>
  15. <w:szcs w:val="21">
  16. </w:szcs>
  17. <w:bdr w:color="auto" w:space="0" w:sz="0" w:val="none">
  18. </w:bdr>
  19. <w:shd w:fill="FAFAFA" w:val="clear">
  20. </w:shd>
  21. </w:rpr>
  22. <w:drawing>
  23. <wp:inline distb="0" distl="114300" distr="114300" distt="0">
  24. <wp:extent cx="5543550" cy="5543550">
  25. </wp:extent>
  26. <wp:effectextent b="0" l="0" r="0" t="0">
  27. </wp:effectextent>
  28. <wp:docpr descr="IMG_256" id="1" name="Picture 1">
  29. </wp:docpr>
  30. <wp:cnvgraphicframepr>
  31. <a:graphicframelocks nochangeaspect="1" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
  32. </a:graphicframelocks>
  33. </wp:cnvgraphicframepr>
  34. <a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
  35. <a:graphicdata uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
  36. <pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
  37. <pic:nvpicpr>
  38. <pic:cnvpr descr="IMG_256" id="1" name="Picture 1">
  39. </pic:cnvpr>
  40. <pic:cnvpicpr>
  41. <a:piclocks nochangeaspect="1">
  42. </a:piclocks>
  43. </pic:cnvpicpr>
  44. </pic:nvpicpr>
  45. <pic:blipfill>
  46. <a:blip r:embed="rId4">
  47. </a:blip>
  48. <a:stretch>
  49. <a:fillrect>
  50. </a:fillrect>
  51. </a:stretch>
  52. </pic:blipfill>
  53. <pic:sppr>
  54. <a:xfrm>
  55. <a:off x="0" y="0">
  56. </a:off>
  57. <a:ext cx="5543550" cy="5543550">
  58. </a:ext>
  59. </a:xfrm>
  60. <a:prstgeom prst="rect">
  61. <a:avlst>
  62. </a:avlst>
  63. </a:prstgeom>
  64. <a:nofill>
  65. </a:nofill>
  66. <a:ln w="9525">
  67. <a:nofill>
  68. </a:nofill>
  69. </a:ln>
  70. </pic:sppr>
  71. </pic:pic>
  72. </a:graphicdata>
  73. </a:graphic>
  74. </wp:inline>
  75. </w:drawing>
  76. </w:r>

有兴趣的童鞋可以看一下上面三段xml代码,我这里直接给结论了:

  word文档shema文件:xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"

文档根节点:<w:document> 定义了整个文档的开始

         <w:body>是document的子节点,文档的主体内容

          <w:p>body子节点,一个段落,就是word文档中的段落

            <w:r>P元素的子节点,一个Run定义了段落中具有相同格式的一段内容

              <w:t>Run元素节点的子节点,就是文档的内容.

              <w:drawing> run元素的子节点,定义了一张图片:

                <w:inline> drawing子节点,具体应用也没有深入研究

                <a:graphic> 定义图片内容

                  <pic:blipfill>这个是graphic文档的子节点,定义了图片内容的索引,具体来说,poi能根据这个名称拿到图片所对应的资源,而获取文档图片位置的关键也就在这里

 

总体看来:XWPF解析docx文档就是做了xml文档的解析,将所有的节点保存下来,然后转换成更加好用的属性,提供API出来供用户使用.

所以我们就能用POI提供给我们的接口拿到文档内容,自己去解析文档中的数据,就能获取到图片是在哪一个段落里了,当然你也可以得知图片是位于哪一个Run元素的后面.

二、实现

  1. package com.szdfhx.reportStatistic.util;
  2. import com.microsoft.schemas.vml.CTShape;
  3. import org.apache.poi.xwpf.usermodel.XWPFParagraph;
  4. import org.apache.poi.xwpf.usermodel.XWPFPictureData;
  5. import org.apache.poi.xwpf.usermodel.XWPFRun;
  6. import org.apache.xmlbeans.XmlCursor;
  7. import org.apache.xmlbeans.XmlObject;
  8. import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObject;
  9. import org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture;
  10. import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;
  11. import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDrawing;
  12. import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTObject;
  13. import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR;
  14.  
  15. import java.util.ArrayList;
  16. import java.util.List;
  17. import java.util.Map;
  18.  
  19. public class XWPFUtils {
  20.  
  21. //获取某一个段落中的所有图片索引
  22. public static List<String> readImageInParagraph(XWPFParagraph paragraph) {
  23. //图片索引List
  24. List<String> imageBundleList = new ArrayList<String>();
  25.  
  26. //段落中所有XWPFRun
  27. List<XWPFRun> runList = paragraph.getRuns();
  28. for (XWPFRun run : runList) {
  29. //XWPFRun是POI对xml元素解析后生成的自己的属性,无法通过xml解析,需要先转化成CTR
  30. CTR ctr = run.getCTR();
  31.  
  32. //对子元素进行遍历
  33. XmlCursor c = ctr.newCursor();
  34. //这个就是拿到所有的子元素:
  35. c.selectPath("./*");
  36. while (c.toNextSelection()) {
  37. XmlObject o = c.getObject();
  38. //如果子元素是<w:drawing>这样的形式,使用CTDrawing保存图片
  39. if (o instanceof CTDrawing) {
  40. CTDrawing drawing = (CTDrawing) o;
  41. CTInline[] ctInlines = drawing.getInlineArray();
  42. for (CTInline ctInline : ctInlines) {
  43. CTGraphicalObject graphic = ctInline.getGraphic();
  44. //
  45. XmlCursor cursor = graphic.getGraphicData().newCursor();
  46. cursor.selectPath("./*");
  47. while (cursor.toNextSelection()) {
  48. XmlObject xmlObject = cursor.getObject();
                    // 如果子元素是<pic:pic>这样的形式
  49. if (xmlObject instanceof CTPicture) {
  50. org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture picture = (org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture) xmlObject;
  51. //拿到元素的属性
  52. imageBundleList.add(picture.getBlipFill().getBlip().getEmbed());
  53. }
  54. }
  55. }
  56. }
  57. //使用CTObject保存图片
              //<w:object>形式
  58. if (o instanceof CTObject) {
  59. CTObject object = (CTObject) o;
  60. System.out.println(object);
  61. XmlCursor w = object.newCursor();
  62. w.selectPath("./*");
  63. while (w.toNextSelection()) {
  64. XmlObject xmlObject = w.getObject();
  65. if (xmlObject instanceof CTShape) {
  66. CTShape shape = (CTShape) xmlObject;
  67. imageBundleList.add(shape.getImagedataArray()[0].getId2());
  68. }
  69. }
  70. }
  71. }
  72. }
  73. return imageBundleList;
  74. }
  75.  
  76. }

首先要提出来是XWPF对xml元素的封装:

<w:document> 对应XWPFDocument类

<w:run>对应XWPFRun类

基本上只对应到Run这一层,因为run的子元素有很多,所以没有再往下面的层次封装和定义了,

所以我们使用API只能拿到所有的XWPFRun对象转成它的xml的定义:CTR对象。最后利用CTR去读取和解析的Run元素中的内容,获取图片的索引。

其次要谈的则是整个XML元素的定义:

我们可以看到POI使用的是Apache下的xmlbeans这个技术解析的XML,相关的技术不做深谈,关键要明白两点:

1:xml文档中的所有元素经过xmlbean是封装后都继承了一个XMLObject的接口,所以可以用这个类来接收获取到的子元素;

2:元素遍历是通过XmlCursor来做的,具体获取子元素是根据XmlCursor对象的selectPath属性来控制,当selectPath为"./*"时就定义为遍历子元素;

所以写成了如下的代码:能遍历当前元素的子元素,并且检验子元素的类型:

  1.          
  1. CTR ctr = run.getCTR();
  2.  
  3. //对子元素进行遍历
  4. XmlCursor c = ctr.newCursor();
  5. //这个就是拿到所有的子元素:
  6. c.selectPath("./*");
  7. while (c.toNextSelection()) {
  8. XmlObject o = c.getObject();
  9. //如果子元素是<w:drawing>这样的形式,使用CTDrawing保存图片
  10. if (o instanceof CTDrawing) {
  11. CTDrawing drawing = (CTDrawing) o;
  1.  

最后你可能会有疑问,不是说<w:drawing>这个元素定义了一张图片吗?

那么

  1. if (o instanceof CTObject) {
  2. CTObject object = (CTObject) o;
    ...
    }

这个第二个判断条件是用来干嘛的?

聪明的你应该已经猜到了

没错!docx文档中的xml定义图片的方式除了<w:drawing>这一种之外,还可以运用<w:object>元素去定义,

为什么只有这两种?

因为我只使用第一种方式解析,发现有些图片丢失了,于是发现了第二种方式.......也许不止两种?我也不知道,反正对于目前的我来说已经没有问题了.

或许聪明的你在实践中还遇到了更多种情况?

那么运用上面提到的xml解析方式,相信你也能正确读取,得到自己想要的索引值.

再拓宽一点,如果POI还有其他没有提供的API,我们是不是也能通过XML解析的技术自己实现呢?这个就需要我们在实践中去探索了,相信时间会给我们答案

好了,现在我们拿到了索引值,那么如何去拿到图片资源呢?

POI提供了现成的方法:

XWPFDocument类中有getPictureDataByID(String picture);方法可以拿到XWPFPictrueDate对象,这个就是图片的资源了.

具体的操作可以参阅相关的博文和API,这里就不详细介绍了.

三、测试:

使用Junit4测试的代码:

  1. package com.szdfhx.reportStatistic.util;
  2.  
  3. import org.apache.commons.collections.CollectionUtils;
  4. import org.apache.commons.lang.StringUtils;
  5. import org.apache.poi.xwpf.usermodel.XWPFDocument;
  6. import org.apache.poi.xwpf.usermodel.XWPFParagraph;
  7. import org.apache.poi.xwpf.usermodel.XWPFPictureData;
  8. import org.junit.Test;
  9.  
  10. import java.io.FileInputStream;
  11. import java.io.IOException;
  12. import java.io.InputStream;
  13. import java.util.Collections;
  14. import java.util.List;
  15.  
  16. import static org.junit.Assert.*;
  17.  
  18. public class XWPFUtilsTest {
  19.  
  20. @Test
  21. public void readImageInParagraph() throws IOException {
  22. InputStream in = new FileInputStream("D:\\Document\\我的博客\\Java解析word,获取文档中图片位置\\示例.docx");
  23. XWPFDocument xwpfDocument = new XWPFDocument(in);
  24. List<XWPFParagraph> paragraphList = xwpfDocument.getParagraphs();
  25. System.out.println("图片的索引\t|图片名称\t|图片上一段文字的内容\t");
  26. System.out.pringln("------------------------------------------");
  27. for(int i = 0;i < paragraphList.size();i++){
  28. List<String> imageBundleList = XWPFUtils.readImageInParagraph(paragraphList.get(i));
  29. if(CollectionUtils.isNotEmpty(imageBundleList)){
  30. for(String pictureId:imageBundleList){
  31. XWPFPictureData pictureData = xwpfDocument.getPictureDataByID(pictureId);
  32. String imageName = pictureData.getFileName();
  33. String lastParagraphText = paragraphList.get(i-1).getParagraphText();
  34. System.out.println(pictureId +"\t|" + imageName + "\t|" + lastParagraphText);
  35. }
  36. }
  37. }
  38. }
  39.  
  40. }

展示结果:

这里使用图片名称指代表明我拿到了对应的资源,实际上 如果你对前文的内容还熟悉的话,会发现图片的名称实际上就是word/media文件夹下的所有图片的全名称。

在对应的XWPFPictureData对象中,图像的二进制数据可以通过getData()属性来拿到,这样你就可以保存到数据库或者是你本地的文件夹中了!

四、其他:

谈到这里,开头提到的第二个问题这里就已经解决了。

那么,第一个问题怎么办呢?

如果你的系统对速度要求不高的话,那么我给你的建议是,把doc文档转化成docx文档来解析--POI就有成熟的API来做

如果要考虑性能的话,那就只好写两套方法去解析文档。

那么......doc类型的word文档怎么获取图片的相对位置呢?

我也不知道········或者,你来告诉我?


参考:

POI官网:https://poi.apache.org/

Apache POI Word - 快速指南 :https://www.w3cschool.cn/apache_poi_word/apache_poi_word_quick_guide.html

Java解析word,获取文档中图片位置的更多相关文章

  1. php解析word,获得文档中的图片

    背景 前段时间在写一个功能:用原生php将获得word中的内容并导入到网站系统中.因为文档中存在公式,图片,表格等,因此写的比较麻烦. 思路 大体思路是先将word中格式为doc的文档转化为docx, ...

  2. java POI往word文档中指定位置插入表格

    1.Service  demo import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.a ...

  3. jquery获取元素在文档中的位置信息以及滚动条位置(转)

    jquery获取元素在文档中的位置信息以及滚动条位置 http://blog.csdn.net/qq_34095777/article/details/78750886     原文链接 原创 201 ...

  4. javaScript获取文档中所有元素节点的个数

    HTML+JS 代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset=&qu ...

  5. html中如何获取元素在文档中的位置

    html中如何获取元素在文档中的位置 一.总结 一句话总结: $("#elem").offset().top $("#elem").offset().left ...

  6. dom4j解析xml报"文档中根元素后面的标记格式必须正确"

    今天,在写个批量启动报盘机的自动化应用,为了简化起见,将配置信息存储在xml中,格式如下: <?xml version="1.0" encoding="UTF-8& ...

  7. 使用compareDocumentPosition比较两个元素在文档中的位置

    PS:尊重原创,转载请注明来自http://www.cnblogs.com/Raoh/p/js_compareDocumentPosition_between_two_node.html 使用comp ...

  8. 可以粘贴Word文档中图片的编辑器

    Chrome+IE默认支持粘贴剪切板中的图片,但是我要发布的文章存在word里面,图片多达数十张,我总不能一张一张复制吧?Chrome高版本提供了可以将单张图片转换在BASE64字符串的功能.但是无法 ...

  9. Java POI Word 写文档

    package apache.poi; import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import ...

随机推荐

  1. 算法帖——用舞蹈链算法(Dancing Links)求解俄罗斯方块覆盖问题

    问题的提出:如下图,用13块俄罗斯方块覆盖8*8的正方形.如何用计算机求解? 解决这类问题的方法不一而足,然而核心思想都是穷举法,不同的方法仅仅是对穷举法进行了优化 用13块不同形状的俄罗斯方块(每个 ...

  2. viewer.js的简单练习

    html <!DOCTYPE html><html><head lang="en"> <meta charset="UTF-8& ...

  3. 在Github发布自己的compile包

    Android入门到转行做服务员--在Github发布自己的compile包 2017-12-05 15:27:10 这是一粒代码发布的第一篇博客,一粒代码从事android开发,近期打算开始搞搞博客 ...

  4. accept 文件描述符用尽处理

    if (events[i].data.fd == listenfd) { peerlen = sizeof(peeraddr); connfd = ::accept4(listenfd, (struc ...

  5. js实现关键词高亮显示 正则匹配

    html 和ajax 部分就不写了,只需将需要匹配的文字传进去就可以了 比如匹配后台传回的字符串data.content中的关键词:直接调用: data.content = highLightKeyw ...

  6. PHP通过ZABBIX API获取主机信息 VS 直接从数据库获取主机信息

    最近项目需要获取linux主机的一些信息,如CPU使用率,内存使用情况等.由于我们本身就装了zabbix系统,所以我只用知道如何获取信息即可,总结有两种方法可以获取. 一.通过ZABBIX API获取 ...

  7. PHP 常用字符串函数

    1.查找字符位置函数 strpos($str,search,[int]):查找search在$str中的第一次位置从int开始: stripos($str,search,[int]):函数返回字符串在 ...

  8. php结合redis实现秒杀功能

    <?php 第一种,简单实现 $conn=mysql_connect("localhost","big","123456"); if( ...

  9. [置顶] spring集成mina 实现消息推送以及转发

    spring集成mina: 在学习mina这块时,在网上找了很多资料,只有一些demo,只能实现客户端向服务端发送消息.建立长连接之类.但是实际上在项目中,并不简单实现这些,还有业务逻辑之类的处理以及 ...

  10. setTimeout和setInterval和单线程

    我们知道,js是单线程执行的(单线程j就是说在程序执行时,所走的程序路径按照连续顺序排下来,前面的必须处理好,后面的才会执行).所以其实setTimeout和setInterval所谓的"异 ...