日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > HTML >内容正文

HTML

apache poi_将HTML转换为Apache POI的RichTextString

發布時間:2023/12/3 HTML 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 apache poi_将HTML转换为Apache POI的RichTextString 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

apache poi

1.概述

在本教程中,我們將構建一個將HTML作為輸入的應用程序,并使用提供HTML的RichText表示形式創建Microsoft Excel工作簿。 為了生成Microsoft Excel工作簿,我們將使用Apache POI 。 為了分析HTML,我們將使用Jericho。

Github上提供了本教程的完整源代碼。

2.什么是耶利哥?

Jericho是一個Java庫 ,它允許對HTML文檔的各個部分(包括服務器端標簽)進行分析和操作,同時逐字再現任何無法識別或無效HTML。 它還提供了高級HTML表單操作功能。 它是一個開放源代碼庫,使用以下許可證發行: Eclipse公共許可證(EPL) , GNU通用公共許可證(LGPL)和Apache許可證 。

我發現Jericho非常易于使用,可以實現將HTML轉換為RichText的目標。

3. pom.xml

這是我們正在構建的應用程序所需的依賴項。 請注意,對于此應用程序,我們必須使用Java 9 。 這是因為我們使用的java.util.regex appendReplacement方法自Java 9起才可用。

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.9.RELEASE</version><relativePath /> <!-- lookup parent from repository --> </parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>9</java.version> </properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-batch</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.7</version></dependency><dependency><groupId>org.springframework.batch</groupId><artifactId>spring-batch-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>3.15</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>3.15</version></dependency><!-- https://mvnrepository.com/artifact/net.htmlparser.jericho/jericho-html --><dependency><groupId>net.htmlparser.jericho</groupId><artifactId>jericho-html</artifactId><version>3.4</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><!-- legacy html allow --><dependency><groupId>net.sourceforge.nekohtml</groupId><artifactId>nekohtml</artifactId></dependency> </dependencies>

4.網頁– Thymeleaf

我們使用Thymeleaf來創建一個基本頁面,該頁面具有帶有文本區域的表單。 Github上提供 Thymeleaf頁面的源代碼。 如果愿意,可以使用RichText編輯器替換此textarea,例如CKEditor。 我們只需要注意使用適當的setData方法使AJAX的數據正確即可。 在Spring Boot中,以前有一個關于CKeditor的教程,標題為CKEditor,名為AJAX 。

5.控制器

在我們的控制器中,我們將自動裝配JobLauncher和一個Spring Batch作業,我們將創建一個名為GenerateExcel的作業 。 通過自動裝配這兩個類,當POST請求發送到“ / export”時,我們可以按需運行Spring Batch Job GenerateExcel 。

要注意的另一件事是,為了確保Spring Batch作業將運行一次以上,我們在此代碼中包含唯一參數: addLong(“ uniqueness”,System.nanoTime())。toJobParameters() 。 如果我們不包括唯一參數,則可能會發生錯誤,因為只能創建和執行唯一的JobInstances,否則Spring Batch無法區分第一個JobInstance和第二個JobInstance 。

