首先感谢以下博客
1.java使用poi操作world生成饼图,柱状图,折线图,组合图:二_不知所终的博客-CSDN博客
2.java使用poi在word中生成柱状图、折线图、饼图、柱状图+折线图组合图、动态表格、文本替换、图片替换、更新内置Excel数据、更新插入的文本框内容、合并表格单元格;_u014427811的博客-CSDN博客
本文参考以上两个博客,并做了部分修改并做了记录
一、利用poi在world生成图表 1、解决问题 1)填充数据后,图例却没动态改变,还是模板里的图例。解决:数据分析时,需要往图形缓存里赋值图例标题
2)动态删除图表,如有要求,图表没有数据时动态删除图表。解决:通过图形所在段落位置删除的,没找到其他方法。
图形的位置是通过一段文字位置的找到,比如我的图形在“1)到访游客规模”下面,我先找到这个文字的位置,文字的位置+1就是我图形的位置。哈哈,有点牵强,但是没找到其他办法。
获取图片的位置
private Integer getParagraphIndex(ListxwpfParagraphList,String mark) { for (int i=0;i xwpfRuns= paragraph.getRuns(); String runStr=""; for (int z=0; z 3)假如我们模板某个折线图有四条数据,但实际我们填充的数据只填充了两条,最后生成的图表里会有四条数据,前两条就是我们实际的数据,后两条没有填充数据,模板数据却保留了。 解决:
新增图标数据前,先删除调模板里边的数据,不知道为啥滴倒着删,正着顺序会乱。。。
2、简单代码示例1)准备一个简单的word模板,后缀名为.docx
2)上代码
测试类
说明:dataSource是数据源,可通过调接口获取json格式数据
wordTemplete可配置系统参数里,定义图标位置及类型等,可动态改变word模板里的图形,不用改动代码。
import com.alibaba.fastjson.JSONObject; import com.asiainfo.srd.bd.common.utils.StringUtils; import com.asiainfo.srd.bd.report.domain.ChartModel; import com.asiainfo.srd.bd.report.domain.ChartsEnum; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.xwpf.usermodel.XWPFChart; import org.apache.poi.xwpf.usermodel.XWPFdocument; import java.io.*; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class Test { public static void main(String[] args) throws IOException, InvalidFormatException { //获取word模板 InputStream docis = new FileInputStream("E:\报告新.docx"); //转成word XWPFdocument doc = new XWPFdocument(docis); Listcharts = doc.getCharts(); Map chartsMap = new HashMap (); for (XWPFChart chart : charts) { String s = chart.toString(); String key = s.replaceAll("Name: ", "") .replaceAll(" - Content Type: application/vnd\.openxmlformats-officedocument\.drawingml\.chart\+xml", "").trim(); System.out.println("key:" + key); chartsMap.put(key, chart); } String dataSorce = "{n" + "t"model": {n" + "tt"textParams": {n" + "ttt"p1": "2020",n" + "ttt"p2": "2021"n" + "tt},n" + "tt"chartsModel": [n" + "ttt[n" + "tttt{n" + "ttttt"xAxis": {n" + "tttttt"月份": "2021年10月1日"n" + "ttttt},n" + "ttttt"data": {n" + "tttttt"到访游客规模": "100.0"n" + "ttttt}n" + "tttt},n" + "tttt{n" + "ttttt"xAxis": {n" + "tttttt"月份": "2021年10月2日"n" + "ttttt},n" + "ttttt"data": {n" + "tttttt"到访游客规模": "200"n" + "ttttt}n" + "tttt}n" + "tttt{n" + "ttttt"xAxis": {n" + "tttttt"月份": "2021年10月3日"n" + "ttttt},n" + "ttttt"data": {n" + "tttttt"到访游客规模": "300"n" + "ttttt}n" + "tttt},n" + "tttt{n" + "ttttt"xAxis": {n" + "tttttt"月份": "2021年10月4日"n" + "ttttt},n" + "ttttt"data": {n" + "tttttt"到访游客规模": "400"n" + "ttttt}n" + "tttt}n" + "ttt]n" + "tt]n" + "t}n" + "}"; //格式化系统参数 String wordTemplete = "{n" + "t"textMap": {n" + "tt"param1": "p1"n" + "t},n" + "t"chartsMap": [n" + "tt{n" + "ttt"dataSourceIndex": 0,n" + "ttt"chartIndex": 1,n " + "ttt"chartType": 3n" + "tt}" + "t]n" + "}"; System.out.println(wordTemplete); Map mapObj = JSONObject.parseObject(wordTemplete, Map.class); Map textMap = (Map ) mapObj.get("textMap"); List 工具类
1.chartModel.class
import lombok.Getter; import lombok.ToString; import lombok.extern.slf4j.Slf4j; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.xwpf.usermodel.XWPFChart; import org.apache.xmlbeans.XmlObject; import org.openxmlformats.schemas.drawingml.x2006.chart.CTChart; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import java.io.IOException; import java.util.*; import java.util.stream.Collectors; @Slf4j @Getter @ToString public class ChartModel { private Boolean isSingle = true; private String sheetName; private XWPFChart xwpfChart; private ListxmlObjectList = new ArrayList<>(); private CTChart ctChart; private List titleList; private List numberList; private List > sourceModelList; private List chartsEnumList; public void setNumberList(List numberList){ this.numberList = numberList; } public void setSourceModelList(List > sourceModelList){ this.sourceModelList = sourceModelList; } public void setTitleList(List titleList){ this.titleList = titleList; } public void setSingleChart(Map charts,String chartSeat,int xmlObjSeat,ChartsEnum chartsEnum){ List chartsEnumList = Arrays.asList(chartsEnum); this.packageBasic(charts, chartSeat,chartsEnumList); XmlObject targetChart = chartsEnum.getTargetChart(chartSeat, this.ctChart, xmlObjSeat); this.xmlObjectList = Arrays.asList(targetChart); //当前是单元素 this.isSingle = true; } public void setComBiChart(Map charts,String chartSeat,int xmlObjSeat,List chartsEnumList){ this.packageBasic(charts, chartSeat,chartsEnumList); this.xmlObjectList.clear(); chartsEnumList.stream().forEach(x->{ XmlObject targetChart = x.getTargetChart(chartSeat,this.ctChart, xmlObjSeat); this.xmlObjectList.add(targetChart); }); //当前不是单元素 this.isSingle = false; } private void packageBasic(Map charts, String chartSeat,List chartsEnumList) { if(CollectionUtils.isEmpty(charts)){ throw new RuntimeException("模板中图表元素为null; !!!ctChart:null"); } if(CollectionUtils.isEmpty(chartsEnumList)){ throw new RuntimeException("图表目标为null;!!!chartsEnum:null"); } this.chartsEnumList = chartsEnumList; this.xwpfChart = charts.get("/word/charts/chart"+chartSeat+".xml"); this.ctChart = this.xwpfChart.getCTChart(); } public void executeFillModel(String sheetName) throws IOException, InvalidFormatException { this.sheetName = sheetName; //异常校验 String s = this.isSingle ? this.abnormalCheckSingle() : this.abnormalCheckComBi(); //执行填充数据 ChartsEnum.refreshExcel(this); for (int i = 0; i < chartsEnumList.size(); i++) { ChartsEnum chartsEnum = chartsEnumList.get(i); chartsEnum.fillModel(this,this.getXmlObjectList().get(i),i); } // //标题 // List titleList = getTitleList(); } private String abnormalCheckSingle() { // if(CollectionUtils.isEmpty(this.numberList)){ // throw new RuntimeException("数据源比对为null; !!!numberList:null"); // } // if(CollectionUtils.isEmpty(this.titleList)){ // throw new RuntimeException("标题为null; !!!titleList:null"); // } // if(CollectionUtils.isEmpty(this.sourceModelList)){ // throw new RuntimeException("数据源为null; !!!sourceModelList:null"); // } if(Objects.isNull(this.xwpfChart)){ throw new RuntimeException("模板中图表元素为null; !!!xwpfChart:null"); } if(CollectionUtils.isEmpty(this.xmlObjectList)){ throw new RuntimeException("模板中具体图表为null;!!!xmlObjectList:null"); } if(CollectionUtils.isEmpty(this.chartsEnumList)){ throw new RuntimeException("图表目标为null;!!!chartsEnum:null"); } if(Objects.isNull(this.ctChart)){ throw new RuntimeException("图表绘制区域为null;!!!chartsEnum:null"); } if(StringUtils.isEmpty(this.sheetName)){ throw new RuntimeException("内置excel页名为null;!!!sheetName:null"); } return null; } private String abnormalCheckComBi() { this.abnormalCheckSingle(); if (this.xmlObjectList.size() < 2) { throw new RuntimeException("组合图中【图表】元素不足两个; !!!xmlObjectList.size !> 2"); } if (this.sourceModelList.stream().filter(x->{return x.keySet().size() >= 3;}).collect(Collectors.toList()).size() < 0) { throw new RuntimeException("组合图中【数据源】元素不足两个; !!!sourceModelList.map.keySet.size !>= 3"); } if (this.numberList.size() < 3) { throw new RuntimeException("组合图中【数据源对应的key】元素不足两个; !!!numberList.size !>= 3"); } return null; } } 2.ChartsEnums.java
import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.apache.poi.ooxml.POIXMLdocumentPart; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; 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.xmlbeans.XmlObject; import org.apache.xmlbeans.XmlString; import org.apache.xmlbeans.impl.values.XmlComplexContentImpl; import org.openxmlformats.schemas.drawingml.x2006.chart.*; import org.openxmlformats.schemas.drawingml.x2006.chart.impl.CTBarChartImpl; import org.openxmlformats.schemas.drawingml.x2006.chart.impl.CTLineChartImpl; import org.openxmlformats.schemas.drawingml.x2006.chart.impl.CTPieChartImpl; import org.openxmlformats.schemas.drawingml.x2006.chart.impl.CTScatterChartImpl; import java.io.IOException; import java.io.OutputStream; import java.math.BigDecimal; import java.util.List; import java.util.Map; @Slf4j @Getter public enum ChartsEnum { PIE(CTPieChart.class, CTPieChartImpl.class,"1","饼图"){ @Override public void fillModel(ChartModel chartModel, XmlObject xmlObject, int bias) { if (!this.chartImplClazz.getName().equals(xmlObject.getClass().getName())) { //当前循环中图表操作不属于当前枚举 ChartsEnum.getEnumByChartImplClazz(((XmlComplexContentImpl)xmlObject).getClass()) .fillModel(chartModel, xmlObject, bias); return; } CTPieChart pieChart = (CTPieChart)xmlObject; List二、动态替换模板里的变量 1.创建word模板serList = pieChart.getSerList(); //更新数据区域 for (int i = 0; i < serList.size(); i++) { //数据填充 // CTPieSer ser = pieChart.getSerArray(i); CTAxDataSource cat = ser.getCat(); CTNumDataSource val = ser.getVal(); // this.dataAnalysisFill(chartModel,i,bias,cat,val); CTSerTx tx = ser.getTx(); this.dataAnalysisFill(chartModel,i,bias,cat,val,tx); } } @Override public XmlObject getTargetChart(String chartSeat, CTChart ctChart, int xmlObjSeat) { try { CTPieChart pieChart = ctChart.getPlotArea().getPieChartArray(xmlObjSeat); return pieChart; }catch (Exception e){ throw new RuntimeException("当前位置【" + chartSeat + "】不存在【饼图】!!!"); } } }, COLUMN(CTBarChart.class, CTBarChartImpl.class,"2","柱形图") { @Override public void fillModel(ChartModel chartModel,XmlObject xmlObject,int bias) { if (!this.chartImplClazz.getName().equals(xmlObject.getClass().getName())) { //当前循环中图表操作不属于当前枚举 ChartsEnum.getEnumByChartImplClazz(((XmlComplexContentImpl)xmlObject).getClass()) .fillModel(chartModel, xmlObject, bias); return; } CTBarChart chart = (CTBarChart)xmlObject; List serList = chart.getSerList(); //更新数据区域 for (int i = 0; i < serList.size(); i++) { //数据填充 // CTBarSer ser = chart.getSerArray(i); CTAxDataSource cat = ser.getCat(); CTNumDataSource val = ser.getVal(); // this.dataAnalysisFill(chartModel,i,bias,cat,val); CTSerTx tx = ser.getTx(); this.dataAnalysisFill(chartModel,i,bias,cat,val,tx); } } @Override public XmlObject getTargetChart(String chartSeat, CTChart ctChart, int xmlObjSeat) { try { CTBarChart barChart = ctChart.getPlotArea().getBarChartArray(xmlObjSeat); return barChart; }catch (Exception e){ throw new RuntimeException("当前位置【" + chartSeat + "】不存在【柱状图】!!!"); } } }, LINE_CHART(CTLineChart.class, CTLineChartImpl.class,"3","折线图"){ @Override public void fillModel(ChartModel chartModel,XmlObject xmlObject,int bias) { if (!this.chartImplClazz.getName().equals(xmlObject.getClass().getName())) { //当前循环中图表操作不属于当前枚举 ChartsEnum.getEnumByChartImplClazz(((XmlComplexContentImpl)xmlObject).getClass()) .fillModel(chartModel, xmlObject, bias); return; } CTLineChart chart = (CTLineChart)xmlObject; List serList = chart.getSerList(); //更新数据区域 for (int i = 0; i < serList.size(); i++) { //数据填充 // CTLineSer ser = chart.getSerArray(i); CTAxDataSource cat = ser.getCat(); CTNumDataSource val = ser.getVal(); CTSerTx tx = ser.getTx(); this.dataAnalysisFill(chartModel,i,bias,cat,val,tx); } } @Override public XmlObject getTargetChart(String chartSeat, CTChart ctChart, int xmlObjSeat) { try { CTLineChart lineChart = ctChart.getPlotArea().getLineChartArray(xmlObjSeat); return lineChart; }catch (Exception e){ throw new RuntimeException("当前位置【" + chartSeat + "】不存在【折线图】!!!"); } } }, SCATTER(CTScatterChart.class, CTScatterChartImpl.class,"4","散点图"){ @Override public void fillModel(ChartModel chartModel,XmlObject xmlObject,int bias) { if (!this.chartImplClazz.getName().equals(xmlObject.getClass().getName())) { //当前循环中图表操作不属于当前枚举 ChartsEnum.getEnumByChartImplClazz(((XmlComplexContentImpl)xmlObject).getClass()) .fillModel(chartModel, xmlObject, bias); return; } CTScatterChart chart = (CTScatterChart)xmlObject; List serList = chart.getSerList(); //更新数据区域 for (int i = 0; i < serList.size(); i++) { //数据填充 // CTScatterSer ser = chart.getSerArray(i); CTAxDataSource cat = ser.getXVal(); CTNumDataSource val = ser.getYVal(); CTSerTx tx = ser.getTx(); this.dataAnalysisFill(chartModel,i,bias,cat,val,tx); } } @Override public XmlObject getTargetChart(String chartSeat, CTChart ctChart, int xmlObjSeat) { try { CTScatterChart scatterChart = ctChart.getPlotArea().getScatterChartArray(xmlObjSeat); return scatterChart; }catch (Exception e){ throw new RuntimeException("当前位置【" + chartSeat + "】不存在【散点图】!!!"); } } }, ; public Class extends XmlObject> chartClazz; private String code; private String msg; public Class extends XmlComplexContentImpl> chartImplClazz; ChartsEnum(Class extends XmlObject> chartClazz, Class extends XmlComplexContentImpl> chartImplClazz,String code, String msg){ this.chartClazz = chartClazz; this.chartImplClazz = chartImplClazz; this.code = code; this.msg = msg; } public static ChartsEnum getInstance(String code){ for (ChartsEnum each : ChartsEnum.values()){ if (each.getCode().equals(code)){ return each; } } return null; } public abstract void fillModel(ChartModel chartModel,XmlObject xmlObject,int bias); public abstract XmlObject getTargetChart(String chartSeat,CTChart ctChart,int xmlObjSeat); public static ChartsEnum getEnumByChartImplClazz(Class extends XmlComplexContentImpl> chartImplClazz){ for (ChartsEnum value : ChartsEnum.values()) { if (value.getChartImplClazz().equals(chartImplClazz)){ return value; } } return null; } public static ChartsEnum getEnumByChartClazz(Class extends XmlObject> chartClazz){ for (ChartsEnum value : ChartsEnum.values()) { if (value.getChartClazz().equals(chartClazz)){ return value; } } return null; } public static boolean refreshExcel(ChartModel chartModel) throws IOException, InvalidFormatException { List titleList = chartModel.getTitleList(); List numberList = chartModel.getNumberList(); List > sourceModelList = chartModel.getSourceModelList(); XWPFChart xwpfChart = chartModel.getXwpfChart(); boolean result = true; Workbook wb = new XSSFWorkbook(); Sheet sheet = wb.createSheet(chartModel.getSheetName()); //根据数据创建excel第一行标题行 if(titleList.size()>0){ //没有数据的建立空表 sheet.createRow(0).createCell(0).setCellValue(""); sheet.getRow(0).createCell(1).setCellValue(""); } for (int i = 0; i < titleList.size(); i++) { if (sheet.getRow(0) == null) { sheet.createRow(0).createCell(i).setCellValue(titleList.get(i) == null ? "" : ""); } else { sheet.getRow(0).createCell(i).setCellValue(titleList.get(i) == null ? "" : titleList.get(i)); } } //遍历数据行 if(titleList.size()<0){ sheet.createRow(1).createCell(0).setCellValue(""); sheet.getRow(1).createCell(1).setCellValue(""); } for (int i = 0; i < sourceModelList.size(); i++) { Map baseFormMap = sourceModelList.get(i);//数据行 //fldNameArr字段属性 for (int j = 0; j < numberList.size(); j++) { if (sheet.getRow(i + 1) == null) { if (j == 0) { try { sheet.createRow(i + 1) .createCell(j) .setCellValue(baseFormMap.get(numberList.get(j)) == null ? "" : baseFormMap.get(numberList.get(j))); } catch (Exception e) { if (baseFormMap.get(numberList.get(j)) == null) { sheet.createRow(i + 1).createCell(j).setCellValue(""); } else { sheet.createRow(i + 1) .createCell(j) .setCellValue(baseFormMap.get(numberList.get(j))+""); } } } } else { // String s = baseFormMap.get(numberList.get(j))+""; // Double aDouble = Double.valueOf(baseFormMap.get(numberList.get(j))); BigDecimal b = new BigDecimal(Double.valueOf(baseFormMap.get(numberList.get(j)))); double value = 0D; if (b != null) { value = b.doublevalue(); } sheet.getRow(i + 1).createCell(j).setCellValue(b.doublevalue()); // if (value == 0D) { // sheet.getRow(i + 1).createCell(j); // } else { // sheet.getRow(i + 1).createCell(j).setCellValue(b.doublevalue()); // } } } } // 更新嵌入的workbook List pxdList = xwpfChart.getRelations(); if(pxdList!=null&&pxdList.size()>0) { for (int i = 0; i < pxdList.size(); i++) { if (pxdList.get(i).toString().contains("sheet")) { POIXMLdocumentPart xlsPart = xwpfChart.getRelations().get(0); OutputStream xlsOut = xlsPart.getPackagePart().getOutputStream(); try { xlsOut.flush(); wb.write(xlsOut); xlsPart.setCommitted(true); // ((XSSFWorkbook) wb).setCommitted(true); xlsOut.close(); } catch (IOException e) { e.printStackTrace(); result = false; } finally { if (wb != null) { try { wb.close(); } catch (IOException e) { e.printStackTrace(); result = false; } } } } } } return result; } public void dataAnalysisFill (ChartModel chartModel, int i, int bias, CTAxDataSource cat, CTNumDataSource val, CTSerTx tx) { //数据源 List > sourceModelList = chartModel.getSourceModelList(); //数据源key List numberList = chartModel.getNumberList(); List titleList = chartModel.getTitleList(); // CTStrData strData = cat.getStrRef().getStrCache(); CTNumData numData = val.getNumRef().getNumCache(); long idx = 0; //1、删掉模板里图表缓存数据 long l=strData.getPtCount().getVal(); long z=0; long num=l; while (z!=num){ numData.removePt((int)l-1); strData.removePt((int)l-1); l--; z++; } //2.新增图表数据 for (int j = 0; j < sourceModelList.size(); j++) { //判断获取的值是否为空 String value = "0"; if (new BigDecimal(sourceModelList.get(j).get(numberList.get(i+1))) != null) { value = new BigDecimal(sourceModelList.get(j).get(numberList.get(i + 1))).toString(); } CTNumVal numVal = numData.addNewPt();//序列值 numVal.setIdx(idx); numVal.setV(value); // if (!"0".equals(value)) { // CTNumVal numVal = numData.addNewPt();//序列值 // numVal.setIdx(idx); // numVal.setV(value); // } CTStrVal sVal = strData.addNewPt();//序列名称 sVal.setIdx(idx); sVal.setV(sourceModelList.get(j).get(numberList.get(0))); idx++; } //3.图表没有数据,默认值,以便能显示出图表 int m=sourceModelList.size(); if(titleList.size()==0){ idx=1; m=1; } numData.getPtCount().setVal(idx); strData.getPtCount().setVal(idx); //赋值横坐标数据区域 String axisDataRange = new CellRangeAddress(1, m, 0, 0) .formatAsString(chartModel.getSheetName(), false); cat.getStrRef().setF(axisDataRange); //赋值纵坐标数据区域 String numDataRange = new CellRangeAddress(1, m, i + 1 + bias, i + 1 + bias) .formatAsString(chartModel.getSheetName(), false); val.getNumRef().setF(numDataRange); //更新图例 if(sourceModelList.size()>0){ tx.getStrRef().getStrCache().getPtList().get(0).setV(titleList.get(i+1)); } } }
替换后的效果
2.上代码import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.fasterxml.jackson.databind.exc.InvalidFormatException; import org.apache.poi.xwpf.usermodel.XWPFdocument; import org.apache.poi.xwpf.usermodel.XWPFParagraph; import org.apache.poi.xwpf.usermodel.XWPFRun; import org.apache.poi.xwpf.usermodel.XWPFTable; import org.apache.poi.xwpf.usermodel.XWPFTableCell; import org.apache.poi.xwpf.usermodel.XWPFTableRow; public class HWPFTest { public static void main(String[] args)throws IOException, InvalidFormatException { HWPFTest hwpfTest=new HWPFTest(); Mapparams = new HashMap (); params.put("totalPeople", "6666"); params.put("bb", "200.00"); params.put("report", "2014-02-28"); params.put("my", "200.00"); params.put("totalAmt", "300.00"); String filePath = "E:\报告.docx"; InputStream is = new FileInputStream(filePath); XWPFdocument doc = new XWPFdocument(is); //替换段落里面的变量 hwpfTest.replaceInPara(doc, params); //替换表格里面的变量 // hwpfTest.replaceInTable(doc, params); OutputStream os = new FileOutputStream("E:\test.doc"); doc.write(os); hwpfTest.close(os); } public void replaceInPara(XWPFdocument doc, Map params) { for( XWPFParagraph para : doc.getParagraphs()){ this.replaceInPara(para, params); } } public void replaceInPara(XWPFParagraph para, Map params) { List runs; Matcher matcher; this.replaceText(para);//如果para拆分的不对,则用这个方法修改成正确的 if (this.matcher(para.getParagraphText()).find()) { runs = para.getRuns(); for (int i=0; i replaceText(XWPFParagraph para){ List runs = para.getRuns(); String str = ""; boolean flag = false; for (int i=0; i params) { Iterator iterator = doc.getTablesIterator(); XWPFTable table; List rows; List cells; List paras; while (iterator.hasNext()) { table = iterator.next(); rows = table.getRows(); for (XWPFTableRow row : rows) { cells = row.getTableCells(); for (XWPFTableCell cell : cells) { paras = cell.getParagraphs(); for (XWPFParagraph para : paras) { this.replaceInPara(para, params); } } } } } public Matcher matcher(String str) { Pattern pattern = Pattern.compile("\$\{(.+?)\}", Pattern.CASE_INSENSITIVE); Matcher matcher = pattern.matcher(str); return matcher; } public void close(InputStream is) { if (is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } public void close(OutputStream os) { if (os != null) { try { os.close(); } catch (IOException e) { e.printStackTrace(); } } } }



