最近有一个项目需要将一个word文档中的数据提取到数据库中。就去网上查了好多资料,最靠谱的就是用poi实现word文档的提取。
喝水不忘挖井人,我查了好多资料就这个最靠谱,我的这篇博客主要是借鉴https://blog.csdn.net/qq_16601953/article/details/82415518
现在讲一下思路:
1.首先我们要用poi将word中的数据提取出来,我把提取的数据存到字符数组中,
2.然后通过sql数据将字符串数组中的数据存到mysql数据库中
当然需要jar包依赖
可能不需要这么多,但是我都导进去了
网上有poi的下载链接http://120.52.51.14/archive.apache.org/dist/poi/release/bin/poi-bin-3.17-20170915.zip
如果实在找不到的话加我
下面贴上主要代码我是按照上面博客借鉴的稍微根据我的需求改了改
1 import java.io.FileInputStream; 2 import java.io.FileOutputStream; 3 import java.io.IOException; 4 import java.io.InputStream; 5 import java.io.OutputStream; 6 import java.math.BigInteger; 7 import java.util.HashMap; 8 import java.util.List; 9 import java.util.Map; 10 11 import org.apache.poi.xwpf.usermodel.XWPFDocument; 12 import org.apache.poi.xwpf.usermodel.XWPFParagraph; 13 import org.apache.poi.xwpf.usermodel.XWPFRun; 14 import org.apache.poi.xwpf.usermodel.XWPFStyle; 15 import org.apache.poi.xwpf.usermodel.XWPFStyles; 16 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDecimalNumber; 17 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTOnOff; 18 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPr; 19 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTString; 20 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTStyle; 21 import org.openxmlformats.schemas.wordprocessingml.x2006.main.STStyleType; 22 23 24 public class test { 25 private static Map<String,Map<String,Object>> orderMap =new HashMap<String, Map<String,Object>>(); 26 27 public void init(String targetPath,String sourcePath){ 28 InputStream is = null; 29 XWPFDocument doc=null; 30 OutputStream out=null; 31 try { 32 XWPFDocument createDoc = new XWPFDocument(); 33 34 is = new FileInputStream(sourcePath); 35 doc = new XWPFDocument(is); 36 //获取段落 37 List<XWPFParagraph> paras=doc.getParagraphs(); 38 39 for (XWPFParagraph para : paras){ 40 // System.out.println(para.getCTP());//得到xml格式 41 System.out.println(para.getStyleID());//段落级别 42 System.out.println(para.getParagraphText());//段落内容 43 44 String titleLvl = getTitleLvl(doc,para);//获取段落级别 45 if("a5".equals(titleLvl)||"HTML".equals(titleLvl)||"".equals(titleLvl)||null==titleLvl){ 46 titleLvl = "8"; 47 } 48 System.out.println(titleLvl+"-----");//0,1,2 49 if(!"8".equals(titleLvl)){ 50 System.out.println(titleLvl+"===="+para.getParagraphText()); 51 } 52 53 54 XWPFParagraph ctPara = createDoc.createParagraph(); 55 //一个XWPFRun代表具有相同属性的一个区域。 56 XWPFRun ctRun = ctPara.createRun(); 57 String ctText = para.getParagraphText(); 58 ctRun.setFontFamily("宋体");//字体 59 ctRun.setFontSize(12); 60 61 if(null!=titleLvl&&!"".equals(titleLvl)&&!"8".equals(titleLvl)){ 62 addCustomHeadingStyle(createDoc,titleLvl,Integer.parseInt(titleLvl)); 63 String orderCode = getOrderCode(titleLvl);//获取编号 64 ctText = orderCode+" "+ctText; 65 ctRun.setBold(true);//标题加粗 66 ctRun.setFontSize(14); 67 68 ctPara.setStyle(titleLvl); 69 70 }else{//正文 71 ctPara.setIndentationFirstLine(567);//首行缩进:567==1厘米 72 // ctRun.setTextPosition(6);//设置行间距 73 } 74 75 ctRun.setText(ctText);//内容 76 } 77 out=new FileOutputStream(targetPath); 78 createDoc.write(out); 79 } catch (Exception e) { 80 e.printStackTrace(); 81 } finally{ 82 try { 83 if(null!=out){ 84 out.close(); 85 } 86 if(null!=is){ 87 is.close(); 88 } 89 }catch (IOException e) { 90 e.printStackTrace(); 91 } 92 } 93 } 94 95 /** 96 * Word中的大纲级别,可以通过getPPr().getOutlineLvl()直接提取,但需要注意,Word中段落级别,通过如下三种方式定义: 97 * 1、直接对段落进行定义; 98 * 2、对段落的样式进行定义; 99 * 3、对段落样式的基础样式进行定义。 100 * 因此,在通过“getPPr().getOutlineLvl()”提取时,需要依次在如上三处读取。 101 * @param doc 102 * @param para 103 * @return 104 */ 105 private static String getTitleLvl(XWPFDocument doc, XWPFParagraph para) { 106 String titleLvl = ""; 107 try { 108 //判断该段落是否设置了大纲级别 109 if (para.getCTP().getPPr().getOutlineLvl() != null) { 110 // System.out.println("getCTP()"); 111 // System.out.println(para.getParagraphText()); 112 // System.out.println(para.getCTP().getPPr().getOutlineLvl().getVal()); 113 114 return String.valueOf(para.getCTP().getPPr().getOutlineLvl().getVal()); 115 } 116 } catch (Exception e) { 117 118 } 119 120 try { 121 //判断该段落的样式是否设置了大纲级别 122 if (doc.getStyles().getStyle(para.getStyle()).getCTStyle().getPPr().getOutlineLvl() != null) { 123 124 // System.out.println("getStyle"); 125 // System.out.println(para.getParagraphText()); 126 // System.out.println(doc.getStyles().getStyle(para.getStyle()).getCTStyle().getPPr().getOutlineLvl().getVal()); 127 128 return String.valueOf(doc.getStyles().getStyle(para.getStyle()).getCTStyle().getPPr().getOutlineLvl().getVal()); 129 } 130 } catch (Exception e) { 131 132 } 133 134 try { 135 //判断该段落的样式的基础样式是否设置了大纲级别 136 if (doc.getStyles().getStyle(doc.getStyles().getStyle(para.getStyle()).getCTStyle().getBasedOn().getVal()) 137 .getCTStyle().getPPr().getOutlineLvl() != null) { 138 // System.out.println("getBasedOn"); 139 // System.out.println(para.getParagraphText()); 140 String styleName = doc.getStyles().getStyle(para.getStyle()).getCTStyle().getBasedOn().getVal(); 141 // System.out.println(doc.getStyles().getStyle(styleName).getCTStyle().getPPr().getOutlineLvl().getVal()); 142 143 return String.valueOf(doc.getStyles().getStyle(styleName).getCTStyle().getPPr().getOutlineLvl().getVal()); 144 } 145 } catch (Exception e) { 146 147 } 148 149 try { 150 if(para.getStyleID()!=null){ 151 return para.getStyleID(); 152 } 153 } catch (Exception e) { 154 155 } 156 157 return titleLvl; 158 } 159 160 /** 161 * 增加自定义标题样式。这里用的是stackoverflow的源码 162 * 163 * @param docxDocument 目标文档 164 * @param strStyleId 样式名称 165 * @param headingLevel 样式级别 166 */ 167 private static void addCustomHeadingStyle(XWPFDocument docxDocument, String strStyleId, int headingLevel) { 168 169 strStyleId = String.valueOf(Integer.parseInt(strStyleId)+1); 170 CTStyle ctStyle = CTStyle.Factory.newInstance(); 171 ctStyle.setStyleId(strStyleId); 172 173 CTString styleName = CTString.Factory.newInstance(); 174 styleName.setVal(strStyleId); 175 ctStyle.setName(styleName); 176 177 CTDecimalNumber indentNumber = CTDecimalNumber.Factory.newInstance(); 178 indentNumber.setVal(BigInteger.valueOf(headingLevel)); 179 180 // lower number > style is more prominent in the formats bar 181 ctStyle.setUiPriority(indentNumber); 182 183 CTOnOff onoffnull = CTOnOff.Factory.newInstance(); 184 ctStyle.setUnhideWhenUsed(onoffnull); 185 186 // style shows up in the formats bar 187 ctStyle.setQFormat(onoffnull); 188 189 // style defines a heading of the given level 190 CTPPr ppr = CTPPr.Factory.newInstance(); 191 ppr.setOutlineLvl(indentNumber); 192 ctStyle.setPPr(ppr); 193 194 XWPFStyle style = new XWPFStyle(ctStyle); 195 196 // is a null op if already defined 197 XWPFStyles styles = docxDocument.createStyles(); 198 199 style.setType(STStyleType.PARAGRAPH); 200 styles.addStyle(style); 201 202 } 203 /** 204 * 获取标题编号 205 * @param titleLvl 206 * @return 207 */ 208 private static String getOrderCode(String titleLvl) { 209 String order = ""; 210 211 if("0".equals(titleLvl)||Integer.parseInt(titleLvl)==8){//文档标题||正文 212 return ""; 213 }else if(Integer.parseInt(titleLvl)>0&&Integer.parseInt(titleLvl)<8){//段落标题 214 215 //设置最高级别标题 216 Map<String,Object> maxTitleMap = orderMap.get("maxTitleLvlMap"); 217 if(null==maxTitleMap){//没有,表示第一次进来 218 //最高级别标题赋值 219 maxTitleMap = new HashMap<String, Object>(); 220 maxTitleMap.put("lvl", titleLvl); 221 orderMap.put("maxTitleLvlMap", maxTitleMap); 222 }else{ 223 String maxTitleLvl = maxTitleMap.get("lvl")+"";//最上层标题级别(0,1,2,3) 224 if(Integer.parseInt(titleLvl)<Integer.parseInt(maxTitleLvl)){//当前标题级别更高 225 maxTitleMap.put("lvl", titleLvl);//设置最高级别标题 226 orderMap.put("maxTitleLvlMap", maxTitleMap); 227 } 228 } 229 230 //查父节点标题 231 int parentTitleLvl = Integer.parseInt(titleLvl)-1;//父节点标题级别 232 Map<String,Object> cMap = orderMap.get(titleLvl);//当前节点信息 233 Map<String,Object> pMap = orderMap.get(parentTitleLvl+"");//父节点信息 234 235 if(0==parentTitleLvl){//父节点为文档标题,表明当前节点为1级标题 236 int count= 0; 237 //最上层标题,没有父节点信息 238 if(null==cMap){//没有当前节点信息 239 cMap = new HashMap<String, Object>(); 240 }else{ 241 count = Integer.parseInt(String.valueOf(cMap.get("cCount")));//当前序个数 242 } 243 count++; 244 order = count+""; 245 cMap.put("cOrder", order);//当前序 246 cMap.put("cCount", count);//当前序个数 247 orderMap.put(titleLvl, cMap); 248 249 }else{//父节点为非文档标题 250 int count= 0; 251 //如果没有相邻的父节点信息,当前标题级别自动升级 252 if(null==pMap){ 253 return getOrderCode(String.valueOf(parentTitleLvl)); 254 }else{ 255 String pOrder = String.valueOf(pMap.get("cOrder"));//父节点序 256 if(null==cMap){//没有当前节点信息 257 cMap = new HashMap<String, Object>(); 258 }else{ 259 count = Integer.parseInt(String.valueOf(cMap.get("cCount")));//当前序个数 260 } 261 count++; 262 order = pOrder+"."+count;//当前序编号 263 cMap.put("cOrder", order);//当前序 264 cMap.put("cCount", count);//当前序个数 265 orderMap.put(titleLvl, cMap); 266 } 267 } 268 269 //字节点标题计数清零 270 int childTitleLvl = Integer.parseInt(titleLvl)+1;//子节点标题级别 271 Map<String,Object> cdMap = orderMap.get(childTitleLvl+"");// 272 if(null!=cdMap){ 273 cdMap.put("cCount", 0);//子节点序个数 274 orderMap.get(childTitleLvl+"").put("cCount", 0); 275 } 276 } 277 return order; 278 } 279 280 public static void main(String[] args) { 281 InputStream is = null; 282 XWPFDocument doc=null; 283 OutputStream out=null; 284 String[] title= new String [276]; 285 String[] concent= new String [276]; 286 String[] type= new String [276]; 287 int i=0; 288 try { 289 XWPFDocument createDoc = new XWPFDocument(); 290 291 is = new FileInputStream("E:/doc/a.docx"); 292 doc = new XWPFDocument(is); 293 //获取段落 294 List<XWPFParagraph> paras=doc.getParagraphs(); 295 296 for (XWPFParagraph para : paras){ 297 //System.out.println(para.getCTP());//得到xml格式 298 //System.out.println(para.getStyleID());//段落级别 299 // System.out.println(para.getParagraphText());//段落内容 300 String titleLvl = getTitleLvl(doc,para);//获取段落级别 301 if("a5".equals(titleLvl)||"HTML".equals(titleLvl)||"".equals(titleLvl)||null==titleLvl){ 302 titleLvl = "8"; 303 } 304 //System.out.println(titleLvl+"-----");//0,1,2 305 if(!"8".equals(titleLvl)){ 306 //System.out.println(titleLvl+"===="+para.getParagraphText()); 307 308 if("3".equals(titleLvl)) { 309 310 if(concent[i]!=null) 311 concent[i]=concent[i]+para.getParagraphText(); 312 else 313 concent[i]=para.getParagraphText(); 314 //System.out.println(concent[i]); 315 } 316 if("2".equals(titleLvl)) { 317 i++; 318 title[i]=para.getParagraphText(); 319 type[i]=type[i-1]; 320 //System.out.println(title[i]); 321 } 322 if("1".equals(titleLvl)) { 323 i++; 324 type[i]=para.getParagraphText(); 325 //System.out.println(title[i]); 326 } 327 } 328 329 330 } 331 for(int j=2;j<title.length;j++) { 332 if(title[j]!=null) { 333 String sql = "INSERT INTO shuju (title,concent,type)VALUES ('"+title[j]+"','"+concent[j]+"','"+type[j]+"')"; 334 DBUtil jdbc=new DBUtil(); 335 int result=jdbc.executeUpdate(sql); 336 jdbc.close(); 337 //System.out.println(type[j]); 338 //System.out.println(title[j]); 339 //System.out.println(concent[j]); 340 } 341 } 342 } catch (Exception e) { 343 e.printStackTrace(); 344 } finally{ 345 try { 346 if(null!=out){ 347 out.close(); 348 } 349 if(null!=is){ 350 is.close(); 351 } 352 }catch (IOException e) { 353 e.printStackTrace(); 354 } 355 } 356 } 357 }
ps:331到341是导入到数据库的需要新建数据库工具类
你自己弄就OK
如果是单纯的读取的话用下面的代码,因为上面比较繁琐我都不太理解,下面的代码比较简单易懂,当然功能相对也少,只能读取所有内容不能识别标题
借鉴的哪一篇博客因为时间太长了,我忘了,抱歉
1 package com.poi.test; 2 3 import java.io.File; 4 import java.io.FileInputStream; 5 import java.io.InputStream; 6 7 import org.apache.poi.POIXMLDocument; 8 import org.apache.poi.POIXMLTextExtractor; 9 import org.apache.poi.hwpf.extractor.WordExtractor; 10 import org.apache.poi.openxml4j.opc.OPCPackage; 11 import org.apache.poi.xwpf.extractor.XWPFWordExtractor; 12 13 public class testPoi { 14 /** 15 * 读取word文件内容 16 * 17 * @param path 18 * @return buffer 19 */ 20 21 public String readWord(String path) { 22 String buffer = ""; 23 try { 24 if (path.endsWith(".doc")) { 25 InputStream is = new FileInputStream(new File(path)); 26 WordExtractor ex = new WordExtractor(is); 27 buffer = ex.getText(); 28 ex.close(); 29 } else if (path.endsWith("docx")) { 30 OPCPackage opcPackage = POIXMLDocument.openPackage(path); 31 POIXMLTextExtractor extractor = new XWPFWordExtractor(opcPackage); 32 buffer = extractor.getText(); 33 extractor.close(); 34 } else { 35 System.out.println("此文件不是word文件!"); 36 } 37 38 } catch (Exception e) { 39 e.printStackTrace(); 40 } 41 42 return buffer; 43 } 44 45 public static void main(String[] args) { 46 // TODO Auto-generated method stub 47 testPoi tp = new testPoi(); 48 String content = tp.readWord("自己的路径.doc"); 49 //String arr[]=content.split("\d+"); 50 //String arr[]=content.split("第"+"\w"+"章"); 51 String arr[]=content.split("\r\n"); 52 /*String[] a=arr[13].split("\d+"); 53 String[] b=a[1].split("\s+"); 54 System.out.println(b[1]);*/ 55 String[] reci = new String [276];; 56 for(int i=12,j=0;i<290;i++,j++) { 57 arr[i]=arr[i]+"1"; 58 if(!arr[i].equals("1")) { 59 60 if(i<27) {//判断页面数是否为单数 61 String[] a=arr[i].split("\d+|\s+"); 62 if(arr[i]!="\s+") {//判断该元素是否为连续空格 63 if(a.length==2) {//判断该元素是否为标题即分割成2个段 64 reci[j]=a[1]; 65 System.out.println(a[1]); 66 } 67 else if(a.length==1) { 68 reci[j]=a[1]; 69 System.out.println(arr[i]); 70 } 71 else//否则该元素是平常元素可以分割成3个段 72 { 73 reci[j]=a[2]; 74 System.out.println(a[2]); 75 } 76 } 77 } 78 else { 79 String[] a=arr[i].split("\d{2,3}|\s+|\t"); 80 if(arr[i]!="\s+") {//判断该元素是否为连续空格 81 if(a.length==2) { 82 reci[j]=a[1]; 83 System.out.println(a[1]); 84 } 85 else if(a.length==1) { 86 reci[j]=a[1]; 87 System.out.println(arr[i]+i); 88 } 89 else if(a.length==4) { 90 reci[j]=a[1]; 91 System.out.println(a[1]); 92 } 93 else 94 {reci[j]=a[2]; 95 System.out.println(a[2]); 96 } 97 } 98 } 99 } 100 } 101 String fengefu=reci[0]; 102 for(int i=1;i<276;i++) { 103 if(reci[i]!=null) 104 fengefu=fengefu+"|"+reci[i]; 105 106 } 107 System.out.println(reci[275]); 108 System.out.println(fengefu); 109 String arr2[]=content.split(fengefu); 110 for(int i=0;i<200;i++) 111 System.out.println(arr2[i]); 112 } 113 }
还有下面这一种方法,与上面相似
1 package com.xxx.util; 2 3 import java.io.File; 4 import java.io.FileInputStream; 5 import java.io.IOException; 6 7 import org.apache.poi.hwpf.extractor.WordExtractor; 8 9 public class DocUtil { 10 /** 11 * 读取doc文件内容 12 * 13 * @param file 14 * 想要读取的文件对象 15 * @return 返回文件内容 16 * @throws IOException 17 */ 18 public static String doc2String(FileInputStream fs) throws IOException { 19 StringBuilder result = new StringBuilder(); 20 WordExtractor re = new WordExtractor(fs); 21 result.append(re.getText()); 22 re.close(); 23 return result.toString(); 24 } 25 26 public static String doc2String(File file) throws IOException { 27 return doc2String(new FileInputStream(file)); 28 } 29 30 public static void main(String[] args) { 31 File file = new File("自己的路径.doc"); 32 try { 33 System.out.println(doc2String(file)); 34 } catch (IOException e) { 35 e.printStackTrace(); 36 } 37 } 38 }
结果截图因为一部分原因就不贴出来了
当然对于poi我还是比较陌生,希望大牛们批评指正