整合營(yíng)銷(xiāo)服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢(xún)熱線(xiàn):

          SpringBoot項(xiàng)目使用EasyPoi實(shí)現(xiàn)導(dǎo)入導(dǎo)

          SpringBoot項(xiàng)目使用EasyPoi實(shí)現(xiàn)導(dǎo)入導(dǎo)出,就是這么的絲滑

          Hi,大家好,我是希留。

          在項(xiàng)目的開(kāi)發(fā)工程中,經(jīng)常有導(dǎo)入導(dǎo)出數(shù)據(jù)的常見(jiàn)功能場(chǎng)景,Apache的POI是處理導(dǎo)入導(dǎo)出中最常用的,但是其原生的用法太復(fù)雜,很繁瑣,總是在Copy… ,無(wú)意間發(fā)現(xiàn)一款簡(jiǎn)單粗暴的神器EasyPoi,EasyPoi也是基于POI的,在SpringBoot中也是做了很好的封裝,讓我們能夠在SpringBoot 快速地使用 EasyPoi 進(jìn)行開(kāi)發(fā),很方便,而且支持多種格式的導(dǎo)入導(dǎo)出。


          本篇文章就給大家介紹下EasyPoi。如果對(duì)你有幫助的話(huà),還不忘點(diǎn)贊支持一下,感謝!文末附有源碼


          目錄

          • 一、EasyPoi簡(jiǎn)介
          • 二、EasyPoi主要功能
          • 三、EasyPoi注解介紹
          • 四、開(kāi)始使用

          一、EasyPoi簡(jiǎn)介

          EasyPoi功能如同名字easy,主打的功能就是容易,讓一個(gè)沒(méi)見(jiàn)接觸過(guò)poi的人員就可以方便的寫(xiě)出Excel導(dǎo)出,Excel模板導(dǎo)出,Excel導(dǎo)入,Word模板導(dǎo)出,通過(guò)簡(jiǎn)單的注解和模板語(yǔ)言(熟悉的表達(dá)式語(yǔ)法),完成以前復(fù)雜的寫(xiě)法。


          最新官方文檔:

          http://doc.wupaas.com/docs/easypoi/easypoi-1c0u6ksp2r091


          二、EasyPoi主要功能

          • 基于注解的導(dǎo)入導(dǎo)出,修改注解就可以修改Excel
          • 支持常用的樣式自定義
          • 基于map可以靈活定義的表頭字段
          • 支持一對(duì)多的導(dǎo)出,導(dǎo)入
          • 支持模板的導(dǎo)出,一些常見(jiàn)的標(biāo)簽,自定義標(biāo)簽
          • 支持HTML/Excel轉(zhuǎn)換,如果模板還不能滿(mǎn)足用戶(hù)的變態(tài)需求,請(qǐng)用這個(gè)功能
          • 支持word的導(dǎo)出,支持圖片,Excel

          三、EasyPoi注解介紹

          easypoi起因就是Excel的導(dǎo)入導(dǎo)出,最初的模板是實(shí)體和Excel的對(duì)應(yīng),model–row,filed–col 這樣利用注解我們可以和容易做到excel到導(dǎo)入導(dǎo)出。


          1、@Excel

          這個(gè)是必須使用的注解,如果需求簡(jiǎn)單只使用這一個(gè)注解也是可以的,涵蓋了常用的Excel需求。

          屬性

          類(lèi)型

          默認(rèn)值

          功能

          name

          String

          null

          列名

          orderNum

          String

          “0”

          列的排序

          replace

          String[]

          {}

          值的替換 {a_id,b_id}

          type

          int

          1

          導(dǎo)出類(lèi)型 1 是文本 2 是圖片,3 是函數(shù),
          10是數(shù)字
          默認(rèn)是文本

          exportFormat

          String

          “”

          導(dǎo)出的時(shí)間格式,以這個(gè)是否為空來(lái)判斷
          是否需要格式化日期

          importFormat

          String

          “”

          導(dǎo)入的時(shí)間格式,以這個(gè)是否為空來(lái)判斷是否需要格式化日期

          format

          String

          “”

          時(shí)間格式,相當(dāng)于同時(shí)設(shè)置了exportForm
          at和 importFormat

          suffix

          String

          “”

          文字后綴,如% 90 變成90%

          isHyperlink

          boolean

          false

          超鏈接,如果是需要實(shí)現(xiàn)接口返回對(duì)象

          isImportField

          boolean

          true

          校驗(yàn)字段,看看這個(gè)字段是不是導(dǎo)入
          的Excel中有,如果沒(méi)有說(shuō)明是錯(cuò)誤的
          Excel,讀取失敗,支持name_id

          2、@ExcelCollection

          一對(duì)多的集合注解,用以標(biāo)記集合是否被數(shù)據(jù)以及集合的整體排序

          屬性

          類(lèi)型

          默認(rèn)值

          功能

          id

          String

          null

          定義ID

          name

          String

          null

          定義集合列名,
          支持nanm_id

          orderNum

          int

          0

          排序,支持name_id

          type

          Class<?>

          ArrayList.class

          導(dǎo)入時(shí)創(chuàng)建對(duì)象使用

          四、開(kāi)始使用

          1、添加依賴(lài)

          Maven 依賴(lài):

          <dependency>
             <groupId>cn.afterturn</groupId>
             <artifactId>easypoi-spring-boot-starter</artifactId>
             <version>4.2.0</version>
          </dependency>

          2、導(dǎo)入功能實(shí)現(xiàn)

          首先定義需要導(dǎo)入的數(shù)據(jù)類(lèi)型UserImportVO,并使用@Excel注解與excel列映射,導(dǎo)入的時(shí)候通常需要對(duì)導(dǎo)入的數(shù)據(jù)進(jìn)行一些校驗(yàn)

          2.1 UserImportVO導(dǎo)入類(lèi)

          EasyPoi的校驗(yàn)使用也很簡(jiǎn)單,對(duì)象上加上通用的校驗(yàn)規(guī)則,配置下需要校驗(yàn)就可以了,校驗(yàn)主要是JSR 303 規(guī)范,可結(jié)合Hibernate Validator使用

          導(dǎo)入類(lèi)對(duì)象實(shí)現(xiàn)IExcelModel、IExcelDataModel 接口,可獲取到錯(cuò)誤校驗(yàn)信息。

          @Data
          public class UserImportVO implements Serializable,IExcelModel, IExcelDataModel {
          
              @NotBlank
              @Excel(name="姓名")
              private String realName;
          
              @Excel(name="性別", replace={ "男_1", "女_2" })
              private Integer sex;
          
              @Excel(name="出生日期", format="yyyy-MM-dd")
              private Date birthday;
          
              @Length(min=1, max=11, message="請(qǐng)?zhí)顚?xiě)正確的手機(jī)號(hào)")
              @Excel(name="手機(jī)號(hào)碼")
              private String phone;
          
              @Excel(name="固定電話(huà)")
              private String tel;
          
              @Email(message="請(qǐng)?zhí)顚?xiě)正確的郵箱地址")
              @Excel(name="郵箱")
              private String email;
          
              @Excel(name="頭像地址")
              private String avatar;
          
              @Excel(name="信息")
              private String errorMsg;
          
              private Integer rowNum;
          
              @Override
              public Integer getRowNum() {
                  return this.rowNum;
              }
          
              @Override
              public void setRowNum(Integer i) {
                  this.rowNum=i;
              }
          
              @Override
              public String getErrorMsg() {
                  return this.errorMsg;
              }
          
              @Override
              public void setErrorMsg(String s) {
                  this.errorMsg=s;
              }
          }

          在編寫(xiě)controller層導(dǎo)入方法

          @Autowired
          private IUserService userService;
          
            @PostMapping("/importExcel")
            public String importExcel(@RequestParam("file") MultipartFile file) {
                  try {
                      String result=userService.importExcel(file);
                      return result;
                  } catch (Exception e) {
                      return "導(dǎo)入失敗";
                  }
             }

          2.3 service層

          具體的實(shí)現(xiàn)是在service層

          
             @Autowired
              private UserVerifyHandler userVerifyHandler;
          
              @Override
              public String importExcel(MultipartFile file) throws Exception{
                  ImportParams importParams=new ImportParams();
                  //表格標(biāo)題行數(shù),默認(rèn)0
                  importParams.setTitleRows(1);
                  //是否需要校驗(yàn)上傳的Excel
                  importParams.setNeedVerify(true);
                  //告訴easypoi我們自定義的驗(yàn)證器
                  importParams.setVerifyHandler(userVerifyHandler);
                  ExcelImportResult<UserImportVO> result=ExcelImportUtil.importExcelMore(file.getInputStream(),UserImportVO.class,importParams);
                  if (!result.isVerifyFail() && !CollectionUtils.isEmpty(result.getList())) {
                      for (UserImportVO vo : result.getList()) {
                          log.info("從Excel導(dǎo)入數(shù)據(jù)到數(shù)據(jù)庫(kù)的詳細(xì)為 :{}", vo);
                          User user=new User();
                          BeanUtil.copyProperties(vo,user);
                          this.save(user);
                      }
                  } else {
                      for (UserImportVO vo : result.getFailList()) {
                          log.info("校驗(yàn)失敗的詳細(xì)為 :{}", vo);
                      }
                      return "文檔校驗(yàn)失敗";
                  }
                  return "導(dǎo)入成功";
              }
          

          2.4 ImportParams 參數(shù)

          導(dǎo)入?yún)?shù)介紹下

          屬性

          類(lèi)型

          默認(rèn)值

          功能

          titleRows

          int

          0

          表格標(biāo)題行數(shù),默認(rèn)0

          headRows

          int

          1

          表頭行數(shù),默認(rèn)1

          startRows

          int

          0

          字段真正值和列標(biāo)題之間
          的距離 默認(rèn)0

          startSheetIndex

          int

          0

          開(kāi)始讀取的sheet位置,
          默認(rèn)為0

          needVerfiy

          boolean

          false

          是否需要校驗(yàn)上傳的Excel

          needSave

          boolean

          false

          是否需要保存上傳的Excel

          saveUrl

          String

          “upload
          /excelUpload”

          保存上傳的Excel目錄,默認(rèn)
          是 如 TestEntity這個(gè)類(lèi)保存路徑就是upload/excelUpload/Test/yyyyMMddHHmss* 保存名稱(chēng)上傳時(shí)間五位隨機(jī)數(shù)

          importFields

          String[]

          null

          導(dǎo)入時(shí)校驗(yàn)數(shù)據(jù)模板,是不是正確的Excel

          verifyHanlder

          IExcelVerifyHandler

          null

          校驗(yàn)處理接口,自定義校驗(yàn)

          dataHanlder

          IExcelDataHandler

          null

          數(shù)據(jù)處理接口,以此為主,replace,format都在這后面


          2.5 自定義校驗(yàn)規(guī)則

          通用的校驗(yàn)滿(mǎn)足不了所有的校驗(yàn),例如還需要通過(guò)查詢(xún)數(shù)據(jù)庫(kù),校驗(yàn)數(shù)據(jù)的唯一性,此時(shí)需要自定義一個(gè)校驗(yàn)規(guī)則,實(shí)現(xiàn)IExcelVerifyHandler接口。

          @Component
          public class UserVerifyHandler implements IExcelVerifyHandler<UserImportVO> {
          
              @Autowired
              private IUserService userService;
          
              @Override
              public ExcelVerifyHandlerResult verifyHandler(UserImportVO vo) {
                  ExcelVerifyHandlerResult result=new ExcelVerifyHandlerResult();
                  //假設(shè)我們要添加用戶(hù),現(xiàn)在去數(shù)據(jù)庫(kù)查詢(xún)r(jià)ealName,如果存在則表示校驗(yàn)不通過(guò)。
                  User user=userService.getOne(new LambdaQueryWrapper<User>().eq(User::getRealName,vo.getRealName()));
                  if (user!=null) {
                      result.setMsg("唯一校驗(yàn)失敗");
                      result.setSuccess(false);
                      return result;
                  }
                  result.setSuccess(true);
                  return result;
              }
          }

          2.6 測(cè)試

          1.此時(shí),基本上的代碼就編寫(xiě)完了,開(kāi)始測(cè)試:

          使用postman工具進(jìn)行導(dǎo)入測(cè)試,先填充一些不符合規(guī)則的數(shù)據(jù),可以看到控制臺(tái)輸出的校驗(yàn)錯(cuò)誤的信息。

          圖1-1 測(cè)試導(dǎo)入的execl

          圖1-2 postman工具請(qǐng)求接口返回

          圖1-3 控制臺(tái)輸出

          2.再填充一些符合規(guī)則的數(shù)據(jù),可以看到導(dǎo)入成功,數(shù)據(jù)庫(kù)成功插入數(shù)據(jù)。

          圖2-1 測(cè)試導(dǎo)入的execl

          圖2-2 postman工具請(qǐng)求接口返回

          圖2-3 數(shù)據(jù)庫(kù)數(shù)據(jù)

          3、導(dǎo)出功能實(shí)現(xiàn)

          3.1 UserExportVO導(dǎo)出類(lèi)

          導(dǎo)出類(lèi)不需要配置校驗(yàn)規(guī)則,只需定義要導(dǎo)出的信息

          @Data
          public class UserExportVO implements Serializable {
          
              @Excel(name="姓名")
              private String realName;
          
              @Excel(name="性別", replace={ "男_1", "女_2" }, suffix="生")
              private Integer sex;
          
              @Excel(name="出生日期", format="yyyy-MM-dd")
              private Date birthday;
          
              @Excel(name="手機(jī)號(hào)碼")
              private String phone;
          
              @Excel(name="固定電話(huà)")
              private String tel;
          
              @Excel(name="郵箱")
              private String email;
          
              @Excel(name="頭像地址")
              private String avatar;
          
          }

          3.2 controller層

          編寫(xiě)controller層導(dǎo)出方法

           @GetMapping("/exportExcel")
           public void export(HttpServletResponse response) {
                  //查詢(xún)要導(dǎo)出的數(shù)據(jù)
                  List<UserExportVO> users=userService.getUserExportList();
                  ExcelUtil.exportExcelX(users, "測(cè)試導(dǎo)出表", "sheet1", UserExportVO.class, "測(cè)試導(dǎo)出表.xlsx", response);
           }
          

          3.3 service層

          編寫(xiě)service層查詢(xún)需要導(dǎo)出的數(shù)據(jù),把查詢(xún)出來(lái)的集合轉(zhuǎn)化成導(dǎo)出VO集合。

          @Override
          public List<UserExportVO> getUserExportList() {
                  List<User> users=this.list();
                  //users集合轉(zhuǎn)成export集合
                  List<UserExportVO> exportVOList=users.stream().map(user -> {
                      UserExportVO vo=new UserExportVO();
                      BeanUtils.copyProperties(user, vo);
                      return vo;
                  }).collect(Collectors.toList());
                  return exportVOList;
          }

          3.4 測(cè)試

          直接瀏覽器請(qǐng)求導(dǎo)出接口,成功導(dǎo)出。

          圖3-1 請(qǐng)求導(dǎo)出接口

          圖3-2 導(dǎo)出結(jié)果


          結(jié)語(yǔ)

          好了,以上就是今天要講的內(nèi)容,本文僅僅簡(jiǎn)單介紹了使用EasyPoi導(dǎo)入導(dǎo)出功能的使用,而EasyPoi還提供了模板的導(dǎo)出、圖片的導(dǎo)出、word的導(dǎo)出等等功能,感興趣的朋友,可查閱官方文檔進(jìn)一步探究。

          本次demo源碼:
          Gitee地址:https://gitee.com/huoqstudy/java-sjzl-demo/tree/master/springboot-easypoi-demo

          Github地址:https://github.com/277769738/java-sjzl-demo/tree/master/springboot-easypoi-demo

          產(chǎn)品期望實(shí)現(xiàn)【公文管理】其中發(fā)文擬文一塊內(nèi)容,用戶(hù)上傳正文(word),再選擇不同套紅模板,最后拼接為一個(gè)對(duì)外發(fā)文,的公文格式。

          基于上次使用vue實(shí)現(xiàn)在線(xiàn)編輯功能,產(chǎn)品不太滿(mǎn)意,重新學(xué)習(xí)java如何操作word文檔,之前地址:(vue使用Tinymce富文本模擬在線(xiàn)word文檔)juejin.cn/post/723665…

          最終效果

          有兩個(gè)文件test1.docx (作為紅頭模板)和test2.docx(作為正文);期望實(shí)現(xiàn)效果:用戶(hù)選擇紅頭模板加上自己寫(xiě)的正文內(nèi)容,最終生成可編輯的word文檔。

          create_table.docx 合并之后最終效果“

          test1.docx 紅頭模板:

          test2.docx 正文(用戶(hù)撰寫(xiě)上傳的內(nèi)容):

          準(zhǔn)備階段

          技術(shù)選型

          1. docx4j:一個(gè)用 文檔的 Java 庫(kù),具有良好的文檔合并功能。
          2. JODConverter:一個(gè)不依賴(lài)于 OpenOffice/LibreOffice 的 Java 庫(kù),可以幫助開(kāi)發(fā)者將 Office 文檔轉(zhuǎn)換成 PDF、HTML、XHTML、ODF 等格式,并支持合并 Word 文檔。
          3. Aspose.Words for Java:一個(gè)商業(yè)級(jí)的文檔處理庫(kù),支持多種文檔格式的處理,包括 Word、PDF、HTML 等,并且支持合并 Word 文檔。
          4. FreeMarker:一個(gè)模板引擎庫(kù),可以用于制作 Word 文檔模板,然后使用 Java 代碼生成文檔。
          5. Apache POI: 是一個(gè)開(kāi)源的 Java 庫(kù),可以用來(lái)讀寫(xiě) Microsoft Office 文檔,包括 Word、Excel、PowerPoint 等各種格式。它是 Apache 軟件基金會(huì)的一部分,最新版本是 5.0.0。

          如標(biāo)題所示,最終采用Apache POI來(lái)實(shí)現(xiàn)這個(gè)功能主要原因:

          1. 讀取和創(chuàng)建 Microsoft Office 文檔,包括 Word、Excel、PowerPoint 等多種格式。
          2. 支持訪問(wèn)和修改文檔的所有元素,比如文本、樣式、圖表、格式等。
          3. 提供豐富的工具類(lèi)和方法,可以方便地進(jìn)行文檔操作,比如把文本轉(zhuǎn)換成 HTML、從 Excel 中讀取數(shù)據(jù)、合并 Word 文檔等。
          4. 支持不同版本的 Office 文檔格式,包括舊版本和新版本。
          5. 支持批量處理大量文檔,提高了文檔處理的效率。

          主要是對(duì)于我這種初學(xué)者來(lái)說(shuō)是非常友好的,太復(fù)雜玩不轉(zhuǎn)。Apache POI 的使用非常簡(jiǎn)單,只需添加它的 jar 包到項(xiàng)目中,并調(diào)用相應(yīng)的 API 即可實(shí)現(xiàn)文檔讀寫(xiě)。同時(shí),Apache POI 提供了豐富的文檔和官方網(wǎng)站上的文檔也很詳細(xì)。

          功能設(shè)計(jì)思路

          1. 創(chuàng)建一個(gè)空的 Word 文檔作為合并后的文檔。
          2. 讀取要合并的 Word 文檔(test1.doxc、test2.docx),并將它們的內(nèi)容復(fù)制到合并后的文檔中。可以使用 Apache POI 中的 XWPFDocument 類(lèi)來(lái)讀寫(xiě) Word 文檔。
          3. 保存合并后的文檔。使用 XWPFDocument 類(lèi)的 write(OutputStream out) 方法將文檔保存到本地文件或輸出流中。

          功能實(shí)現(xiàn)

          Apache POI,分別為 Word、Excel、PowerPoint 等各種格式提供不同的類(lèi)方法,我們需要操作Word文檔的功能,所以使用(Java API for Microsoft Documents)中的XWPFDocument類(lèi),實(shí)現(xiàn)文檔合并功能。

          整理不同格式文檔操作類(lèi)

          1. HSSF: MS-Excel 97-2003(.xls),基于BIFF8格式的JAVA接口。
          2. XSSF:MS-Excel 2007+(.xlsx),基于OOXML格式的JAVA接口。
          3. HWPF: MS-Word 97-2003(.doc),基于BIFF8格式的JAVA接口。只支持.doc文件簡(jiǎn)單的操作,讀寫(xiě)能力有限。本API為POI項(xiàng)目早期開(kāi)發(fā),很不幸的 是主要負(fù)責(zé)HWPF模塊開(kāi)發(fā)的工程師-"Ryan Ackley"已經(jīng)離開(kāi)Apache組織,現(xiàn)在該模塊沒(méi)有人維護(hù)、更新、完善。
          4. XWPF:MS-Word 2007+(.docx),基于OOXML格式的JAVA接口。較HWPF功能完善。

          注意:word文檔目前有兩種不同格式,一種是以doc結(jié)尾的,另一種以docx結(jié)尾,本次功能主要講解docx格式文檔操作,doc格式文檔調(diào)用的類(lèi)和函數(shù)HWPF開(kāi)頭。

          兩者區(qū)別:doc是Word2007及以下版的文件擴(kuò)展名,而docx是Word2007及以上版本的文件擴(kuò)展名,docx版本兼容性較高,而且比doc文件所占用空間更小。

          引入依賴(lài)

          在pom.xml文件中引入maven依賴(lài),

                  <!-- WordToHtml .doc .odcx  poi  -->
                  <dependency>
                      <groupId>org.apache.poi</groupId>
                      <artifactId>poi-scratchpad</artifactId>
                      <version>4.1.2</version>
                  </dependency>
          
                  <!-- 操作excel的庫(kù) 注意版本保持一致 poi poi-ooxml  poi-scratchpad -->
                  <dependency>
                      <groupId>org.apache.poi</groupId>
                      <artifactId>poi</artifactId>
                      <version>4.1.2</version>
                  </dependency>
                  
                  <!--poi-ooxml和*poi-ooxml-schemas*是poi對(duì)2007及以上版本的擴(kuò)充。-->
                  <dependency>
                      <groupId>org.apache.poi</groupId>
                      <artifactId>poi-ooxml-schemas</artifactId>
                      <version>4.1.2</version>
                  </dependency>
                  <!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
                  <dependency>
                      <groupId>org.apache.poi</groupId>
                      <artifactId>poi-ooxml</artifactId>
                      <version>4.1.2</version>
                  </dependency>
          


          示例代碼

          簡(jiǎn)化整體流程,創(chuàng)建兩個(gè)word文件test1.docx和test2.docx。將下列file對(duì)應(yīng)的文件路徑換成自己創(chuàng)建的文件路徑創(chuàng),建單個(gè)java文件(帶main),直接運(yùn)行main方法輸出creat_table.docx文件。 先上代碼,再進(jìn)行講解:

          package org.ssssssss.magicboot;
          
          import org.apache.poi.xwpf.usermodel.*;
          
          import java.io.File;
          import java.io.FileInputStream;
          import java.io.FileOutputStream;
          import java.util.List;
          
          public class WordDocumentTest {
              public static void main(String[] args) throws Exception
              {
                  //獲取文件轉(zhuǎn)io流
                  File file1=new File("D:/IDM/test1.docx");
                  File file2=new File("D:/IDM/test2.docx");
                  FileInputStream fis1=new FileInputStream(file1);
                  FileInputStream fis2=new FileInputStream(file2);
                  //最終文件輸出的路徑
                  FileOutputStream out=new FileOutputStream(new File("D:/IDM/create_table.docx"));
          
                  //轉(zhuǎn)為word文檔元素
                  XWPFDocument dcx1=new XWPFDocument(fis1);
                  XWPFDocument dcx2=new XWPFDocument(fis2);
          
                  //創(chuàng)建一個(gè)新的文檔
                  XWPFDocument document=new XWPFDocument();
          
          
                  //將第一個(gè)文檔元素復(fù)制新創(chuàng)建的文檔中;
                  document=dcx1;
          
                  //換行 document.createParagraph().createRun().addBreak();
          
                  //將第二個(gè)docx內(nèi)容添加到新創(chuàng)建的文檔中
                  mergeParagraphs(dcx2.getParagraphs(), document);
                  //結(jié)束關(guān)閉io流
                  document.write(out);
                  out.close();
                  fis1.close();
                  fis2.close();
                  System.out.println("create_table document written success.");
          
              }
              // 合并文本段落
              private static void mergeParagraphs(List<XWPFParagraph> paragraphs, XWPFDocument outDoc) {
                  for (XWPFParagraph para : paragraphs) {
          
                      XWPFParagraph newPara=outDoc.createParagraph();
                      newPara.getCTP().setPPr(para.getCTP().getPPr());
                      //判斷是否是文本、段落、圖片 //.getRPr() para.tables !=null ,iruns 獲取圖片
          
                      for (XWPFRun run : para.getRuns()) {
                          XWPFRun newRun=newPara.createRun();
                          newRun.getCTR().setRPr(run.getCTR().getRPr());
                          newRun.setText(run.getText(0));
                      }
                  }
              }
          


          代碼解釋

          實(shí)現(xiàn)流程主要看代碼中的注釋?zhuān)韵聨讉€(gè)步驟

          1. 獲取文件轉(zhuǎn)io流
          2. 將io流轉(zhuǎn)為word文檔元素(XWPFDocument)
          3. 創(chuàng)建一個(gè)新的文檔
          4. 將第一個(gè)文檔元素復(fù)制新創(chuàng)建的文檔中
          5. 將第二個(gè)docx內(nèi)容添加到新創(chuàng)建的文檔中
          6. 輸出新文檔,關(guān)閉io流

          核心重點(diǎn)將第二個(gè)docx內(nèi)容添加到新創(chuàng)建的文檔中封裝mergeParagraphs方法,在這個(gè)方法中傳入了兩個(gè)參數(shù)(List paragraphs, XWPFDocument outDoc) 其中List<XWPFParagraph> paragraphs=dcx2.getParagraphs() 意思是將dcx2文檔所有段落取出來(lái)用一個(gè)數(shù)組存放,再進(jìn)行循環(huán)段落;通過(guò)XWPFParagraph newPara=outDoc.createParagraph();給新的文檔創(chuàng)建一個(gè)新的段落;給新的段落添加對(duì)應(yīng)的樣式newPara.getCTP().setPPr(para.getCTP().getPPr());最后由于段落中會(huì)劃分不同的XWPFRun再進(jìn)行循環(huán)設(shè)置文本的字體、大小、顏色、加粗、斜體、下劃線(xiàn)等格式。 官方api介紹

          剛才對(duì)XWPFRun沒(méi)有進(jìn)行很好的解釋?zhuān)@里重新舉例說(shuō)明下,例如以下標(biāo)紅的段落

          按照正常理解這一個(gè)段落內(nèi)容應(yīng)該是一個(gè)東西,其實(shí)在XWPF中會(huì)劃分為不同的XWPFRun,使用idea打斷點(diǎn)查看數(shù)據(jù)

          可以看出它將一段文字劃分為不同模塊,為什么會(huì)這樣,在一段文字中也存在不同的區(qū)別,例如文字的字體,像下圖中“根據(jù)”“2023”屬于不同的字體,所以會(huì)劃分為不同的XWPFRun,理解這個(gè)概念后同理明白為什么一個(gè)段落會(huì)劃分為29模塊

          相關(guān)函數(shù)

          在前面其實(shí)已經(jīng)實(shí)現(xiàn)第一個(gè)模塊最終效果的docx文檔合并的功能,所以在這個(gè)模塊講解在實(shí)現(xiàn)這個(gè)過(guò)程中記錄有意思的內(nèi)容。

          XWPFRun(文本段落)

          接著上面講XWPFRun這個(gè)函數(shù),XWPFRun用于在 Word 文檔中添加或修改單個(gè)本 Run 或 Run 中的文字格式。它是文本段落(XWPFParagraph)中的最小單元,用于精細(xì)控制文本的格式和樣式。可以使用 XWPFRun 類(lèi)的各種方法來(lái)設(shè)置文本的字體、大小、顏色、加粗、斜體、下劃線(xiàn)等格式。 下列是在使用過(guò)程中記錄的一些屬性,以及這些屬性對(duì)應(yīng)能夠設(shè)置的格式注釋。

              XWPFRun run=firstParagraph.createRun();
                          XWPFRun tempRun=xwpfRuns.get(i);
              
                          //默認(rèn):宋體(wps)/等線(xiàn)(office2016) 5號(hào) 兩端對(duì)齊 單倍間距
                          run.setText(tempRun.text());
                          //加粗
                          run.setBold(tempRun.isBold());
                          //我也不知道這個(gè)屬性做啥的
                          run.setCapitalized(tempRun.isCapitalized());
                          //設(shè)置顏色--十六進(jìn)制
                          run.setColor(tempRun.getColor());
                          //這個(gè)屬性報(bào)錯(cuò)
                          run.setCharacterSpacing(tempRun.getCharacterSpacing());
                          //浮雕字體----效果和印記(懸浮陰影)類(lèi)似
                          run.setEmbossed(tempRun.isEmbossed());
                          //雙刪除線(xiàn)
                          run.setDoubleStrikethrough(tempRun.isDoubleStrikeThrough());
                          run.setEmphasisMark(tempRun.getEmphasisMark().toString());
                          //字體,//字體,范圍----效果不詳
                          run.setFontFamily(tempRun.getFontFamily());
                          //字體大小,沒(méi)有設(shè)置默認(rèn)是-1,
                          if(tempRun.getFontSize() !=-1){
                              run.setFontSize(tempRun.getFontSize());
                          }
                          //印跡(懸浮陰影)---效果和浮雕類(lèi)似
                          run.setImprinted(tempRun.isImprinted());
                          //斜體(字體傾斜)
                          run.setItalic(tempRun.isItalic());
                          //字距調(diào)整----這個(gè)好像沒(méi)有效果
                          run.setKerning(tempRun.getKerning());
                          //陰影---稍微有點(diǎn)效果(陰影不明顯)
                          run.setShadow(tempRun.isShadowed());
                          //小型股------效果不清楚
                          run.setSmallCaps(tempRun.isSmallCaps());
                          //單刪除線(xiàn)(廢棄)
                          run.setStrike(tempRun.isStrike());
                          //單刪除線(xiàn)(新的替換Strike)
                          run.setStrikeThrough(tempRun.isStrikeThrough());
                          //下標(biāo)(吧當(dāng)前這個(gè)run變成下標(biāo))---枚舉
                          run.setSubscript(tempRun.getSubscript());
                          //設(shè)置兩行之間的行間距
                          run.setTextPosition(tempRun.getTextPosition());
                          //各種類(lèi)型的下劃線(xiàn)(枚舉)
                          run.setUnderline(tempRun.getUnderline());
          
                          run.setVerticalAlignment(tempRun.getVerticalAlignment().toString());
                          run.setVanish(tempRun.isVanish());
                          run.setUnderlineThemeColor(tempRun.getUnderlineColor());
                          run.setUnderlineColor(tempRun.getUnderlineColor());
                          run.setTextScale(tempRun.getTextScale());
                          run.setTextPosition(tempRun.getTextPosition());
                          run.setTextHighlightColor(tempRun.getTextHightlightColor().toString());
          //                run.setStyle(tempRun.gets); 沒(méi)找到這個(gè)屬性
                          run.setLang(tempRun.getLang());
          


          XWPFParagraph(段落)

          XWPFParagraph 是 Apache POI 庫(kù)中 XWPF 模塊的一部分,用于創(chuàng)建或修改 Word 文檔中的段落。它可以添加不同的文本格式,并且可以添加圖片、表格、超鏈接等內(nèi)容。XWPFParagraph 類(lèi)可以控制段落的樣式和格式,包括字體、字號(hào)、行距、首行縮進(jìn)、對(duì)齊方式等。可以使用 XWPFParagraph 類(lèi)的各種方法來(lái)設(shè)置段落的格式和樣式。

              常用方法:
              //創(chuàng)建一個(gè)新的 XWPFRun 對(duì)象,用于在段落中添加文本或修改文本格式。
              createRun()
              //設(shè)置段落的對(duì)齊方式,align 參數(shù)可以是 LEFT、CENTER、RIGHT、JUSTIFY 等值。
              setAlignment(ParagraphAlignment align)
              //設(shè)置段落的行距和行距規(guī)則,lineSpacing 參數(shù)是行距大小(以磅為單位),lineSpacingRule 參數(shù)可以是 EXACT、AT_LEAST、AUTO 等值。
              setSpacingBetween(int lineSpacing, LineSpacingRule lineSpacingRule)
              //設(shè)置段落的左縮進(jìn)大小(以磅為單位)。
              setIndentationLeft(int indentation)
              //設(shè)置段落的右縮進(jìn)大小(以磅為單位)。
              setIndentationRight(int indentation)
              //設(shè)置段落的編號(hào) ID。
              setNumID(BigInteger numId)
              //設(shè)置段落的編號(hào)格式,numFmt 參數(shù)可以是 DECIMAL、LOWERCASE_LETTER、UPPERCASE_LETTER 等值。
              setNumFmt(NumberFormat numFmt)
              //在段落中添加圖片,pictureType 參數(shù)是圖片類(lèi)型,filename 參數(shù)是圖片文件名,width 和 height 參數(shù)是圖片寬度和高度。
              createPicture(XWPFRun run, int pictureType, String filename, int width, int height)
              
              其他方法:
              //指定應(yīng)顯示在左邊頁(yè)面指定段周?chē)倪吔纭?
              setBorderBottom(Borders.APPLES); 
              //指定應(yīng)顯示在下邊頁(yè)面指定段周?chē)倪吔纭?
              setBorderLeft(Borders.APPLES);
              //指定應(yīng)顯示在右側(cè)的頁(yè)面指定段周?chē)倪吔纭?
              setBorderRight(Borders.ARCHED_SCALLOPS);
              //指定應(yīng)顯示上方一組有相同的一組段邊界設(shè)置的段落的邊界。這幾個(gè)是對(duì)段落之間的格式的統(tǒng)一,相當(dāng)于格式刷
              setBorderTop(Borders.ARCHED_SCALLOPS);
              //---正文寬度會(huì)稍微變窄 
              p1.setFirstLineIndent(99);
              //---段落的對(duì)齊方式 1左 2中 3右 4往上 左 不可寫(xiě)0和負(fù)數(shù)
              p1.setFontAlignment(1);
              //---首行縮進(jìn),指定額外的縮進(jìn),應(yīng)適用于父段的第一行。
              p1.setIndentationFirstLine(400);
              //---首行前進(jìn),指定的縮進(jìn)量,應(yīng)通過(guò)第一行回到開(kāi)始的文本流的方向上移動(dòng)縮進(jìn)從父段的第一行中刪除。
              p1.setIndentationHanging(400);
              //---整段右移
              p1.setIndentFromLeft(400);
              //--此方法提供了樣式的段落,這非常有用。
              p1.setStyle("");
              //--此元素指定是否消費(fèi)者應(yīng)中斷超過(guò)一行的文本范圍,通過(guò)打破這個(gè)詞 (打破人物等級(jí)) 的兩行或通過(guò)移動(dòng)到下一行 (在詞匯層面上打破) 這個(gè)詞的拉丁文字。
              p1.setWordWrapped(true);
              //---指定的文本的垂直對(duì)齊方式將應(yīng)用于此段落中的文本 
              p1.setVerticalAlignment(TextAlignment.CENTER);
              //--指定行之間的間距如何計(jì)算存儲(chǔ)在行屬性中。 
              p1.setSpacingLineRule(LineSpacingRule.AT_LEAST);
              //--指定應(yīng)添加在此線(xiàn)單位在文檔中的段落的第一行之前的間距。
              p1.setSpacingBeforeLines(6);  
              //--指定應(yīng)添加上面這一段文檔中絕對(duì)單位中的第一行的間距。
              p1.setSpacingBefore(6); 
              //--指定應(yīng)添加在此線(xiàn)單位在文檔中的段落的最后一行之后的間距。 
              p1.setSpacingAfterLines(6);
              //--指定應(yīng)添加在文檔中絕對(duì)單位這一段的最后一行之后的間距。
              p1.setSpacingAfter(6); 
              //--指定當(dāng)渲染此分頁(yè)視圖中的文檔,這一段的內(nèi)容都呈現(xiàn)在文檔中的新頁(yè)的開(kāi)始。
              p1.setPageBreak(true);
          


          其他功能

          剛在展示活動(dòng)內(nèi)容都是根據(jù)自身的需求寫(xiě)小demo,實(shí)際項(xiàng)目遠(yuǎn)遠(yuǎn)不止這些內(nèi)容,其中還是存在不足之處,例如word中的表格、圖片都是需要單獨(dú)處理,表格有個(gè)專(zhuān)門(mén)類(lèi)XWPFTable;圖片也有XWPFPictureData、 XWPFPicture

          學(xué)習(xí)參考

          Apache POI 官方網(wǎng)站提供了完整的 API 文檔:poi.apache.org/apidocs/dev…

          Apache POI 的 GitHub 倉(cāng)庫(kù)中查看示例代碼和文檔:github.com/apache/poi

          Java POI 生成Word文檔:blog.csdn.net/qq_34755766…

          Apache POI 中文版download.csdn.net/download/qq…


          作者:沐游虞
          轉(zhuǎn)自:https://juejin.cn/post/7237487091554730021
          來(lái)源:稀土掘金
          著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。

          、前言

          實(shí)現(xiàn)文檔在線(xiàn)預(yù)覽的方式除了上篇文章 文檔在線(xiàn)預(yù)覽新版(一)通過(guò)將文件轉(zhuǎn)成圖片實(shí)現(xiàn)在線(xiàn)預(yù)覽功能說(shuō)的將文檔轉(zhuǎn)成圖片的實(shí)現(xiàn)方式外,還有轉(zhuǎn)成pdf,前端通過(guò)pdf.js、pdfobject.js等插件來(lái)實(shí)現(xiàn)在線(xiàn)預(yù)覽,以及本文將要說(shuō)到的將文檔轉(zhuǎn)成html的方式來(lái)實(shí)現(xiàn)在線(xiàn)預(yù)覽。

          以下代碼分別提供基于aspose、pdfbox、spire來(lái)實(shí)現(xiàn)來(lái)實(shí)現(xiàn)txt、word、pdf、ppt、word等文件轉(zhuǎn)圖片的需求。

          1、aspose

          Aspose 是一家致力于.Net ,Java,SharePoint,JasperReports和SSRS組件的提供商,數(shù)十個(gè)國(guó)家的數(shù)千機(jī)構(gòu)都有用過(guò)aspose組件,創(chuàng)建、編輯、轉(zhuǎn)換或渲染 Office、OpenOffice、PDF、圖像、ZIP、CAD、XPS、EPS、PSD 和更多文件格式。注意aspose是商用組件,未經(jīng)授權(quán)導(dǎo)出文件里面都是是水印(尊重版權(quán),遠(yuǎn)離破解版)。

          需要在項(xiàng)目的pom文件里添加如下依賴(lài)

                  <dependency>
                      <groupId>com.aspose</groupId>
                      <artifactId>aspose-words</artifactId>
                      <version>23.1</version>
                  </dependency>
                  <dependency>
                      <groupId>com.aspose</groupId>
                      <artifactId>aspose-pdf</artifactId>
                      <version>23.1</version>
                  </dependency>
                  <dependency>
                      <groupId>com.aspose</groupId>
                      <artifactId>aspose-cells</artifactId>
                      <version>23.1</version>
                  </dependency>
                  <dependency>
                      <groupId>com.aspose</groupId>
                      <artifactId>aspose-slides</artifactId>
                      <version>23.1</version>
                  </dependency>
          

          2 、poi + pdfbox

          因?yàn)閍spose和spire雖然好用,但是都是是商用組件,所以這里也提供使用開(kāi)源庫(kù)操作的方式的方式。

          POI是Apache軟件基金會(huì)用Java編寫(xiě)的免費(fèi)開(kāi)源的跨平臺(tái)的 Java API,Apache POI提供API給Java程序?qū)icrosoft Office格式檔案讀和寫(xiě)的功能。

          Apache PDFBox是一個(gè)開(kāi)源Java庫(kù),支持PDF文檔的開(kāi)發(fā)和轉(zhuǎn)換。 使用此庫(kù),您可以開(kāi)發(fā)用于創(chuàng)建,轉(zhuǎn)換和操作PDF文檔的Java程序。

          需要在項(xiàng)目的pom文件里添加如下依賴(lài)

          		<dependency>
                      <groupId>org.apache.pdfbox</groupId>
                      <artifactId>pdfbox</artifactId>
                      <version>2.0.4</version>
                  </dependency>
          		<dependency>
                      <groupId>org.apache.poi</groupId>
                      <artifactId>poi</artifactId>
                      <version>5.2.0</version>
                  </dependency>
                  <dependency>
                      <groupId>org.apache.poi</groupId>
                      <artifactId>poi-ooxml</artifactId>
                      <version>5.2.0</version>
                  </dependency>
                  <dependency>
                      <groupId>org.apache.poi</groupId>
                      <artifactId>poi-scratchpad</artifactId>
                      <version>5.2.0</version>
                  </dependency>
                  <dependency>
                      <groupId>org.apache.poi</groupId>
                      <artifactId>poi-excelant</artifactId>
                      <version>5.2.0</version>
                  </dependency>
          

          3 spire

          spire一款專(zhuān)業(yè)的Office編程組件,涵蓋了對(duì)Word、Excel、PPT、PDF等文件的讀寫(xiě)、編輯、查看功能。spire提供免費(fèi)版本,但是存在只能導(dǎo)出前3頁(yè)以及只能導(dǎo)出前500行的限制,只要達(dá)到其一就會(huì)觸發(fā)限制。需要超出前3頁(yè)以及只能導(dǎo)出前500行的限制的這需要購(gòu)買(mǎi)付費(fèi)版(尊重版權(quán),遠(yuǎn)離破解版)。這里使用免費(fèi)版進(jìn)行演示。

          spire在添加pom之前還得先添加maven倉(cāng)庫(kù)來(lái)源

          		<repository>
                      <id>com.e-iceblue</id>
                      <name>e-iceblue</name>
                      <url>https://repo.e-iceblue.cn/repository/maven-public/</url>
                  </repository>
          

          接著在項(xiàng)目的pom文件里添加如下依賴(lài)

          免費(fèi)版:

          		<dependency>
                      <groupId>e-iceblue</groupId>
                      <artifactId>spire.office.free</artifactId>
                      <version>5.3.1</version>
                  </dependency>
          

          付費(fèi)版版:

          		<dependency>
                      <groupId>e-iceblue</groupId>
                      <artifactId>spire.office</artifactId>
                      <version>5.3.1</version>
                  </dependency>
          

          二、將文件轉(zhuǎn)換成html字符串

          1、將word文件轉(zhuǎn)成html字符串

          1.1 使用aspose

          public static String wordToHtmlStr(String wordPath) {
                  try {
                      Document doc=new Document(wordPath); // Address是將要被轉(zhuǎn)化的word文檔
                      String htmlStr=doc.toString();
                      return htmlStr;
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
                  return null;
              }
          

          驗(yàn)證結(jié)果:

          1.2 使用poi

          public String wordToHtmlStr(String wordPath) throws TransformerException, IOException, ParserConfigurationException {
                  String htmlStr=null;
                  String ext=wordPath.substring(wordPath.lastIndexOf("."));
                  if (ext.equals(".docx")) {
                      htmlStr=word2007ToHtmlStr(wordPath);
                  } else if (ext.equals(".doc")){
                      htmlStr=word2003ToHtmlStr(wordPath);
                  } else {
                      throw new RuntimeException("文件格式不正確");
                  }
                  return htmlStr;
              }
          
              public String word2007ToHtmlStr(String wordPath) throws IOException {
                  // 使用內(nèi)存輸出流
                  try(ByteArrayOutputStream out=new ByteArrayOutputStream()){
                      word2007ToHtmlOutputStream(wordPath, out);
                      return out.toString();
                  }
              }
          
              private void word2007ToHtmlOutputStream(String wordPath,OutputStream out) throws IOException {
                  ZipSecureFile.setMinInflateRatio(-1.0d);
                  InputStream in=Files.newInputStream(Paths.get(wordPath));
                  XWPFDocument document=new XWPFDocument(in);
                  XHTMLOptions options=XHTMLOptions.create().setIgnoreStylesIfUnused(false).setImageManager(new Base64EmbedImgManager());
                  // 使用內(nèi)存輸出流
                  XHTMLConverter.getInstance().convert(document, out, options);
              }
          
          
              private String word2003ToHtmlStr(String wordPath) throws TransformerException, IOException, ParserConfigurationException {
                  org.w3c.dom.Document htmlDocument=word2003ToHtmlDocument(wordPath);
                  // Transform document to string
                  StringWriter writer=new StringWriter();
                  TransformerFactory tf=TransformerFactory.newInstance();
                  Transformer transformer=tf.newTransformer();
                  transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
                  transformer.setOutputProperty(OutputKeys.METHOD, "html");
                  transformer.setOutputProperty(OutputKeys.INDENT, "yes");
                  transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
                  transformer.transform(new DOMSource(htmlDocument), new StreamResult(writer));
                  return writer.toString();
              }
          
          private org.w3c.dom.Document word2003ToHtmlDocument(String wordPath) throws IOException, ParserConfigurationException {
                  InputStream input=Files.newInputStream(Paths.get(wordPath));
                  HWPFDocument wordDocument=new HWPFDocument(input);
                  WordToHtmlConverter wordToHtmlConverter=new WordToHtmlConverter(
                          DocumentBuilderFactory.newInstance().newDocumentBuilder()
                                  .newDocument());
                  wordToHtmlConverter.setPicturesManager((content, pictureType, suggestedName, widthInches, heightInches) -> {
                      System.out.println(pictureType);
                      if (PictureType.UNKNOWN.equals(pictureType)) {
                          return null;
                      }
                      BufferedImage bufferedImage=ImgUtil.toImage(content);
                      String base64Img=ImgUtil.toBase64(bufferedImage, pictureType.getExtension());
                      //  帶圖片的word,則將圖片轉(zhuǎn)為base64編碼,保存在一個(gè)頁(yè)面中
                      StringBuilder sb=(new StringBuilder(base64Img.length() + "data:;base64,".length()).append("data:;base64,").append(base64Img));
                      return sb.toString();
                  });
                  // 解析word文檔
                  wordToHtmlConverter.processDocument(wordDocument);
                  return wordToHtmlConverter.getDocument();
              }

          1.3 使用spire

           public String wordToHtmlStr(String wordPath) throws IOException {
                  try(ByteArrayOutputStream outputStream=new ByteArrayOutputStream()) {
                      Document document=new Document();
                      document.loadFromFile(wordPath);
                      document.saveToFile(outputStream, FileFormat.Html);
                      return outputStream.toString();
                  }
              }

          2、將pdf文件轉(zhuǎn)成html字符串

          2.1 使用aspose

          public static String pdfToHtmlStr(String pdfPath) throws IOException, ParserConfigurationException {
                  PDDocument document=PDDocument.load(new File(pdfPath));
                  Writer writer=new StringWriter();
                  new PDFDomTree().writeText(document, writer);
                  writer.close();
                  document.close();
                  return writer.toString();
              }

          驗(yàn)證結(jié)果:

          2.2 使用 poi + pbfbox

          public String pdfToHtmlStr(String pdfPath) throws IOException, ParserConfigurationException {
                  PDDocument document=PDDocument.load(new File(pdfPath));
                  Writer writer=new StringWriter();
                  new PDFDomTree().writeText(document, writer);
                  writer.close();
                  document.close();
                  return writer.toString();
              }

          2.3 使用spire

          public String pdfToHtmlStr(String pdfPath) throws IOException, ParserConfigurationException {
                  try(ByteArrayOutputStream outputStream=new ByteArrayOutputStream()) {
                      PdfDocument pdf=new PdfDocument();
                      pdf.loadFromFile(pdfPath);
                      return outputStream.toString();
                  }
              }
          

          3、將excel文件轉(zhuǎn)成html字符串

          3.1 使用aspose

          public static String excelToHtmlStr(String excelPath) throws Exception {
                  FileInputStream fileInputStream=new FileInputStream(excelPath);
                  Workbook workbook=new XSSFWorkbook(fileInputStream);
                  DataFormatter dataFormatter=new DataFormatter();
                  FormulaEvaluator formulaEvaluator=workbook.getCreationHelper().createFormulaEvaluator();
                  Sheet sheet=workbook.getSheetAt(0);
                  StringBuilder htmlStringBuilder=new StringBuilder();
                  htmlStringBuilder.append("<html><head><title>Excel to HTML using Java and POI library</title>");
                  htmlStringBuilder.append("<style>table, th, td { border: 1px solid black; }</style>");
                  htmlStringBuilder.append("</head><body><table>");
                  for (Row row : sheet) {
                      htmlStringBuilder.append("<tr>");
                      for (Cell cell : row) {
                          CellType cellType=cell.getCellType();
                          if (cellType==CellType.FORMULA) {
                              formulaEvaluator.evaluateFormulaCell(cell);
                              cellType=cell.getCachedFormulaResultType();
                          }
                          String cellValue=dataFormatter.formatCellValue(cell, formulaEvaluator);
                          htmlStringBuilder.append("<td>").append(cellValue).append("</td>");
                      }
                      htmlStringBuilder.append("</tr>");
                  }
                  htmlStringBuilder.append("</table></body></html>");
                  return htmlStringBuilder.toString();
              }
          

          返回的html字符串:

          <html><head><title>Excel to HTML using Java and POI library</title><style>table, th, td { border: 1px solid black; }</style></head><body><table><tr><td>序號(hào)</td><td>姓名</td><td>性別</td><td>聯(lián)系方式</td><td>地址</td></tr><tr><td>1</td><td>張曉玲</td><td>女</td><td>11111111111</td><td>上海市浦東新區(qū)xx路xx弄xx號(hào)</td></tr><tr><td>2</td><td>王小二</td><td>男</td><td>1222222</td><td>上海市浦東新區(qū)xx路xx弄xx號(hào)</td></tr><tr><td>1</td><td>張曉玲</td><td>女</td><td>11111111111</td><td>上海市浦東新區(qū)xx路xx弄xx號(hào)</td></tr><tr><td>2</td><td>王小二</td><td>男</td><td>1222222</td><td>上海市浦東新區(qū)xx路xx弄xx號(hào)</td></tr><tr><td>1</td><td>張曉玲</td><td>女</td><td>11111111111</td><td>上海市浦東新區(qū)xx路xx弄xx號(hào)</td></tr><tr><td>2</td><td>王小二</td><td>男</td><td>1222222</td><td>上海市浦東新區(qū)xx路xx弄xx號(hào)</td></tr><tr><td>1</td><td>張曉玲</td><td>女</td><td>11111111111</td><td>上海市浦東新區(qū)xx路xx弄xx號(hào)</td></tr><tr><td>2</td><td>王小二</td><td>男</td><td>1222222</td><td>上海市浦東新區(qū)xx路xx弄xx號(hào)</td></tr><tr><td>1</td><td>張曉玲</td><td>女</td><td>11111111111</td><td>上海市浦東新區(qū)xx路xx弄xx號(hào)</td></tr><tr><td>2</td><td>王小二</td><td>男</td><td>1222222</td><td>上海市浦東新區(qū)xx路xx弄xx號(hào)</td></tr><tr><td>1</td><td>張曉玲</td><td>女</td><td>11111111111</td><td>上海市浦東新區(qū)xx路xx弄xx號(hào)</td></tr><tr><td>2</td><td>王小二</td><td>男</td><td>1222222</td><td>上海市浦東新區(qū)xx路xx弄xx號(hào)</td></tr><tr><td>1</td><td>張曉玲</td><td>女</td><td>11111111111</td><td>上海市浦東新區(qū)xx路xx弄xx號(hào)</td></tr><tr><td>2</td><td>王小二</td><td>男</td><td>1222222</td><td>上海市浦東新區(qū)xx路xx弄xx號(hào)</td></tr></table></body></html>
          

          3.2 使用poi + pdfbox

          public String excelToHtmlStr(String excelPath) throws Exception {
                  FileInputStream fileInputStream=new FileInputStream(excelPath);
                  try (Workbook workbook=WorkbookFactory.create(new File(excelPath))){
                      DataFormatter dataFormatter=new DataFormatter();
                      FormulaEvaluator formulaEvaluator=workbook.getCreationHelper().createFormulaEvaluator();
                      org.apache.poi.ss.usermodel.Sheet sheet=workbook.getSheetAt(0);
                      StringBuilder htmlStringBuilder=new StringBuilder();
                      htmlStringBuilder.append("<html><head><title>Excel to HTML using Java and POI library</title>");
                      htmlStringBuilder.append("<style>table, th, td { border: 1px solid black; }</style>");
                      htmlStringBuilder.append("</head><body><table>");
                      for (Row row : sheet) {
                          htmlStringBuilder.append("<tr>");
                          for (Cell cell : row) {
                              CellType cellType=cell.getCellType();
                              if (cellType==CellType.FORMULA) {
                                  formulaEvaluator.evaluateFormulaCell(cell);
                                  cellType=cell.getCachedFormulaResultType();
                              }
                              String cellValue=dataFormatter.formatCellValue(cell, formulaEvaluator);
                              htmlStringBuilder.append("<td>").append(cellValue).append("</td>");
                          }
                          htmlStringBuilder.append("</tr>");
                      }
                      htmlStringBuilder.append("</table></body></html>");
                      return htmlStringBuilder.toString();
                  }
              }
          

          3.3 使用spire

          public String excelToHtmlStr(String excelPath) throws Exception {
                  try(ByteArrayOutputStream outputStream=new ByteArrayOutputStream()) {
                      Workbook workbook=new Workbook();
                      workbook.loadFromFile(excelPath);
                      workbook.saveToStream(outputStream, com.spire.xls.FileFormat.HTML);
                      return outputStream.toString();
                  }
              }
          

          三、將文件轉(zhuǎn)換成html,并生成html文件

          有時(shí)我們是需要的不僅僅返回html字符串,而是需要生成一個(gè)html文件這時(shí)應(yīng)該怎么做呢?一個(gè)改動(dòng)量小的做法就是使用org.apache.commons.io包下的FileUtils工具類(lèi)寫(xiě)入目標(biāo)地址:

          FileUtils類(lèi)將html字符串生成html文件示例:

          首先需要引入pom:

          		<dependency>
                      <groupId>commons-io</groupId>
                      <artifactId>commons-io</artifactId>
                      <version>2.8.0</version>
                  </dependency>
          

          相關(guān)代碼:

          String htmlStr=FileConvertUtil.pdfToHtmlStr("D:\\書(shū)籍\\電子書(shū)\\小說(shuō)\\歷史小說(shuō)\\最后的可汗.doc");
          FileUtils.write(new File("D:\\test\\doc.html"), htmlStr, "utf-8");
          

          除此之外,還可以對(duì)上面的代碼進(jìn)行一些調(diào)整,已實(shí)現(xiàn)生成html文件,代碼調(diào)整如下:

          1、將word文件轉(zhuǎn)換成html文件

          word原文件效果:

          1.1 使用aspose

          public static void wordToHtml(String wordPath, String htmlPath) {
                  try {
                      File sourceFile=new File(wordPath);
                      String path=htmlPath + File.separator + sourceFile.getName().substring(0, sourceFile.getName().lastIndexOf(".")) + ".html";
                      File file=new File(path); // 新建一個(gè)空白pdf文檔
                      FileOutputStream os=new FileOutputStream(file);
                      Document doc=new Document(wordPath); // Address是將要被轉(zhuǎn)化的word文檔
                      HtmlSaveOptions options=new HtmlSaveOptions();
                      options.setExportImagesAsBase64(true);
                      options.setExportRelativeFontSize(true);
                      doc.save(os, options);
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }
          

          轉(zhuǎn)換成html的效果:

          1.2 使用poi + pdfbox

          public void wordToHtml(String wordPath, String htmlPath) throws TransformerException, IOException, ParserConfigurationException {
                  htmlPath=FileUtil.getNewFileFullPath(wordPath, htmlPath, "html");
                  String ext=wordPath.substring(wordPath.lastIndexOf("."));
                  if (ext.equals(".docx")) {
                      word2007ToHtml(wordPath, htmlPath);
                  } else if (ext.equals(".doc")){
                      word2003ToHtml(wordPath, htmlPath);
                  } else {
                      throw new RuntimeException("文件格式不正確");
                  }
              }
          
              public void word2007ToHtml(String wordPath, String htmlPath) throws TransformerException, IOException, ParserConfigurationException {
                  //try(OutputStream out=Files.newOutputStream(Paths.get(path))){
                  try(FileOutputStream out=new FileOutputStream(htmlPath)){
                      word2007ToHtmlOutputStream(wordPath, out);
                  }
              }
          
              private void word2007ToHtmlOutputStream(String wordPath,OutputStream out) throws IOException {
                  ZipSecureFile.setMinInflateRatio(-1.0d);
                  InputStream in=Files.newInputStream(Paths.get(wordPath));
                  XWPFDocument document=new XWPFDocument(in);
                  XHTMLOptions options=XHTMLOptions.create().setIgnoreStylesIfUnused(false).setImageManager(new Base64EmbedImgManager());
                  // 使用內(nèi)存輸出流
                  XHTMLConverter.getInstance().convert(document, out, options);
              }
          
              public void word2003ToHtml(String wordPath, String htmlPath) throws TransformerException, IOException, ParserConfigurationException {
                  org.w3c.dom.Document htmlDocument=word2003ToHtmlDocument(wordPath);
                  // 生成html文件地址
          
                  try(OutputStream outStream=Files.newOutputStream(Paths.get(htmlPath))){
                      DOMSource domSource=new DOMSource(htmlDocument);
                      StreamResult streamResult=new StreamResult(outStream);
                      TransformerFactory factory=TransformerFactory.newInstance();
                      Transformer serializer=factory.newTransformer();
                      serializer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
                      serializer.setOutputProperty(OutputKeys.INDENT, "yes");
                      serializer.setOutputProperty(OutputKeys.METHOD, "html");
                      serializer.transform(domSource, streamResult);
                  }
              }
          
              private org.w3c.dom.Document word2003ToHtmlDocument(String wordPath) throws IOException, ParserConfigurationException {
                  InputStream input=Files.newInputStream(Paths.get(wordPath));
                  HWPFDocument wordDocument=new HWPFDocument(input);
                  WordToHtmlConverter wordToHtmlConverter=new WordToHtmlConverter(
                          DocumentBuilderFactory.newInstance().newDocumentBuilder()
                                  .newDocument());
                  wordToHtmlConverter.setPicturesManager((content, pictureType, suggestedName, widthInches, heightInches) -> {
                      System.out.println(pictureType);
                      if (PictureType.UNKNOWN.equals(pictureType)) {
                          return null;
                      }
                      BufferedImage bufferedImage=ImgUtil.toImage(content);
                      String base64Img=ImgUtil.toBase64(bufferedImage, pictureType.getExtension());
                      //  帶圖片的word,則將圖片轉(zhuǎn)為base64編碼,保存在一個(gè)頁(yè)面中
                      StringBuilder sb=(new StringBuilder(base64Img.length() + "data:;base64,".length()).append("data:;base64,").append(base64Img));
                      return sb.toString();
                  });
                  // 解析word文檔
                  wordToHtmlConverter.processDocument(wordDocument);
                  return wordToHtmlConverter.getDocument();
              }
          

          轉(zhuǎn)換成html的效果:

          1.3 使用spire

          public void wordToHtml(String wordPath, String htmlPath) {
                  htmlPath=FileUtil.getNewFileFullPath(wordPath, htmlPath, "html");
                  Document document=new Document();
                  document.loadFromFile(wordPath);
                  document.saveToFile(htmlPath, FileFormat.Html);
              }
          

          轉(zhuǎn)換成html的效果:

          因?yàn)槭褂玫氖敲赓M(fèi)版,存在頁(yè)數(shù)和字?jǐn)?shù)限制,需要完整功能的的可以選擇付費(fèi)版本。PS:這回76頁(yè)的文檔居然轉(zhuǎn)成功了前50頁(yè)。

          2、將pdf文件轉(zhuǎn)換成html文件

          圖片版pdf原文件效果:

          文字版pdf原文件效果:

          2.1 使用aspose

          public static void pdfToHtml(String pdfPath, String htmlPath) throws IOException, ParserConfigurationException {
                  File file=new File(pdfPath);
                  String path=htmlPath + File.separator + file.getName().substring(0, file.getName().lastIndexOf(".")) + ".html";
                  PDDocument document=PDDocument.load(new File(pdfPath));
                  Writer writer=new PrintWriter(path, "UTF-8");
                  new PDFDomTree().writeText(document, writer);
                  writer.close();
                  document.close();
              }
          

          圖片版PDF文件驗(yàn)證結(jié)果:

          文字版PDF文件驗(yàn)證結(jié)果:

          2.2 使用poi + pdfbox

          public void pdfToHtml(String pdfPath, String htmlPath) throws IOException, ParserConfigurationException {
                  String path=FileUtil.getNewFileFullPath(pdfPath, htmlPath, "html");
                  PDDocument document=PDDocument.load(new File(pdfPath));
                  Writer writer=new PrintWriter(path, "UTF-8");
                  new PDFDomTree().writeText(document, writer);
                  writer.close();
                  document.close();
              }
          

          圖片版PDF文件驗(yàn)證結(jié)果:

          文字版PDF原文件效果:

          2.3 使用spire

          public void pdfToHtml(String pdfPath, String htmlPath) throws IOException, ParserConfigurationException {
                  htmlPath=FileUtil.getNewFileFullPath(pdfPath, htmlPath, "html");
                  PdfDocument pdf=new PdfDocument();
                  pdf.loadFromFile(pdfPath);
                  pdf.saveToFile(htmlPath, com.spire.pdf.FileFormat.HTML);
              }
          

          圖片版PDF文件驗(yàn)證結(jié)果:
          因?yàn)槭褂玫氖敲赓M(fèi)版,所以只有前三頁(yè)是正常的。。。有超過(guò)三頁(yè)需求的可以選擇付費(fèi)版本。

          文字版PDF原文件效果:

          報(bào)錯(cuò)了無(wú)法轉(zhuǎn)換。。。

          java.lang.NullPointerException
          	at com.spire.pdf.PdfPageWidget.spr┢?(Unknown Source)
          	at com.spire.pdf.PdfPageWidget.getSize(Unknown Source)
          	at com.spire.pdf.PdfPageBase.spr???—(Unknown Source)
          	at com.spire.pdf.PdfPageBase.getActualSize(Unknown Source)
          	at com.spire.pdf.PdfPageBase.getSection(Unknown Source)
          	at com.spire.pdf.general.PdfDestination.spr︻┎?—(Unknown Source)
          	at com.spire.pdf.general.PdfDestination.spr┻┑?—(Unknown Source)
          	at com.spire.pdf.general.PdfDestination.getElement(Unknown Source)
          	at com.spire.pdf.primitives.PdfDictionary.setProperty(Unknown Source)
          	at com.spire.pdf.bookmarks.PdfBookmark.setDestination(Unknown Source)
          	at com.spire.pdf.bookmarks.PdfBookmarkWidget.spr┭┘?—(Unknown Source)
          	at com.spire.pdf.bookmarks.PdfBookmarkWidget.getDestination(Unknown Source)
          	at com.spire.pdf.PdfDocumentBase.spr??(Unknown Source)
          	at com.spire.pdf.widget.PdfPageCollection.spr┦?(Unknown Source)
          	at com.spire.pdf.widget.PdfPageCollection.removeAt(Unknown Source)
          	at com.spire.pdf.PdfDocumentBase.spr┞?(Unknown Source)
          	at com.spire.pdf.PdfDocument.loadFromFile(Unknown Source)
          

          3、將excel文件轉(zhuǎn)換成html文件

          excel原文件效果:

          3.1 使用aspose

          public void excelToHtml(String excelPath, String htmlPath) throws Exception {
                  htmlPath=FileUtil.getNewFileFullPath(excelPath, htmlPath, "html");
                  Workbook workbook=new Workbook(excelPath);
                  com.aspose.cells.HtmlSaveOptions options=new com.aspose.cells.HtmlSaveOptions();
                  workbook.save(htmlPath, options);
              }
          

          轉(zhuǎn)換成html的效果:

          3.2 使用poi

          public void excelToHtml(String excelPath, String htmlPath) throws Exception {
                  String path=FileUtil.getNewFileFullPath(excelPath, htmlPath, "html");
                  try(FileOutputStream fileOutputStream=new FileOutputStream(path)){
                      String htmlStr=excelToHtmlStr(excelPath);
                      byte[] bytes=htmlStr.getBytes();
                      fileOutputStream.write(bytes);
                  }
              }
          
          
              public String excelToHtmlStr(String excelPath) throws Exception {
                  FileInputStream fileInputStream=new FileInputStream(excelPath);
                  try (Workbook workbook=WorkbookFactory.create(new File(excelPath))){
                      DataFormatter dataFormatter=new DataFormatter();
                      FormulaEvaluator formulaEvaluator=workbook.getCreationHelper().createFormulaEvaluator();
                      org.apache.poi.ss.usermodel.Sheet sheet=workbook.getSheetAt(0);
                      StringBuilder htmlStringBuilder=new StringBuilder();
                      htmlStringBuilder.append("<html><head><title>Excel to HTML using Java and POI library</title>");
                      htmlStringBuilder.append("<style>table, th, td { border: 1px solid black; }</style>");
                      htmlStringBuilder.append("</head><body><table>");
                      for (Row row : sheet) {
                          htmlStringBuilder.append("<tr>");
                          for (Cell cell : row) {
                              CellType cellType=cell.getCellType();
                              if (cellType==CellType.FORMULA) {
                                  formulaEvaluator.evaluateFormulaCell(cell);
                                  cellType=cell.getCachedFormulaResultType();
                              }
                              String cellValue=dataFormatter.formatCellValue(cell, formulaEvaluator);
                              htmlStringBuilder.append("<td>").append(cellValue).append("</td>");
                          }
                          htmlStringBuilder.append("</tr>");
                      }
                      htmlStringBuilder.append("</table></body></html>");
                      return htmlStringBuilder.toString();
                  }
              }
          

          轉(zhuǎn)換成html的效果:

          3.3 使用spire

          public void excelToHtml(String excelPath, String htmlPath) throws Exception {
                  htmlPath=FileUtil.getNewFileFullPath(excelPath, htmlPath, "html");
                  Workbook workbook=new Workbook();
                  workbook.loadFromFile(excelPath);
                  workbook.saveToFile(htmlPath, com.spire.xls.FileFormat.HTML);
              }
          

          轉(zhuǎn)換成html的效果:

          四、總結(jié)

          從上述的效果展示我們可以發(fā)現(xiàn)其實(shí)轉(zhuǎn)成html效果不是太理想,很多細(xì)節(jié)樣式?jīng)]有還原,這其實(shí)是因?yàn)檫@類(lèi)轉(zhuǎn)換往往都是追求目標(biāo)是通過(guò)使用文檔中的語(yǔ)義信息并忽略其他細(xì)節(jié)來(lái)生成簡(jiǎn)單干凈的 HTML,所以在轉(zhuǎn)換過(guò)程中復(fù)雜樣式被忽略,比如居中、首行縮進(jìn)、字體,文本大小,顏色。舉個(gè)例子在轉(zhuǎn)換是 會(huì)將應(yīng)用標(biāo)題 1 樣式的任何段落轉(zhuǎn)換為 h1 元素,而不是嘗試完全復(fù)制標(biāo)題的樣式。所以轉(zhuǎn)成html的顯示效果往往和原文檔不太一樣。這意味著對(duì)于較復(fù)雜的文檔而言,這種轉(zhuǎn)換不太可能是完美的。但如果都是只使用簡(jiǎn)單樣式文檔或者對(duì)文檔樣式不太關(guān)心的這種方式也不妨一試。

          PS:如果想要展示效果好的話(huà),其實(shí)可以將上篇文章《文檔在線(xiàn)預(yù)覽(一)通過(guò)將txt、word、pdf轉(zhuǎn)成圖片實(shí)現(xiàn)在線(xiàn)預(yù)覽功能》說(shuō)的內(nèi)容和本文結(jié)合起來(lái)使用,即將文檔里的內(nèi)容都生成成圖片(很可能是多張圖片),然后將生成的圖片全都放到一個(gè)html頁(yè)面里 ,用html+css來(lái)保持樣式并實(shí)現(xiàn)多張圖片展示,再將html返回。開(kāi)源組件kkfilevie就是用的就是這種做法。

          kkfileview展示效果如下:

          下圖是kkfileview返回的html代碼,從html代碼我們可以看到kkfileview其實(shí)是將文件(txt文件除外)每頁(yè)的內(nèi)容都轉(zhuǎn)成了圖片,然后將這些圖片都嵌入到一個(gè)html里,再返回給用戶(hù)一個(gè)html頁(yè)面。


          主站蜘蛛池模板: 一区二区三区免费电影| 久久久精品人妻一区二区三区| 国模大胆一区二区三区| 久久综合精品不卡一区二区| 国产美女精品一区二区三区| 成人精品一区二区三区不卡免费看 | 亚洲一区在线视频| 色窝窝无码一区二区三区 | 福利一区二区三区视频午夜观看| 国模无码视频一区二区三区| 亚洲一区视频在线播放| 无码囯产精品一区二区免费| 日韩免费一区二区三区在线| 美女视频免费看一区二区| 国产无套精品一区二区| 无码国产精品一区二区免费式直播| 亚洲综合色一区二区三区| 国产精品成人一区二区| 精品欧洲av无码一区二区三区| 日韩免费视频一区| 日韩免费无码一区二区三区| 国产成人精品一区二区三在线观看| 国产午夜精品一区二区三区嫩草 | 无码精品人妻一区| 精品人伦一区二区三区潘金莲| 国产成人av一区二区三区在线| 久久精品亚洲一区二区| 一区五十路在线中出| 交换国产精品视频一区| 国产成人高清精品一区二区三区 | 精品国产a∨无码一区二区三区| 日韩精品无码久久一区二区三| 91一区二区在线观看精品| 久久精品无码一区二区三区日韩 | 波多野结衣AV一区二区三区中文| 国产亚洲福利精品一区| 国产成人精品无人区一区| 精品乱码一区二区三区在线| 亚洲愉拍一区二区三区| 日韩av无码一区二区三区| 国产精品日本一区二区不卡视频|