@Controller public class WebController {private String currentContent;@AutowiredJobLauncher jobLauncher;@AutowiredGenerateExcel exceljob; @GetMapping("/")public ModelAndView getHome() {ModelAndView modelAndView = new ModelAndView("index");return modelAndView;}@PostMapping("/export")public String postTheFile(@RequestBody String body, RedirectAttributes redirectAttributes, Model model)throws IOException, JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException, JobParametersInvalidException {setCurrentContent(body);Job job = exceljob.ExcelGenerator();jobLauncher.run(job, new JobParametersBuilder().addLong("uniqueness", System.nanoTime()).toJobParameters());return "redirect:/";}//standard getters and setters}

6.批處理作業

在批處理作業的步驟1中,我們調用getCurrentContent()方法來獲取傳遞到Thymeleaf表單中的內容,創建一個新的XSSFWorkbook,指定一個任意的Microsoft Excel Sheet選項卡名稱,然后將所有三個變量都傳遞到createWorksheet方法中我們將在本教程的下一步中進行以下操作:

@Configuration @EnableBatchProcessing @Lazy public class GenerateExcel {List<String> docIds = new ArrayList<String>();@Autowiredprivate JobBuilderFactory jobBuilderFactory;@Autowiredprivate StepBuilderFactory stepBuilderFactory;@AutowiredWebController webcontroller;@AutowiredCreateWorksheet createexcel;@Beanpublic Step step1() {return stepBuilderFactory.get("step1").tasklet(new Tasklet() {@Overridepublic RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception, JSONException {String content = webcontroller.getCurrentContent();System.out.println("content is ::" + content);Workbook wb = new XSSFWorkbook();String tabName = "some";createexcel.createWorkSheet(wb, content, tabName);return RepeatStatus.FINISHED;}}).build();}@Beanpublic Job ExcelGenerator() {return jobBuilderFactory.get("ExcelGenerator").start(step1()).build();}}

我們還在其他教程中介紹了Spring Batch,例如將XML轉換為JSON + Spring Batch和Spring Batch CSV Processing 。

7. Excel創建服務

我們使用各種類來創建我們的Microsoft Excel文件。 在將HTML轉換為RichText時,順序很重要,因此這將是重點。

7.1 RichTextDetails

一個帶有兩個參數的類:一個字符串,其內容將成為RichText,一個字體映射。

public class RichTextDetails {private String richText;private Map<Integer, Font> fontMap;//standard getters and setters@Overridepublic int hashCode() {// The goal is to have a more efficient hashcode than standard one.return richText.hashCode();}

7.2 RichTextInfo

一個POJO,它將跟蹤RichText的位置以及其他內容:

public class RichTextInfo {private int startIndex;private int endIndex;private STYLES fontStyle;private String fontValue;// standard getters and setters, and the like

7.3樣式

一個包含要處理HTML標記的枚舉。 我們可以根據需要添加以下內容:

public enum STYLES {BOLD("b"), EM("em"), STRONG("strong"), COLOR("color"), UNDERLINE("u"), SPAN("span"), ITALLICS("i"), UNKNOWN("unknown"),PRE("pre");// standard getters and setters

7.4 TagInfo

POJO跟蹤標簽信息:

public class TagInfo {private String tagName;private String style;private int tagType;// standard getters and setters

7.5 HTML為RichText

這不是一個小類,所以讓我們按方法將其分解。

本質上,我們用div標簽將任意HTML包圍起來,因此我們知道我們在尋找什么。 然后,我們在div標簽中查找所有元素,將每個元素添加到RichTextDetails的ArrayList中,然后將整個ArrayList傳遞給mergeTextDetails方法。 mergeTextDetails返回RichtextString,這是我們需要設置單元格值的內容:

public RichTextString fromHtmlToCellValue(String html, Workbook workBook){Config.IsHTMLEmptyElementTagRecognised = true;Matcher m = HEAVY_REGEX.matcher(html);String replacedhtml = m.replaceAll("");StringBuilder sb = new StringBuilder();sb.insert(0, "<div>");sb.append(replacedhtml);sb.append("</div>");String newhtml = sb.toString();Source source = new Source(newhtml);List<RichTextDetails> cellValues = new ArrayList<RichTextDetails>();for(Element el : source.getAllElements("div")){cellValues.add(createCellValue(el.toString(), workBook));}RichTextString cellValue = mergeTextDetails(cellValues);return cellValue;}

如上所述,我們在此方法中傳遞了RichTextDetails的ArrayList。 Jericho的設置采用布爾值來識別空標簽元素,例如
:已識別Config.IsHTMLEmptyElementTag。 在與在線富文本編輯器打交道時,這可能很重要,因此我們將其設置為true。 因為我們需要跟蹤元素的順序,所以我們使用LinkedHashMap而不是HashMap。

private static RichTextString mergeTextDetails(List<RichTextDetails> cellValues) {Config.IsHTMLEmptyElementTagRecognised = true;StringBuilder textBuffer = new StringBuilder();Map<Integer, Font> mergedMap = new LinkedHashMap<Integer, Font>(550, .95f);int currentIndex = 0;for (RichTextDetails richTextDetail : cellValues) {//textBuffer.append(BULLET_CHARACTER + " ");currentIndex = textBuffer.length();for (Entry<Integer, Font> entry : richTextDetail.getFontMap().entrySet()) {mergedMap.put(entry.getKey() + currentIndex, entry.getValue());}textBuffer.append(richTextDetail.getRichText()).append(NEW_LINE);}RichTextString richText = new XSSFRichTextString(textBuffer.toString());for (int i = 0; i < textBuffer.length(); i++) {Font currentFont = mergedMap.get(i);if (currentFont != null) {richText.applyFont(i, i + 1, currentFont);}}return richText;}

如上所述,我們使用Java 9來將StringBuilder與java.util.regex.Matcher.appendReplacement結合使用 。 為什么? 那是因為StringBuffer的運行速度比StringBuilder慢。 StringBuffer函數被同步以確保線程安全,因此速度較慢。

我們使用Deque而不是Stack,因為Deque接口提供了更完整和一致的LIFO堆棧操作集:

static RichTextDetails createCellValue(String html, Workbook workBook) {Config.IsHTMLEmptyElementTagRecognised = true;Source source = new Source(html);Map<String, TagInfo> tagMap = new LinkedHashMap<String, TagInfo>(550, .95f);for (Element e : source.getChildElements()) {getInfo(e, tagMap);}StringBuilder sbPatt = new StringBuilder();sbPatt.append("(").append(StringUtils.join(tagMap.keySet(), "|")).append(")");String patternString = sbPatt.toString();Pattern pattern = Pattern.compile(patternString);Matcher matcher = pattern.matcher(html);StringBuilder textBuffer = new StringBuilder();List<RichTextInfo> textInfos = new ArrayList<RichTextInfo>();ArrayDeque<RichTextInfo> richTextBuffer = new ArrayDeque<RichTextInfo>();while (matcher.find()) {matcher.appendReplacement(textBuffer, "");TagInfo currentTag = tagMap.get(matcher.group(1));if (START_TAG == currentTag.getTagType()) {richTextBuffer.push(getRichTextInfo(currentTag, textBuffer.length(), workBook));} else {if (!richTextBuffer.isEmpty()) {RichTextInfo info = richTextBuffer.pop();if (info != null) {info.setEndIndex(textBuffer.length());textInfos.add(info);}}}}matcher.appendTail(textBuffer);Map<Integer, Font> fontMap = buildFontMap(textInfos, workBook);return new RichTextDetails(textBuffer.toString(), fontMap);}

我們可以在這里看到RichTextInfo的使用位置:

private static Map<Integer, Font> buildFontMap(List<RichTextInfo> textInfos, Workbook workBook) {Map<Integer, Font> fontMap = new LinkedHashMap<Integer, Font>(550, .95f);for (RichTextInfo richTextInfo : textInfos) {if (richTextInfo.isValid()) {for (int i = richTextInfo.getStartIndex(); i < richTextInfo.getEndIndex(); i++) {fontMap.put(i, mergeFont(fontMap.get(i), richTextInfo.getFontStyle(), richTextInfo.getFontValue(), workBook));}}}return fontMap;}

我們在哪里使用STYLES枚舉:

private static Font mergeFont(Font font, STYLES fontStyle, String fontValue, Workbook workBook) {if (font == null) {font = workBook.createFont();}switch (fontStyle) {case BOLD:case EM:case STRONG:font.setBoldweight(Font.BOLDWEIGHT_BOLD);break;case UNDERLINE:font.setUnderline(Font.U_SINGLE);break;case ITALLICS:font.setItalic(true);break;case PRE:font.setFontName("Courier New");case COLOR:if (!isEmpty(fontValue)) {font.setColor(IndexedColors.BLACK.getIndex());}break;default:break;}return font;}

我們正在使用TagInfo類來跟蹤當前標簽:

private static RichTextInfo getRichTextInfo(TagInfo currentTag, int startIndex, Workbook workBook) {RichTextInfo info = null;switch (STYLES.fromValue(currentTag.getTagName())) {case SPAN:if (!isEmpty(currentTag.getStyle())) {for (String style : currentTag.getStyle().split(";")) {String[] styleDetails = style.split(":");if (styleDetails != null && styleDetails.length > 1) {if ("COLOR".equalsIgnoreCase(styleDetails[0].trim())) {info = new RichTextInfo(startIndex, -1, STYLES.COLOR, styleDetails[1]);}}}}break;default:info = new RichTextInfo(startIndex, -1, STYLES.fromValue(currentTag.getTagName()));break;}return info;}

我們處理HTML標簽:

private static void getInfo(Element e, Map<String, TagInfo> tagMap) {tagMap.put(e.getStartTag().toString(),new TagInfo(e.getStartTag().getName(), e.getAttributeValue("style"), START_TAG));if (e.getChildElements().size() > 0) {List<Element> children = e.getChildElements();for (Element child : children) {getInfo(child, tagMap);}}if (e.getEndTag() != null) {tagMap.put(e.getEndTag().toString(),new TagInfo(e.getEndTag().getName(), END_TAG));} else {// Handling self closing tagstagMap.put(e.getStartTag().toString(),new TagInfo(e.getStartTag().getName(), END_TAG));}}

7.6創建工作表

使用StringBuilder,我創建了一個要寫入FileOutPutStream的字符串。 在實際應用中,應由用戶定義。 我在兩個不同的行上附加了文件夾路徑和文件名。 請將文件路徑更改為您自己的文件路徑。

sheet.createRow(0)在第一行創建一行,而dataRow.createCell(0)在該行的列A中創建一個單元格。

public void createWorkSheet(Workbook wb, String content, String tabName) {StringBuilder sbFileName = new StringBuilder();sbFileName.append("/Users/mike/javaSTS/michaelcgood-apache-poi-richtext/");sbFileName.append("myfile.xlsx");String fileMacTest = sbFileName.toString();try {this.fileOut = new FileOutputStream(fileMacTest);} catch (FileNotFoundException ex) {Logger.getLogger(CreateWorksheet.class.getName()).log(Level.SEVERE, null, ex);}Sheet sheet = wb.createSheet(tabName); // Create new sheet w/ Tab namesheet.setZoom(85); // Set sheet zoom: 85%// content rich textRichTextString contentRich = null;if (content != null) {contentRich = htmlToExcel.fromHtmlToCellValue(content, wb);}// begin insertion of values into cellsRow dataRow = sheet.createRow(0);Cell A = dataRow.createCell(0); // Row NumberA.setCellValue(contentRich);sheet.autoSizeColumn(0);try {/// Write the output to a filewb.write(fileOut);fileOut.close();} catch (IOException ex) {Logger.getLogger(CreateWorksheet.class.getName()).log(Level.SEVERE, null, ex);}}

8.演示

我們訪問localhost:8080 。

我們用一些HTML輸入一些文本:

我們打開excel文件,然后看到我們創建的RichText:

9.結論

我們可以看到將HTML轉換為Apache POI的RichTextString類并不是一件容易的事。 但是,對于商業應用程序而言,將HTML轉換為RichTextString至關重要,因為在Microsoft Excel文件中,可讀性很重要。 我們構建的應用程序的性能可能還有改進的余地,但我們涵蓋了構建此類應用程序的基礎。

完整的源代碼可在Github上找到。

翻譯自: https://www.javacodegeeks.com/2018/01/converting-html-richtextstring-apache-poi.html

apache poi

總結

以上是生活随笔為你收集整理的apache poi_将HTML转换为Apache POI的RichTextString的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。