https. //github. com/alanhay/html-exporter
Đây là ví dụ mã.
______0
Nếu bạn đang sử dụng bình này, cần lưu ý 3 điểm.
1. Kiểu CSS phải được xác định trong thẻ .
.pNewCounter { background: #FFC000; } table, tbody, tfoot, thead, tr, th, td, footer, header { margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline; }
2. Dữ liệu định dạng ngày phải có data-date-cell-format thuộc tính
Creation Date
06/08/2018
3. Dữ liệu văn bản phải có thuộc tính data-text-cell attribute
Offer Expiry Date 14/09/2018 14/09/2018Offered Amount 3,500,000.00 3,600,000.00Offered Amount [%] 35.000% 36.000%
HTML mẫu.
https. //github. com/callow/html-exporter/blob/master/Sample. html
Kết quả đã chuyển đổi.
https. //github. com/callow/html-exporter/blob/master/report. xlsx
Trong hướng dẫn này, chúng ta sẽ xây dựng một ứng dụng lấy HTML làm đầu vào và tạo Sổ làm việc Microsoft Excel với biểu diễn RichText của HTML đã được cung cấp. Để tạo Sổ làm việc Microsoft Excel, chúng tôi sẽ sử dụng Apache POI. Để phân tích HTML, chúng tôi sẽ sử dụng Jericho
Mã nguồn đầy đủ cho hướng dẫn này có sẵn trên Github
2. Giê-ri-cô là gì?
Jericho là một thư viện java cho phép phân tích và thao tác các phần của tài liệu HTML, bao gồm các thẻ phía máy chủ, đồng thời sao chép nguyên văn bất kỳ HTML nào không được nhận dạng hoặc không hợp lệ. Nó cũng cung cấp các chức năng thao tác biểu mẫu HTML cấp cao. Nó là một thư viện mã nguồn mở được phát hành theo các giấy phép sau. Giấy phép công cộng Eclipse [EPL], Giấy phép công cộng cấp thấp hơn GNU [LGPL] và Giấy phép Apache
Tôi thấy Jericho rất dễ sử dụng để đạt được mục tiêu chuyển đổi HTML sang RichText
3. quả bông. xml
Dưới đây là các phụ thuộc cần thiết cho ứng dụng chúng tôi đang xây dựng. Xin lưu ý rằng đối với ứng dụng này, chúng tôi phải sử dụng Java 9. Điều này là do java. sử dụng. regex appendReplacement mà chúng tôi sử dụng chỉ có sẵn kể từ Java 9
org.springframework.boot spring-boot-starter-parent 1.5.9.RELEASE UTF-8 UTF-8 9 org.springframework.boot spring-boot-starter-batch org.springframework.boot spring-boot-starter-thymeleaf com.h2database h2 runtime org.springframework.boot spring-boot-starter-test test org.apache.commons commons-lang3 3.7 org.springframework.batch spring-batch-test test org.apache.poi poi 3.15 org.apache.poi poi-ooxml 3.15 net.htmlparser.jericho jericho-html 3.4 org.springframework.boot spring-boot-configuration-processor true net.sourceforge.nekohtml nekohtml
4. Trang web – Thymeleaf
Chúng tôi sử dụng Thymeleaf để tạo một trang web cơ bản có biểu mẫu với vùng văn bản. Mã nguồn của trang Thymeleaf hiện có tại đây trên Github. Vùng văn bản này có thể được thay thế bằng RichText Editor nếu chúng ta muốn, chẳng hạn như CKEditor. Chúng ta chỉ cần chú ý làm cho dữ liệu cho AJAX chính xác, sử dụng phương thức setData thích hợp. Có một bài hướng dẫn trước về CKeditor với tiêu đề AJAX with CKEditor in Spring Boot
5. Bộ điều khiển
Trong bộ điều khiển của chúng tôi, chúng tôi Autowire JobLauncher và một công việc Spring Batch mà chúng tôi sẽ tạo có tên là GenerateExcel. Tự động kết nối hai lớp này cho phép chúng tôi chạy Spring Batch Job GenerateExcel theo yêu cầu khi yêu cầu POST được gửi tới “/export”
Một điều khác cần lưu ý là để đảm bảo rằng công việc Spring Batch sẽ chạy nhiều lần, chúng tôi bao gồm các tham số duy nhất với mã này. addLong[“tính duy nhất”, Hệ thống. nanoTime[]]. toJobParameter[]. Có thể xảy ra lỗi nếu chúng tôi không bao gồm các tham số duy nhất vì chỉ có JobInstance duy nhất mới có thể được tạo và thực thi và Spring Batch không có cách nào phân biệt giữa JobInstance thứ nhất và thứ hai nếu không
@Controller public class WebController { private String currentContent; @Autowired JobLauncher jobLauncher; @Autowired GenerateExcel 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. Công việc hàng loạt
Trong Bước 1 của Batch job, chúng ta gọi phương thức getCurrentContent[] để lấy nội dung được chuyển vào biểu mẫu Thymeleaf, tạo XSSFWorkbook mới, chỉ định tên tab Trang tính Microsoft Excel tùy ý, sau đó chuyển cả ba biến vào phương thức createWorksheet
@Configuration @EnableBatchProcessing @Lazy public class GenerateExcel { List docIds = new ArrayList[]; @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; @Autowired WebController webcontroller; @Autowired CreateWorksheet createexcel; @Bean public Step step1[] { return stepBuilderFactory.get["step1"] .tasklet[new Tasklet[] { @Override public 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[]; } @Bean public Job ExcelGenerator[] { return jobBuilderFactory.get["ExcelGenerator"] .start[step1[]] .build[]; } }
Chúng tôi đã đề cập đến Spring Batch trong các hướng dẫn khác, chẳng hạn như Chuyển đổi XML thành JSON + Spring Batch và Xử lý CSV Spring Batch
7. Dịch vụ tạo excel
Chúng tôi sử dụng nhiều lớp khác nhau để tạo tệp Microsoft Excel của mình. Thứ tự quan trọng khi xử lý chuyển đổi HTML sang RichText, vì vậy đây sẽ là trọng tâm
7. 1 RichTextChi tiết
Một lớp có hai tham số. một Chuỗi sẽ có nội dung của chúng tôi sẽ trở thành RichText và bản đồ phông chữ
public class RichTextDetails { private String richText; private Map fontMap; //standard getters and setters @Override public int hashCode[] { // The goal is to have a more efficient hashcode than standard one. return richText.hashCode[]; }
7. 2 RichTextInfo
Một POJO sẽ theo dõi vị trí của RichText và những gì không
________số 87. 3 phong cách
Một enum để chứa các thẻ HTML mà chúng tôi muốn xử lý. Chúng ta có thể thêm vào đây khi cần thiết
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 TagThông tin
Một POJO để theo dõi thông tin thẻ
.pNewCounter { background: #FFC000; } table, tbody, tfoot, thead, tr, th, td, footer, header { margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline; }0
7. 5 HTML sang RichText
Đây không phải là một lớp nhỏ, vì vậy hãy chia nhỏ nó theo phương pháp
Về cơ bản, chúng tôi đang bao quanh bất kỳ HTML tùy ý nào bằng thẻ div, vì vậy chúng tôi biết những gì chúng tôi đang tìm kiếm. Sau đó, chúng tôi tìm kiếm tất cả các phần tử trong thẻ div, thêm từng phần tử vào ArrayList của RichTextDetails và sau đó chuyển toàn bộ ArrayList sang phương thức mergeTextDetails. mergeTextDetails trả về RichtextString, đây là thứ chúng ta cần để đặt giá trị ô
.pNewCounter { background: #FFC000; } table, tbody, tfoot, thead, tr, th, td, footer, header { margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline; }1
Như chúng ta đã thấy ở trên, chúng ta truyền một ArrayList của RichTextDetails trong phương thức này. Jericho có một cài đặt nhận giá trị boolean để nhận dạng các phần tử thẻ trống, chẳng hạn như
. cấu hình. IsHTMLEmptyElementTagRecognised. Điều này có thể quan trọng khi xử lý các trình soạn thảo văn bản đa dạng thức trực tuyến, vì vậy chúng tôi đặt điều này thành true. Vì chúng tôi cần theo dõi thứ tự của các phần tử nên chúng tôi sử dụng LinkedHashMap thay vì HashMap.
.pNewCounter { background: #FFC000; } table, tbody, tfoot, thead, tr, th, td, footer, header { margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline; }2
Như đã đề cập ở trên, chúng tôi đang sử dụng Java 9 để sử dụng StringBuilder với java. sử dụng. biểu thức chính quy. người mai mối. nối thêmThay thế. Tại sao? . Các chức năng StringBuffer được đồng bộ hóa để đảm bảo an toàn cho luồng và do đó chậm hơn
Chúng tôi đang sử dụng Deque thay vì Stack vì một bộ hoạt động ngăn xếp LIFO đầy đủ và nhất quán hơn được cung cấp bởi giao diện Deque
.pNewCounter { background: #FFC000; } table, tbody, tfoot, thead, tr, th, td, footer, header { margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline; }3
Chúng ta có thể thấy RichTextInfo được sử dụng ở đâu tại đây
@Controller public class WebController { private String currentContent; @Autowired JobLauncher jobLauncher; @Autowired GenerateExcel 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 }0
Nơi chúng tôi sử dụng STYLES enum
@Controller public class WebController { private String currentContent; @Autowired JobLauncher jobLauncher; @Autowired GenerateExcel 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 }1
Chúng tôi đang sử dụng lớp TagInfo để theo dõi thẻ hiện tại
@Controller public class WebController { private String currentContent; @Autowired JobLauncher jobLauncher; @Autowired GenerateExcel 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 }2
Chúng tôi xử lý các thẻ HTML
@Controller public class WebController { private String currentContent; @Autowired JobLauncher jobLauncher; @Autowired GenerateExcel 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 }3
7. 6 Tạo trang tính
Sử dụng StringBuilder, tôi tạo một Chuỗi sẽ được ghi vào FileOutPutStream. Trong một ứng dụng thực tế, điều này phải do người dùng xác định. Tôi đã thêm đường dẫn thư mục và tên tệp của mình trên hai dòng khác nhau. Vui lòng thay đổi đường dẫn tệp thành của riêng bạn
tờ giấy. createRow[0] tạo một hàng trên dòng đầu tiên và dataRow. createCell[0] tạo một ô trong cột A của hàng
@Controller public class WebController { private String currentContent; @Autowired JobLauncher jobLauncher; @Autowired GenerateExcel 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 }4
8. Thử nghiệm
Chúng tôi truy cập localhost. 8080
Chúng tôi nhập một số văn bản với một số HTML
Chúng tôi mở tệp excel của bạn và xem Văn bản đa dạng thức mà chúng tôi đã tạo
9. Sự kết luận
Chúng ta có thể thấy việc chuyển đổi HTML sang lớp RichTextString của Apache POI không hề đơn giản; . Có khả năng cải thiện hiệu suất của ứng dụng mà chúng tôi xây dựng, nhưng chúng tôi đã đề cập đến nền tảng của việc xây dựng một ứng dụng như vậy