From cf9644ef29aa0344c8f4ab71d0d5b93712f702d8 Mon Sep 17 00:00:00 2001 From: zangshuihua <1920114288@qq.com> Date: Fri, 21 Oct 2022 08:56:20 +0800 Subject: [PATCH] =?UTF-8?q?2022/10/21=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../shate/DateUploadController.java | 14 +- .../web/controller/shate/PoiController.java | 199 ------ .../CustomXWPFDocument.java | 6 +- .../utils/chartForWord/ExportUtils.java | 209 ------ .../utils/chartForWord/GenerateWord.java | 110 --- .../utils/chartForWord/PoiChartsTools.java | 651 ------------------ .../utils/chartForWord/PoiWordUtil.java | 299 -------- ruoyi-common/src/main/resources/V3.0.docx | Bin 61475 -> 0 bytes 8 files changed, 13 insertions(+), 1475 deletions(-) delete mode 100644 ruoyi-admin/src/main/java/com/ruoyi/web/controller/shate/PoiController.java rename ruoyi-common/src/main/java/com/ruoyi/common/utils/{chartForWord => }/CustomXWPFDocument.java (96%) delete mode 100644 ruoyi-common/src/main/java/com/ruoyi/common/utils/chartForWord/ExportUtils.java delete mode 100644 ruoyi-common/src/main/java/com/ruoyi/common/utils/chartForWord/GenerateWord.java delete mode 100644 ruoyi-common/src/main/java/com/ruoyi/common/utils/chartForWord/PoiChartsTools.java delete mode 100644 ruoyi-common/src/main/java/com/ruoyi/common/utils/chartForWord/PoiWordUtil.java delete mode 100644 ruoyi-common/src/main/resources/V3.0.docx diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/shate/DateUploadController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/shate/DateUploadController.java index 305e9c8..0f874fa 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/shate/DateUploadController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/shate/DateUploadController.java @@ -2,7 +2,7 @@ package com.ruoyi.web.controller.shate; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.utils.BarChart; -import com.ruoyi.common.utils.chartForWord.CustomXWPFDocument; +import com.ruoyi.common.utils.CustomXWPFDocument; import com.ruoyi.common.utils.shate.PageUtils; import com.ruoyi.system.domain_shate.*; @@ -11,7 +11,6 @@ import com.ruoyi.system.service_shate.IPlantingSuitabilityService; import com.ruoyi.system.service_shate.ISeedingSuccessService; import com.ruoyi.system.service_shate.IVegetationHealthServices; import io.swagger.annotations.Api; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.ResourceUtils; import org.springframework.web.bind.annotation.*; import org.w3c.dom.Document; @@ -560,11 +559,16 @@ public class DateUploadController //创建第一个段落的内容 BarChart.createParagraphAndInsertWord(docxDocument, "Date time: "+year); BarChart.createParagraphAndInsertWord(docxDocument, "Evaluation area: "+zone); + + //创建第二段落的标题 BarChart.createFirstLevelTopic(docxDocument, "2.Results of remote sensing monitoring of seeding success rate"); //循环判断有多少个资源 List seedingSuccessRates = seedingSuccessService.sqlSeeding(zone, year); for (SeedingSuccessRate seedingSuccessRate : seedingSuccessRates) { + //图片的url + //String productCode1 = seedingSuccessRate.getProductCode1(); + //String productCode2 = seedingSuccessRate.getProductCode2(); //创建第二段落的内容 BarChart.insertPic(docxDocument, "C:\\Users\\xkrs\\Desktop\\pic\\1.png"); BarChart.setPicTitle(docxDocument, "Spatial distribution data of successful seeding regions"); @@ -577,7 +581,9 @@ public class DateUploadController //获取ProductCode1的集合 List M_code=new ArrayList<>(); List H_code=new ArrayList<>(); + //查询数据库中有多少条数据 List vegetationHealths = vegetationHealthServices.sqlInfo(zone, year); + //循环查询的数据分别加入到不同的集合中作为中质量和高质量的循环次数 for (VegetationHealth vegetationHealth : vegetationHealths) { String productCode1 = vegetationHealth.getProductCode1(); if(productCode1.startsWith("M")) @@ -637,6 +643,8 @@ public class DateUploadController List plantingSuitabilities = plantingSuitabilityService.sqlSeeding(zone); for (PlantingSuitability suitability : plantingSuitabilities) { BarChart.createFirstLevelTopic(docxDocument,"4.Results of remote sensing monitoring of planting suitability"); + //获取图片的url + String productCode1 = suitability.getProductCode1(); //第四个标题的内容 BarChart.insertPic(docxDocument,"C:\\Users\\xkrs\\Desktop\\pic\\1.png"); BarChart.setPicTitle(docxDocument,"Spatial distribution data of planting suitability"); @@ -647,7 +655,7 @@ public class DateUploadController Double s3 = suitability.getNotSuitable(); Double[] yAxisData2 = new Double[]{s1, s2, s3}; BarChart.drawTable(docxDocument,xAxisData2,yAxisData2); - BarChart.setPicTitle(docxDocument,"Spatial distribution data of planting suitability"); + BarChart.setPicTitle(docxDocument,"Classification statistics of planting suitability"); BarChart.createParagraphAndInsertWord(docxDocument,"In "+suitability.getZone()+" region, the area of very suitable region was "+suitability.getVerySuitable()+" hm², accounting for "+BarChart.getDoubleNumber((suitability.getVerySuitable()/suitability.getTotalArea())*100)+"%. The area of suitable grade was "+suitability.getSuitable()+" hm², accounting for "+BarChart.getDoubleNumber((suitability.getSuitable()/suitability.getTotalArea())*100)+"%. The area of unsuitable area was "+suitability.getNotSuitable()+" hm², accounting for "+BarChart.getDoubleNumber((suitability.getNotSuitable()/suitability.getTotalArea())*100)+"%."); } response.setCharacterEncoding("UTF-8"); diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/shate/PoiController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/shate/PoiController.java deleted file mode 100644 index c74b2f1..0000000 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/shate/PoiController.java +++ /dev/null @@ -1,199 +0,0 @@ -package com.ruoyi.web.controller.shate; - -import cn.hutool.core.collection.CollUtil; -import com.ruoyi.common.utils.chartForWord.CustomXWPFDocument; -import com.ruoyi.common.utils.chartForWord.ExportUtils; -import com.ruoyi.common.utils.chartForWord.PoiChartsTools; -import com.ruoyi.common.utils.chartForWord.PoiWordUtil; -import com.ruoyi.system.service_shate.impl.DateUploadServiceImpl; -import org.apache.poi.ooxml.POIXMLDocumentPart; -import org.apache.poi.xwpf.usermodel.XWPFTable; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServletResponse; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * 操作word - * @author shuaihua zang - * http://localhost:9080/poi/barCharts - */ -@RestController -public class PoiController { - - - - @GetMapping("/poi/barCharts") - public void barCharts(HttpServletResponse response) { - - - - try (InputStream is = this.getClass().getClassLoader() - .getResourceAsStream("V3.0.docx"); - ServletOutputStream out = response.getOutputStream()) { - if (is == null) { - throw new RuntimeException("未找到模板信息"); - } - //XWPFDocument doc = new XWPFDocument(is); - CustomXWPFDocument doc = new CustomXWPFDocument(is); - this.doBarCharts(PoiChartsTools.getPOIXMLDocumentPart(doc, - "/word/charts/chart1.xml")); - this.doBarCharts(PoiChartsTools.getPOIXMLDocumentPart(doc, - "/word/charts/chart2.xml")); - this.doBarCharts(PoiChartsTools.getPOIXMLDocumentPart(doc, - "/word/charts/chart3.xml")); - ExportUtils exportUtils=new ExportUtils(); - exportUtils.insertImage(doc); - exportUtils.insertText(doc); - - - response.setCharacterEncoding("UTF-8"); - response.setContentType("application/msword"); - //response.setContentType("application/octet-stream"); - //String filename = "test.docx"; - //response.setHeader("Content-disposition", "attachment;filename=" - //+ URLEncoder.encode(filename, "UTF-8")); - //doc.write(out); - //out.flush(); - String fileName = "Evaluation report of planting monitoring in ITBA Nature Reserve - V3.0.docx"; - response.setHeader("Content-Disposition", "attachment;fileName=" + new String(fileName.getBytes("UTF-8"), "ISO-8859-1")); - ServletOutputStream responseOutputStream = response.getOutputStream(); - doc.write(responseOutputStream); - responseOutputStream.flush(); - responseOutputStream.close(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - /** - * 处理图表数据-柱状图 - */ - public void doBarCharts(POIXMLDocumentPart chart1) { - /*// 行 标题 - List titleArr = CollUtil.newArrayList(" ", "Health","Normal","Not-Health"); - // 字段名 - List fldNameArr = CollUtil.newArrayList("item1", "item2","item3","item4"); - // 数据集合 - List> listItemsByType = new ArrayList>(); - Map base1 = new HashMap<>(4); - base1.put("item1", " " ); - base1.put("item2", "1000"); - base1.put("item3", "700"); - base1.put("item4", "1200" ); - listItemsByType.add(base1);*/ - // 行 标题 - List titleArr = CollUtil.newArrayList(" ", "date"); - // 字段名 - List fldNameArr = CollUtil.newArrayList("item1", "item2"); - // 数据集合 - List> listItemsByType = new ArrayList>(); - for(int i=0;i<3;i++) - { - if(i==0) - { - Map base1 = new HashMap<>(2); - base1.put("item1", "Health" ); - base1.put("item2", "100"); - listItemsByType.add(base1); - } - if(i==1) - { - Map base1 = new HashMap<>(2); - base1.put("item1", "Normal" ); - base1.put("item2", "300"); - listItemsByType.add(base1); - } - if(i==2) - { - Map base1 = new HashMap<>(2); - base1.put("item1", "Not-Health" ); - base1.put("item2", "500"); - listItemsByType.add(base1); - } - - } - - - - PoiChartsTools.replaceBarCharts(chart1, titleArr, fldNameArr, listItemsByType); - } - - - /** - * 处理图表数据-折线图 - */ - private void doLineChart(POIXMLDocumentPart chart) { - // 行 标题 - List titleArr = CollUtil.newArrayList("类别", "系列1", "系列2", "系列3"); - // 字段名 - List fldNameArr = CollUtil.newArrayList("item1", "item2", "item3", "item4"); - // 数据集合 - List> listItemsByType = new ArrayList>(); - for (int i = 1; i < 5; i++) { - Map base1 = new HashMap<>(4); - base1.put("item1", "折线图" + i); - base1.put("item2", "100"); - base1.put("item3", "20"); - base1.put("item4", "3"); - listItemsByType.add(base1); - } - PoiChartsTools.replaceLineCharts(chart, titleArr, fldNameArr, listItemsByType); - } - - /** - * 处理图表数据-饼图 - */ - private void doPieCharts(POIXMLDocumentPart chart) { - // 行 标题 - List titleArr = CollUtil.newArrayList("类别", "系列1", "系列2", "系列3"); - // 字段名 - List fldNameArr = CollUtil.newArrayList("item1", "item2", "item3", "item4"); - // 数据集合 - List> listItemsByType = new ArrayList>(); - for (int i = 1; i < 5; i++) { - Map base1 = new HashMap<>(4); - base1.put("item1", "饼图" + i); - base1.put("item2", "100"); - base1.put("item3", "20"); - base1.put("item4", "3"); - listItemsByType.add(base1); - } - PoiChartsTools.replacePieCharts(chart, titleArr, fldNameArr, listItemsByType); - } - - /** - * 处理表格-新增行 - */ - private void insertTable(XWPFTable table) { - List> tableList = new ArrayList<>(); - List table1 = new ArrayList<>(); - table1.add(new String[]{"1", "张三", "男", "22", "186xxxxxxxx"}); - table1.add(new String[]{"2", "李四", "女", "23", "187xxxxxxxx"}); - table1.add(new String[]{"3", "王五", "男", "24", "188xxxxxxxx"}); - table1.add(new String[]{"4", "赵六", "女", "25", "189xxxxxxxx"}); - tableList.add(table1); - PoiWordUtil.insertTable(table, table1, 2); - PoiWordUtil.mergeCellsHorizontal(table, 0, 0, 1); - PoiWordUtil.mergeCellsHorizontal(table, 0, 3, 4); - } - - /** - * 处理表格-替换表格中信息 - */ - private void replaceTable(XWPFTable table) { - Map params = new HashMap<>(); - params.put("name", "XXXWord"); - params.put("start", "2021-04-21"); - params.put("end", "2021-04-28"); - PoiWordUtil.replaceTableParams(table, params); - } - - -} \ No newline at end of file diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/chartForWord/CustomXWPFDocument.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/CustomXWPFDocument.java similarity index 96% rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/chartForWord/CustomXWPFDocument.java rename to ruoyi-common/src/main/java/com/ruoyi/common/utils/CustomXWPFDocument.java index c0d86ce..0500131 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/chartForWord/CustomXWPFDocument.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/CustomXWPFDocument.java @@ -1,11 +1,9 @@ -package com.ruoyi.common.utils.chartForWord; +package com.ruoyi.common.utils; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; - import org.apache.poi.openxml4j.opc.OPCPackage; -import org.apache.poi.sl.usermodel.PictureData; + import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFParagraph; import org.apache.xmlbeans.XmlException; diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/chartForWord/ExportUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/chartForWord/ExportUtils.java deleted file mode 100644 index 7aab323..0000000 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/chartForWord/ExportUtils.java +++ /dev/null @@ -1,209 +0,0 @@ -package com.ruoyi.common.utils.chartForWord; - - -import com.ruoyi.common.utils.StringFilterUtil; -import com.ruoyi.common.utils.chartForWord.CustomXWPFDocument; -import org.apache.poi.openxml4j.exceptions.InvalidFormatException; -import org.apache.poi.xwpf.usermodel.*; - -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServletResponse; -import java.io.*; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.*; -import java.util.List; - -/** - * @Author shuaihua zang - * @date 2022/10/8 - * 导出word的工具类 - */ - -public class ExportUtils { - - - /** - * 读取模板 - * - * @throws Exception - */ - - public void operatorWord(HttpServletResponse response) throws Exception { - //获得模板文件 - InputStream docis = new FileInputStream("C:\\Users\\xkrs\\Desktop\\V3.0.docx"); - //转成word - CustomXWPFDocument document = new CustomXWPFDocument(docis); - - //写入图片 - this.insertImage(document); - //段落替换对象 - this.insertText(document); - //把doc输出到输出流 - response.setCharacterEncoding("UTF-8"); - response.setContentType("application/msword"); - //文件名 - String fileName = "Evaluation report of planting monitoring in ITBA Nature Reserve - V2.0.docx"; - response.setHeader("Content-Disposition", "attachment;fileName=" + new String(fileName.getBytes("UTF-8"), "ISO-8859-1")); - ServletOutputStream responseOutputStream = response.getOutputStream(); - document.write(responseOutputStream); - responseOutputStream.flush(); - responseOutputStream.close(); - //in.close(); - - - } - - /** - * 写入图片在word中 - * @param document - * @throws IOException - * @throws InvalidFormatException - */ - public void insertImage(CustomXWPFDocument document) throws Exception{ - - //定义一个URL对象 - URL url = new URL("https://rs.sensetime.com/sl-temp/thumbs/cc1hsd7ng0b90dum9jcg.png"); - //打开连接 - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - //设置请求方式为"GET" - conn.setRequestMethod("GET"); - //超时响应时间为10秒 - conn.setConnectTimeout(10 * 1000); - InputStream in = conn.getInputStream(); - //图片 - //FileInputStream in = new FileInputStream("https://rs.sensetime.com/sl-temp/thumbs/cc1hsd7ng0b90dum9jcg.png"); - //段落集合 - List paragraphs = document.getParagraphs(); - for (XWPFParagraph paragraph : paragraphs) { - //获取到段落中的所有文本内容 - String text = paragraph.getText(); - //判断此段落中是否有需要进行替换的文本 - if (checkText(text)) { - List runs = paragraph.getRuns(); - for (XWPFRun run : runs) { - //替换模板原来位置 - String key = "${ct_pg2_image_1}"; - //if (run.toString().indexOf(key) != -1) { - if (run.text().contains(key)) { - byte[] ba = new byte[in.available()]; - int len = in.read(ba); - ByteArrayInputStream byteInputStream = new ByteArrayInputStream(ba, 0, len); - //设置图片 - document.addPictureData(byteInputStream, XWPFDocument.PICTURE_TYPE_PNG); - //创建一个word图片,并插入到文档中-->像素可改 - document.createPicture(document.getAllPictures().size() - 1, 100, 100, paragraph); - } - break; - } - //break; - } - } - in.close(); - } - public void insertText (CustomXWPFDocument document){ - //声明替换模板对象 - Map textMap = new HashMap(); - textMap.put("${ct_1}", "11"); - textMap.put("${ct_2}", "12"); - textMap.put("${ct_3}", "13"); - textMap.put("${ct_4}", "14"); - textMap.put("${ct_5}", "15"); - textMap.put("${ct_6}", "16"); - textMap.put("${ct_7}", "17"); - textMap.put("${ct_8}", "18"); - textMap.put("${ct_9}", "19"); - textMap.put("${ct_10}", "20"); - textMap.put("${ct_11}", "21"); - textMap.put("${ct_12}", "22"); - textMap.put("${ct_13}", "23"); - textMap.put("${ct_14}", "24"); - textMap.put("${ct_1515}", "25"); - textMap.put("${ct_16}", "26"); - textMap.put("${ct_17}", "27"); - textMap.put("${ct_18}", "28"); - textMap.put("${ct_19}", "29"); - textMap.put("${ct_20}", "30"); - textMap.put("${ct_21}", "31"); - textMap.put("${ct_22}", "32"); - textMap.put("${ct_23}", "33"); - textMap.put("${ct_24}", "34"); - textMap.put("${ct_25}", "35"); - textMap.put("${ct_26}", "36"); - textMap.put("${ct_27}", "37"); - textMap.put("${ct_28}", "38"); - textMap.put("${ct_29}", "39"); - //替换模板数据 - changeText(document, textMap); - } - - /** - * 替换段落文本 - * - * @param document docx解析对象 - * @param textMap 需要替换的信息集合 - */ - public static void changeText (XWPFDocument document, Map < String, Object > textMap){ - //获取段落集合 - List paragraphs = document.getParagraphs(); - for (XWPFParagraph paragraph : paragraphs) { - //获取到段落中的所有文本内容 - String text = paragraph.getText(); - //判断此段落中是否有需要进行替换的文本 - if (checkText(text)) { - List runs = paragraph.getRuns(); - for (XWPFRun run : runs) { - //替换模板原来位置 - //System.out.println(run.text()); - run.setText(changeText_$(run.text()) + (String) changeValue(run.text().toString(), textMap), 0); - } - } - } - - } - /** - * 判断文本中是否包含$ - * - * @param text 文本 - * @return 包含返回true, 不包含返回false - */ - public static boolean checkText (String text){ - boolean check = false; - if (text.indexOf("$") != -1) { - check = true; - } - return check; - } - /** - * 替换模板${} - */ - private static Object changeValue (String value, Map < String, Object > textMap){ - Set> textSets = textMap.entrySet(); - Object valu = ""; - for (Map.Entry textSet : textSets) { - // 匹配模板与替换值 格式${key} - String key = textSet.getKey(); - if (value.contains(key)) { - valu = (String) textSet.getValue(); - } - } - return valu; - } - - /** - * 替换原先段落中的${} - * @param text - * @return - */ - public static String changeText_$ (String text) - { - - if (!text.contains("$")) { - return text; - } - String filterForBetween = StringFilterUtil.filterForBetween(text, '$', '}'); - System.out.println(filterForBetween); - return filterForBetween; - } - - } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/chartForWord/GenerateWord.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/chartForWord/GenerateWord.java deleted file mode 100644 index bcfe218..0000000 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/chartForWord/GenerateWord.java +++ /dev/null @@ -1,110 +0,0 @@ -package com.ruoyi.common.utils.chartForWord; -import com.ruoyi.common.utils.BarChart; -import com.ruoyi.common.utils.chartForWord.CustomXWPFDocument; -import org.apache.poi.xwpf.usermodel.*; -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - - -/** - * 生成动态word - * @author shuaihua zang - * @date 2022/10/13 - */ - -public class GenerateWord { - - public static void makeWord(HttpServletResponse response,HttpServletRequest request,int pg2_size,int pg3_size)throws Exception { - - //创建文本对象 - CustomXWPFDocument docxDocument = new CustomXWPFDocument(); - //secondRun.setColor("FFC0CB"); - //secondRun.setUnderline(UnderlinePatterns.SINGLE); - //paragraph_2_title_run.addCarriageReturn(); - //paragraphX2.setIndentationFirstLine(420);//首行缩进 - //paragraph_2_title.setStyle("2"); - - //创建标题 - BarChart.setTitle(docxDocument,"Evaluation report of planting monitoring in ITBA Nature Reserve"); - - //创建第一个段落的标题 - BarChart.createFirstLevelTopic(docxDocument, "1.Background information"); - //创建第一个段落的内容 - BarChart.createParagraphAndInsertWord(docxDocument, "Date time:${ct_pg1_1}"); - BarChart.createParagraphAndInsertWord(docxDocument, "Evaluation area:${ct_pg1_2}"); - - //创建第二段落的标题 - BarChart.createFirstLevelTopic(docxDocument, "2.Results of remote sensing monitoring of seeding success rate"); - //循环判断有多少个资源 - for (int i = 0; i < pg2_size; i++) { - //创建第二段落的内容 - BarChart.insertPic(docxDocument, "C:\\Users\\xkrs\\Desktop\\pic\\1.png"); - BarChart.setPicTitle(docxDocument, "Spatial distribution data of successful seeding regions"); - BarChart.insertPic(docxDocument, "C:\\Users\\xkrs\\Desktop\\pic\\2.png"); - BarChart.setPicTitle(docxDocument, "Spatial distribution data of seeding success rate"); - BarChart.createParagraphAndInsertWord(docxDocument, "${ct_pg2_wz_1}.The total planting area in ${ct_pg2_wz_2} area was ${ct_pg2_wz_3} hm2, the vegetation survival area was ${ct_pg2_wz_4} hm2, and the seeding success rate was ${ct_pg2_wz_5} %."); - } - //第三段的标题 - BarChart.createFirstLevelTopic(docxDocument, "3.Results of remote sensing monitoring of vegetation health"); - for(int i = 1; i <=pg3_size; i=i+2) { - int j=i+1; - //第三段的内容 - //第三段的第一个小标题 - BarChart.createSecondLevelTopic(docxDocument, "3."+i+".Monitoring results of medium resolution data"); - //第三段的第一个小标题的内容 - BarChart.insertPic(docxDocument, "C:\\Users\\xkrs\\Desktop\\pic\\2.png"); - BarChart.setPicTitle(docxDocument, "Spatial distribution data of vegetation planting area"); - BarChart.insertPic(docxDocument, "C:\\Users\\xkrs\\Desktop\\pic\\1.png"); - BarChart.setPicTitle(docxDocument, "Spatial distribution data of vegetation health status"); - //插入柱状图表 - String[] xAxisData = new String[]{"Health", "Normal", "Not-Health"}; - Integer[] yAxisData = new Integer[]{1000, 700, 1200}; - //BarChart.drawTable(docxDocument,xAxisData,yAxisData); - - - BarChart.setPicTitle(docxDocument, "Statistical data on vegetation health"); - BarChart.createParagraphAndInsertWord(docxDocument, "2022-06-04.Based on the monitoring results of high resolution satellite images, the area of healthy vegetation growth in 01 region was 1202.8 hm2, accounting for 40.7%. The area with normal vegetation growth was 749.9 hm2, accounting for 25.4%. The area of unhealthy vegetation growth was 1000.2 hm2, accounting for 33.9%."); - //第三段的第二个小标题 - BarChart.createSecondLevelTopic(docxDocument, "3."+j+".Monitoring results of high resolution data"); - //第三段的第二个小标题的内容 - BarChart.insertPic(docxDocument, "C:\\Users\\xkrs\\Desktop\\pic\\1.png"); - BarChart.setPicTitle(docxDocument, "Spatial distribution data of vegetation planting area"); - BarChart.insertPic(docxDocument, "C:\\Users\\xkrs\\Desktop\\pic\\2.png"); - BarChart.setPicTitle(docxDocument, "Spatial distribution data of vegetation health status"); - //此处插入图表 - String[] xAxisData1 = new String[]{"Health", "Normal", "Not-Health"}; - Integer[] yAxisData1 = new Integer[]{1000, 700, 1200}; - //BarChart.drawTable(docxDocument,xAxisData1,yAxisData1); - BarChart.setPicTitle(docxDocument, "Statistical data on vegetation health"); - BarChart.createParagraphAndInsertWord(docxDocument, "2022-06-04.Based on the monitoring results of high resolution satellite images, the area of healthy vegetation growth in 01 region was 1202.8 hm2, accounting for 40.7%. The area with normal vegetation growth was 749.9 hm2, accounting for 25.4%. The area of unhealthy vegetation growth was 1000.2 hm2, accounting for 33.9%."); - - } - - //第四个标题 - BarChart.createFirstLevelTopic(docxDocument,"4.Results of remote sensing monitoring of planting suitability"); - //第四个标题的内容 - BarChart.insertPic(docxDocument,"C:\\Users\\xkrs\\Desktop\\pic\\1.png"); - BarChart.setPicTitle(docxDocument,"Spatial distribution data of planting suitability"); - //此处插入图表 - String[] xAxisData2 = new String[]{"Health", "Normal", "Not-Health"}; - Integer[] yAxisData2 = new Integer[]{1000, 700, 1200}; - //BarChart.drawTable(docxDocument,xAxisData2,yAxisData2); - BarChart.setPicTitle(docxDocument,"Spatial distribution data of planting suitability"); - BarChart.createParagraphAndInsertWord(docxDocument,"In 01 region, the area of very suitable region was 1202.8 hm2, accounting for 40.7%. The area of suitable grade was 749.9 hm2, accounting for 25.4%. The area of unsuitable area was 1000.2 hm2, accounting for 33.9%."); - response.setCharacterEncoding("UTF-8"); - response.setContentType("application/msword"); - //文件名 - String fileName = "Evaluation report of planting monitoring in ITBA Nature Reserve - V2.0.docx"; - response.setHeader("Content-Disposition","attachment;fileName="+new - - String(fileName.getBytes("UTF-8"), "ISO-8859-1")); - - ServletOutputStream responseOutputStream = response.getOutputStream(); - docxDocument.write(responseOutputStream); - responseOutputStream.flush(); - responseOutputStream.close(); - -} - -} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/chartForWord/PoiChartsTools.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/chartForWord/PoiChartsTools.java deleted file mode 100644 index 6e5ed65..0000000 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/chartForWord/PoiChartsTools.java +++ /dev/null @@ -1,651 +0,0 @@ -package com.ruoyi.common.utils.chartForWord; -import org.apache.poi.ooxml.POIXMLDocumentPart; -import org.apache.poi.ss.usermodel.Sheet; -import org.apache.poi.ss.usermodel.Workbook; -import org.apache.poi.ss.util.CellRangeAddress; -import org.apache.poi.xssf.usermodel.XSSFWorkbook; -import org.apache.poi.xwpf.usermodel.XWPFChart; -import org.apache.poi.xwpf.usermodel.XWPFDocument; -import org.apache.poi.xwpf.usermodel.XWPFTableCell; -import org.openxmlformats.schemas.drawingml.x2006.chart.*; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.*; -import org.springframework.stereotype.Component; - -import java.io.IOException; -import java.io.OutputStream; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * poi操作word中图表的工具类 - * - * @author shuaihua zang - * @date 2022/10/10 - */ -@Component -public class PoiChartsTools { - - private static final BigDecimal bd2 = new BigDecimal("2"); - - /** - * 获取word模板中的所有图表元素,用map存放 - */ - public static Map getPOIXMLDocumentPartMap(XWPFDocument doc) { - // 获取word模板中的所有图表元素,用map存放 - // 为什么不用list保存:查看doc.getRelations()的源码可知,源码中使用了hashMap读取文档图表元素, - // 对relations变量进行打印后发现,图表顺序和文档中的顺序不一致,也就是说relations的图表顺序不是文档中从上到下的顺序 - Map chartsMap = new HashMap<>(); - //动态刷新图表 - List relations = doc.getRelations(); - for (POIXMLDocumentPart poixmlDocumentPart : relations) { - if (poixmlDocumentPart instanceof XWPFChart) { // 如果是图表元素 - String str = poixmlDocumentPart.toString(); - String key = str.replaceAll("Name: ", "") - .replaceAll(" - Content Type: application/vnd\\.openxmlformats-officedocument\\.drawingml\\.chart\\+xml", "") - .trim(); - chartsMap.put(key, poixmlDocumentPart); - } - } - return chartsMap; - } - - /** - * 获取word模板中的对应名称的图表元素 - * 返回null则查询不到 - */ - public static POIXMLDocumentPart getPOIXMLDocumentPart(XWPFDocument doc, String chartsName) { - List relations = doc.getRelations(); - for (POIXMLDocumentPart poixmlDocumentPart : relations) { - // 如果是图表元素 - if (poixmlDocumentPart instanceof XWPFChart) { - String str = poixmlDocumentPart.toString(); - String key = str.replaceAll("Name: ", "") - .replaceAll(" - Content Type: application/vnd\\.openxmlformats-officedocument\\.drawingml\\.chart\\+xml", "") - .trim(); - if (key.equals(chartsName)){ - return poixmlDocumentPart; - } - } - } - return null; - } - - /** - * 调用替换柱状图数据 - */ - public static void replaceBarCharts(POIXMLDocumentPart poixmlDocumentPart, - List titleArr, List fldNameArr, List> listItemsByType) { - XWPFChart chart = (XWPFChart) poixmlDocumentPart; - chart.getCTChart(); - - //根据属性第一列名称切换数据类型 - CTChart ctChart = chart.getCTChart(); - CTPlotArea plotArea = ctChart.getPlotArea(); - - CTBarChart barChart = plotArea.getBarChartArray(0); - List BarSerList = barChart.getSerList(); // 获取柱状图单位 - - //刷新内置excel数据 - refreshExcel(chart, listItemsByType, fldNameArr, titleArr); - //刷新页面显示数据 - refreshBarStrGraphContent(barChart, BarSerList, listItemsByType, fldNameArr, 1); - - } - - - /** - * 调用替换折线图数据 - */ - public static void replaceLineCharts(POIXMLDocumentPart poixmlDocumentPart, - List titleArr, List fldNameArr, List> listItemsByType) { - XWPFChart chart = (XWPFChart) poixmlDocumentPart; - chart.getCTChart(); - - //根据属性第一列名称切换数据类型 - CTChart ctChart = chart.getCTChart(); - CTPlotArea plotArea = ctChart.getPlotArea(); - - CTLineChart lineChart = plotArea.getLineChartArray(0); - List lineSerList = lineChart.getSerList(); // 获取折线图单位 - - //刷新内置excel数据 - refreshExcel(chart, listItemsByType, fldNameArr, titleArr); - //刷新页面显示数据 - refreshLineStrGraphContent(lineChart, lineSerList, listItemsByType, fldNameArr, 1); - - } - - - /** - * 调用替换饼图数据 - */ - public static void replacePieCharts(POIXMLDocumentPart poixmlDocumentPart, - List titleArr, List fldNameArr, List> listItemsByType) { - XWPFChart chart = (XWPFChart) poixmlDocumentPart; - chart.getCTChart(); - - //根据属性第一列名称切换数据类型 - CTChart ctChart = chart.getCTChart(); - CTPlotArea plotArea = ctChart.getPlotArea(); - - CTPieChart pieChart = plotArea.getPieChartArray(0); - List pieSerList = pieChart.getSerList(); // 获取饼图单位 - - //刷新内置excel数据 - refreshExcel(chart, listItemsByType, fldNameArr, titleArr); - //刷新页面显示数据 - refreshPieStrGraphContent(pieChart, pieSerList, listItemsByType, fldNameArr, 1); - - } - - - /** - * 调用替换柱状图、折线图组合数据 - */ - public static void replaceCombinationCharts(POIXMLDocumentPart poixmlDocumentPart, - List titleArr, List fldNameArr, List> listItemsByType) { - XWPFChart chart = (XWPFChart) poixmlDocumentPart; - chart.getCTChart(); - - //根据属性第一列名称切换数据类型 - CTChart ctChart = chart.getCTChart(); - CTPlotArea plotArea = ctChart.getPlotArea(); - - CTBarChart barChart = plotArea.getBarChartArray(0); - List barSerList = barChart.getSerList(); // 获取柱状图单位 - //刷新内置excel数据 - refreshExcel(chart, listItemsByType, fldNameArr, titleArr); - //刷新页面显示数据 - refreshBarStrGraphContent(barChart, barSerList, listItemsByType, fldNameArr, 1); - - - CTBarChart barChart2 = plotArea.getBarChartArray(0); - List barSerList2 = barChart2.getSerList(); // 获取柱状图单位 - //刷新内置excel数据 - refreshExcel(chart, listItemsByType, fldNameArr, titleArr); - //刷新页面显示数据 - refreshBarStrGraphContent(barChart2, barSerList2, listItemsByType, fldNameArr, 1); - - - CTLineChart lineChart = plotArea.getLineChartArray(0); - List lineSerList = lineChart.getSerList(); // 获取折线图单位 - //刷新内置excel数据 - refreshExcel(chart, listItemsByType, fldNameArr, titleArr); - //刷新页面显示数据 - refreshLineStrGraphContent(lineChart, lineSerList, listItemsByType, fldNameArr, 1); - - } - - - /** - * 刷新折线图数据方法 - * - * @param typeChart - * @param serList - * @param dataList - * @param fldNameArr - * @param position - * @return - */ - public static boolean refreshLineStrGraphContent(Object typeChart, - List serList, List> dataList, List fldNameArr, int position) { - - boolean result = true; - //更新数据区域 - for (int i = 0; i < serList.size(); i++) { - //CTSerTx tx=null; - CTAxDataSource cat = null; - CTNumDataSource val = null; - CTLineSer ser = ((CTLineChart) typeChart).getSerArray(i); - //tx= ser.getTx(); - // Category Axis Data - cat = ser.getCat(); - // 获取图表的值 - val = ser.getVal(); - // strData.set - CTStrData strData = cat.getStrRef().getStrCache(); - CTNumData numData = val.getNumRef().getNumCache(); - strData.setPtArray((CTStrVal[]) null); // unset old axis text - numData.setPtArray((CTNumVal[]) null); // unset old values - - // set model - long idx = 0; - for (int j = 0; j < dataList.size(); j++) { - //判断获取的值是否为空 - String value = "0"; - if (new BigDecimal(dataList.get(j).get(fldNameArr.get(i + position))) != null) { - value = new BigDecimal(dataList.get(j).get(fldNameArr.get(i + position))).toString(); - } - if (!"0".equals(value)) { - CTNumVal numVal = numData.addNewPt();//序列值 - numVal.setIdx(idx); - numVal.setV(value); - } - CTStrVal sVal = strData.addNewPt();//序列名称 - sVal.setIdx(idx); - sVal.setV(dataList.get(j).get(fldNameArr.get(0))); - idx++; - } - numData.getPtCount().setVal(idx); - strData.getPtCount().setVal(idx); - - - //赋值横坐标数据区域 - String axisDataRange = new CellRangeAddress(1, dataList.size(), 0, 0) - .formatAsString("Sheet1", false); - cat.getStrRef().setF(axisDataRange); - - //数据区域 - String numDataRange = new CellRangeAddress(1, dataList.size(), i + position, i + position) - .formatAsString("Sheet1", false); - val.getNumRef().setF(numDataRange); - - // 设置系列生成方向 - - - } - return result; - } - - - /** - * 刷新柱状图数据方法 - * - * @param typeChart - * @param serList - * @param dataList - * @param fldNameArr - * @param position - * @return - */ - public static boolean refreshBarStrGraphContent(Object typeChart, - List serList, List> dataList, List fldNameArr, int position) { - boolean result = true; - //更新数据区域 - for (int i = 0; i < serList.size(); i++) { - //CTSerTx tx=null; - CTAxDataSource cat = null; - CTNumDataSource val = null; - CTBarSer ser = ((CTBarChart) typeChart).getSerArray(i); - //tx= ser.getTx(); - // Category Axis Data - cat = ser.getCat(); - // 获取图表的值 - val = ser.getVal(); - // strData.set - CTStrData strData = cat.getStrRef().getStrCache(); - CTNumData numData = val.getNumRef().getNumCache(); - strData.setPtArray((CTStrVal[]) null); // unset old axis text - numData.setPtArray((CTNumVal[]) null); // unset old values - - // set model - long idx = 0; - for (int j = 0; j < dataList.size(); j++) { - //判断获取的值是否为空 - String value = "0"; - - if (new BigDecimal(dataList.get(j).get(fldNameArr.get(i + position))) != null) { - value = new BigDecimal(dataList.get(j).get(fldNameArr.get(i + position))).toString(); - } - if (!"0".equals(value)) { - CTNumVal numVal = numData.addNewPt();//序列值 - numVal.setIdx(idx); - numVal.setV(value); - } - CTStrVal sVal = strData.addNewPt();//序列名称 - sVal.setIdx(idx); - sVal.setV(dataList.get(j).get(fldNameArr.get(0))); - idx++; - } - numData.getPtCount().setVal(idx); - strData.getPtCount().setVal(idx); - - - //赋值横坐标数据区域 - String axisDataRange = new CellRangeAddress(1, dataList.size(), 0, 0) - .formatAsString("Sheet1", true); - cat.getStrRef().setF(axisDataRange); - - //数据区域 - String numDataRange = new CellRangeAddress(1, dataList.size(), i + position, i + position) - .formatAsString("Sheet1", true); - val.getNumRef().setF(numDataRange); - - } - return result; - } - - - /** - * 刷新饼图数据方法 - * - * @param typeChart - * @param serList - * @param dataList - * @param fldNameArr - * @param position - * @return - */ - public static boolean refreshPieStrGraphContent(Object typeChart, - List serList, List> dataList, List fldNameArr, int position) { - - boolean result = true; - //更新数据区域 - for (int i = 0; i < serList.size(); i++) { - //CTSerTx tx=null; - CTAxDataSource cat = null; - CTNumDataSource val = null; - CTPieSer ser = ((CTPieChart) typeChart).getSerArray(i); - - //tx= ser.getTx(); - // Category Axis Data - cat = ser.getCat(); - // 获取图表的值 - val = ser.getVal(); - // strData.set - CTStrData strData = cat.getStrRef().getStrCache(); - CTNumData numData = val.getNumRef().getNumCache(); - strData.setPtArray((CTStrVal[]) null); // unset old axis text - numData.setPtArray((CTNumVal[]) null); // unset old values - - // set model - long idx = 0; - for (int j = 0; j < dataList.size(); j++) { - //判断获取的值是否为空 - String value = "0"; - if (new BigDecimal(dataList.get(j).get(fldNameArr.get(i + position))) != null) { - value = new BigDecimal(dataList.get(j).get(fldNameArr.get(i + position))).toString(); - } - if (!"0".equals(value)) { - CTNumVal numVal = numData.addNewPt();//序列值 - numVal.setIdx(idx); - numVal.setV(value); - } - CTStrVal sVal = strData.addNewPt();//序列名称 - sVal.setIdx(idx); - sVal.setV(dataList.get(j).get(fldNameArr.get(0))); - idx++; - } - numData.getPtCount().setVal(idx); - strData.getPtCount().setVal(idx); - - - //赋值横坐标数据区域 - String axisDataRange = new CellRangeAddress(1, dataList.size(), 0, 0) - .formatAsString("Sheet1", true); - cat.getStrRef().setF(axisDataRange); - - //数据区域 - String numDataRange = new CellRangeAddress(1, dataList.size(), i + position, i + position) - .formatAsString("Sheet1", true); - val.getNumRef().setF(numDataRange); - } - return result; - } - - - /** - * 刷新内置excel数据 - * - * @param chart - * @param dataList - * @param fldNameArr - * @param titleArr - * @return - */ - public static boolean refreshExcel(XWPFChart chart, - List> dataList, List fldNameArr, List titleArr) { - boolean result = true; - Workbook wb = new XSSFWorkbook(); - Sheet sheet = wb.createSheet("Sheet1"); - //根据数据创建excel第一行标题行 - for (int i = 0; i < titleArr.size(); i++) { - if (sheet.getRow(0) == null) { - sheet.createRow(0).createCell(i).setCellValue(titleArr.get(i) == null ? "" : titleArr.get(i)); - - } else { - sheet.getRow(0).createCell(i).setCellValue(titleArr.get(i) == null ? "" : titleArr.get(i)); - - } - } - - //遍历数据行 - for (int i = 0; i < dataList.size(); i++) { - Map baseFormMap = dataList.get(i);//数据行 - //fldNameArr字段属性 - for (int j = 0; j < fldNameArr.size(); j++) { - if (sheet.getRow(i + 1) == null) { - if (j == 0) { - try { - sheet.createRow(i + 1).createCell(j).setCellValue(baseFormMap.get(fldNameArr.get(j)) == null ? "" : baseFormMap.get(fldNameArr.get(j))); - } catch (Exception e) { - if (baseFormMap.get(fldNameArr.get(j)) == null) { - sheet.createRow(i + 1).createCell(j).setCellValue(""); - } else { - sheet.createRow(i + 1).createCell(j).setCellValue(baseFormMap.get(fldNameArr.get(j))); - } - } - } - } else { - BigDecimal b = new BigDecimal(baseFormMap.get(fldNameArr.get(j))); - double value = 0d; - if (b != null) { - value = b.doubleValue(); - } - if (value == 0) { - sheet.getRow(i + 1).createCell(j); - } else { - sheet.getRow(i + 1).createCell(j).setCellValue(b.doubleValue()); - } - } - } - - } - // 更新嵌入的workbook - - List pxdList = chart.getRelations(); - if (pxdList != null && pxdList.size() > 0) { - for (int i = 0; i < pxdList.size(); i++) { - if (pxdList.get(i).toString().contains("sheet")) {//判断为sheet再去进行更新表格数据 - POIXMLDocumentPart xlsPart = pxdList.get(i); - OutputStream xlsOut = xlsPart.getPackagePart().getOutputStream(); - - try { - wb.write(xlsOut); - xlsOut.close(); - } catch (IOException e) { - e.printStackTrace(); - result = false; - } finally { - if (wb != null) { - try { - wb.close(); - } catch (IOException e) { - e.printStackTrace(); - result = false; - } - } - } - break; - } - } - } - return result; - } - - - /** - * 设置表格样式 - * - * @param cell - * @param fontName - * @param fontSize - * @param fontBlod - * @param alignment - * @param vertical - * @param fontColor - * @param bgColor - * @param cellWidth - * @param content - */ - public static void setWordCellSelfStyle(XWPFTableCell cell, String fontName, String fontSize, int fontBlod, - String alignment, String vertical, String fontColor, - String bgColor, String cellWidth, String content) { - - //poi对字体大小设置特殊,不支持小数,但对原word字体大小做了乘2处理 - BigInteger bFontSize = new BigInteger("24"); - if (fontSize != null && !fontSize.equals("")) { - //poi对字体大小设置特殊,不支持小数,但对原word字体大小做了乘2处理 - BigDecimal fontSizeBD = new BigDecimal(fontSize); - fontSizeBD = bd2.multiply(fontSizeBD); - fontSizeBD = fontSizeBD.setScale(0, BigDecimal.ROUND_HALF_UP);//这里取整 - bFontSize = new BigInteger(fontSizeBD.toString());// 字体大小 - } - - // 设置单元格宽度 - cell.setWidth(cellWidth); - - //=====获取单元格 - CTTc tc = cell.getCTTc(); - //====tcPr开始====》》》》 - CTTcPr tcPr = tc.getTcPr();//获取单元格里的 - if (tcPr == null) {//没有,创建 - tcPr = tc.addNewTcPr(); - } - - // --vjc开始-->> - CTVerticalJc vjc = tcPr.getVAlign();//获取 - if (vjc == null) {//没有,创建 - vjc = tcPr.addNewVAlign(); - } - //设置单元格对齐方式 - vjc.setVal(vertical.equals("top") ? STVerticalJc.TOP : vertical.equals("bottom") ? STVerticalJc.BOTTOM : STVerticalJc.CENTER); //垂直对齐 - - CTShd shd = tcPr.getShd();//获取里的 - if (shd == null) {//没有,创建 - shd = tcPr.addNewShd(); - } - // 设置背景颜色 - shd.setFill(bgColor.substring(1)); - //《《《《====tcPr结束==== - - //====p开始====》》》》 - CTP p = tc.getPList().get(0);//获取单元格里的 - - //---ppr开始--->>> - CTPPr ppr = p.getPPr();//获取里的 - if (ppr == null) {//没有,创建 - ppr = p.addNewPPr(); - } - // --jc开始-->> - CTJc jc = ppr.getJc();//获取里的 - if (jc == null) {//没有,创建 - jc = ppr.addNewJc(); - } - //设置单元格对齐方式 - jc.setVal(alignment.equals("left") ? STJc.LEFT : alignment.equals("right") ? STJc.RIGHT : STJc.CENTER); //水平对齐 - // <<--jc结束-- - // --pRpr开始-->> - CTParaRPr pRpr = ppr.getRPr(); //获取里的 - if (pRpr == null) {//没有,创建 - pRpr = ppr.addNewRPr(); - } - CTFonts pfont = pRpr.getRFonts();//获取里的 - if (pfont == null) {//没有,创建 - pfont = pRpr.addNewRFonts(); - } - //设置字体 - pfont.setAscii(fontName); - pfont.setEastAsia(fontName); - pfont.setHAnsi(fontName); - - CTOnOff pb = pRpr.getB();//获取里的 - if (pb == null) {//没有,创建 - pb = pRpr.addNewB(); - } - //设置字体是否加粗 - pb.setVal(fontBlod == 1 ? STOnOff.ON : STOnOff.OFF); - - CTHpsMeasure psz = pRpr.getSz();//获取里的 - if (psz == null) {//没有,创建 - psz = pRpr.addNewSz(); - } - // 设置单元格字体大小 - psz.setVal(bFontSize); - CTHpsMeasure pszCs = pRpr.getSzCs();//获取里的 - if (pszCs == null) {//没有,创建 - pszCs = pRpr.addNewSzCs(); - } - // 设置单元格字体大小 - pszCs.setVal(bFontSize); - // <<--pRpr结束-- - //<<<---ppr结束--- - - //---r开始--->>> - List rlist = p.getRList(); //获取里的 - CTR r = null; - if (rlist != null && rlist.size() > 0) {//获取第一个 - r = rlist.get(0); - } else {//没有,创建 - r = p.addNewR(); - } - //--rpr开始-->> - CTRPr rpr = r.getRPr();//获取里的 - if (rpr == null) {//没有,创建 - rpr = r.addNewRPr(); - } - //->- - CTFonts font = rpr.getRFonts();//获取里的 - if (font == null) {//没有,创建 - font = rpr.addNewRFonts(); - } - //设置字体 - font.setAscii(fontName); - font.setEastAsia(fontName); - font.setHAnsi(fontName); - - CTOnOff b = rpr.getB();//获取里的 - if (b == null) {//没有,创建 - b = rpr.addNewB(); - } - //设置字体是否加粗 - b.setVal(fontBlod == 1 ? STOnOff.ON : STOnOff.OFF); - CTColor color = rpr.getColor();//获取里的 - if (color == null) {//没有,创建 - color = rpr.addNewColor(); - } - // 设置字体颜色 - if (content.contains("↓")) { - color.setVal("43CD80"); - } else if (content.contains("↑")) { - color.setVal("943634"); - } else { - color.setVal(fontColor.substring(1)); - } - CTHpsMeasure sz = rpr.getSz(); - if (sz == null) { - sz = rpr.addNewSz(); - } - sz.setVal(bFontSize); - CTHpsMeasure szCs = rpr.getSzCs(); - if (szCs == null) { - szCs = rpr.addNewSz(); - } - szCs.setVal(bFontSize); - //-<- - //<<--rpr结束-- - List tlist = r.getTList(); - CTText t = null; - if (tlist != null && tlist.size() > 0) {//获取第一个 - t = tlist.get(0); - } else {//没有,创建 - t = r.addNewT(); - } - t.setStringValue(content); - //<<<---r结束--- - } - -} \ No newline at end of file diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/chartForWord/PoiWordUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/chartForWord/PoiWordUtil.java deleted file mode 100644 index b5996a8..0000000 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/chartForWord/PoiWordUtil.java +++ /dev/null @@ -1,299 +0,0 @@ -package com.ruoyi.common.utils.chartForWord; -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.IdUtil; -import org.apache.poi.util.Units; -import org.apache.poi.xwpf.usermodel.*; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge; - -import java.io.BufferedInputStream; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * @author shuaihua zang - * @date 2022/10/10 - */ -public class PoiWordUtil { - - /** - * @param doc docx解析对象 - * @param tableIndex 第几个表格 - */ - public static XWPFTable getTable(XWPFDocument doc, int tableIndex) { - return doc.getTables().get(tableIndex); - } - - /** - * 为表格插入行数,此处不处理表头,所以从第二行开始 - * - * @param table 需要插入数据的表格 - * @param tableList 插入数据集合 - * @param index 在几行后开始插入数据 1为第一行 - */ - public static void insertTable(XWPFTable table, List tableList, int index) { - //创建与数据一致的行数 - for (int i = 0; i < tableList.size(); i++) { - table.createRow(); - } - int length = table.getRows().size() - index; - for (int i = 0; i < length; i++) { - XWPFTableRow newRow = table.getRow(i + index); - List cells = newRow.getTableCells(); - for (int j = 0; j < cells.size(); j++) { - XWPFTableCell cell = cells.get(j); - cell.setText(tableList.get(i)[j]); - } - } - } - - - /** - * 替换段落里面的变量 - * - * @param doc 要替换的文档 - * @param params 参数 - */ - public static void replaceParams(XWPFDocument doc, Map params) { - Iterator iterator = doc.getParagraphsIterator(); - XWPFParagraph paragraph; - while (iterator.hasNext()) { - paragraph = iterator.next(); - replaceParam(paragraph, params); - } - } - - - /** - * 替换所有表格里面的变量 - * - * @param doc 要替换的文档 - */ - public static void replaceAllTableParams(XWPFDocument doc, Map testMap) { - Iterator iterator = doc.getTablesIterator(); - XWPFTable table; - List rows; - List cells; - List paras; - while (iterator.hasNext()) { - table = iterator.next(); - //判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入 - if (matcher(table.getText()).find()) { - rows = table.getRows(); - for (XWPFTableRow row : rows) { - cells = row.getTableCells(); - for (XWPFTableCell cell : cells) { - paras = cell.getParagraphs(); - for (XWPFParagraph para : paras) { - replaceParam(para, testMap); - } - } - } - } - } - } - - /** - * 替换表格里面的变量 - */ - public static void replaceTableParams(XWPFTable table, Map testMap) { - List rows; - List cells; - List paras; - //判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入 - if (matcher(table.getText()).find()) { - rows = table.getRows(); - for (XWPFTableRow row : rows) { - cells = row.getTableCells(); - for (XWPFTableCell cell : cells) { - paras = cell.getParagraphs(); - for (XWPFParagraph para : paras) { - replaceParam(para, testMap); - } - } - } - } - } - - /** - * 正则匹配字符串 - * - * @param str - * @return - */ - public static Matcher matcher(String str) { - Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}", Pattern.CASE_INSENSITIVE); - return pattern.matcher(str); - } - - /** - * 替换段落里面的变量 - * - * @param paragraph 要替换的段落 - * @param params 参数 - */ - public static void replaceParam(XWPFParagraph paragraph, Map params) { - List runs; - Matcher matcher; - StringBuilder runText = new StringBuilder(); - if (matcher(paragraph.getParagraphText()).find()) { - runs = paragraph.getRuns(); - int j = runs.size(); - for (int i = 0; i < j; i++) { - runText.append(runs.get(0).toString()); - //保留最后一个段落,在这段落中替换值,保留段落样式 - if (!((j - 1) == i)) { - paragraph.removeRun(0); - } - } - matcher = matcher(runText.toString()); - if (matcher.find()) { - while ((matcher = matcher(runText.toString())).find()) { - runText = new StringBuilder(matcher.replaceFirst(String.valueOf(params.get(matcher.group(1))))); - } - runs.get(0).setText(runText.toString(), 0); - } - } - - } - - /** - * word单元格列合并 都以0开始计算 - * - * @param table 表格 - * @param row 合并列所在行 - * @param startCell 开始列 - * @param endCell 结束列 - * @date 2020年4月8日 下午4:43:54 - */ - public static void mergeCellsHorizontal(XWPFTable table, int row, int startCell, int endCell) { - for (int i = startCell; i <= endCell; i++) { - XWPFTableCell cell = table.getRow(row).getCell(i); - if (i == startCell) { - // The first merged cell is set with RESTART merge value - cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART); - } else { - // Cells which join (merge) the first one, are set with CONTINUE - cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE); - } - } - } - - /** - * word单元格行合并 - * - * @param table 表格 - * @param col 合并行所在列 - * @param startRow 开始行 - * @param endRow 结束行 - * @date 2020年4月8日 下午4:46:18 - */ - public static void mergeCellsVertically(XWPFTable table, int col, int startRow, int endRow) { - for (int i = startRow; i <= endRow; i++) { - XWPFTableCell cell = table.getRow(i).getCell(col); - if (i == startRow) { - cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART); - } else { - cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE); - } - } - } - - - /** - * 替换图片 - * key 替换字段名称,与word中相同 - * value 图片地址 - */ - public static void doParagraphs(XWPFDocument doc, Map imgMap) { - List paragraphList = doc.getParagraphs(); - if (paragraphList != null && paragraphList.size() > 0) { - for (XWPFParagraph paragraph : paragraphList) { - List runs = paragraph.getRuns(); - for (XWPFRun run : runs) { - String text = run.getText(0); - if (text != null) { - String imgkey = text.replaceAll("\\{\\{@", "").replaceAll("}}", ""); - String imgPath = imgMap.get(imgkey); - if (imgPath != null) { - if (imgPath.startsWith("http")) { - imgPath = saveToFile(imgPath); - } - saveLocalImg(run, imgPath); - } - } - } - } - } - } - - /** - * 获取本地保存图片文件流 - * - * @param imgPath - * @return FileInputStream - * @throws Exception - */ - private static void saveLocalImg(XWPFRun run, String imgPath) { - try (FileInputStream pictureData = new FileInputStream(imgPath)) { - run.setText("", 0); - run.addPicture(pictureData, - Document.PICTURE_TYPE_PNG, "img.png", Units.toEMU(200), Units.toEMU(200)); - } catch (Exception e) { - e.printStackTrace(); - } - } - - - /** - * 获取网络图片流 - * - * @return - */ - public static String saveToFile(String destUrl) { - HttpURLConnection httpUrl = null; - byte[] buf = new byte[1024]; - int size = 0; - StringBuilder append = new StringBuilder() - .append("D:/fjFile/") - .append(IdUtil.simpleUUID()) - .append(".png"); - String fileUrl = append.toString(); - try { - URL url = new URL(destUrl); - httpUrl = (HttpURLConnection) url.openConnection(); - httpUrl.setConnectTimeout(5*1000); - httpUrl.setReadTimeout(5*1000); - httpUrl.connect(); - try (BufferedInputStream bis = new BufferedInputStream(httpUrl.getInputStream()); - FileOutputStream fos = new FileOutputStream(fileUrl)){ - while ((size = bis.read(buf)) != -1) { - fos.write(buf, 0, size); - } - fos.flush(); - } catch (IOException e) { - e.printStackTrace(); - } - } catch (IOException e) { - e.printStackTrace(); - } finally { - try { - if(httpUrl!=null){ - httpUrl.disconnect(); - } - } catch (Exception e) { - e.printStackTrace(); - } - } - return fileUrl; - } - - -} diff --git a/ruoyi-common/src/main/resources/V3.0.docx b/ruoyi-common/src/main/resources/V3.0.docx deleted file mode 100644 index e0ffaf72f5b7f7135a424a2aa19c1dbfc788ca30..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61475 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 IzCZha0F-#rLI3~&