1. 程式人生 > >java通過xml配置屬性用iText包生成pdf檔案

java通過xml配置屬性用iText包生成pdf檔案

總共步驟為:1、提供一個需要替換引數傳入類;2、解析xml檔案,替換xml檔案中的特定引數(寫死格式);3、解析xml檔案中的pdf檔案佈局(包括表、段落、文字、換行等);

4、生成pdf檔案。

第一步:引數可以用map存放,根據相應的key可以取到對應的值,如果值為List,則可用來替換表格中的引數,根據List大小擴充套件表格的行數。

第二步:解析xml檔案,可以直接用dom4j進行解析標準格式的xml檔案。此次先用檔案流進行解析吧,方便將拿到的引數進行字串替換操作。解析程式碼如下:

	/**
	 * 逐行讀取傳入的檔案內容
	 * @param filepath 檔案絕對路徑和檔名
	 * @return 存放檔案全部內容的String
	 * @throws Exception
	 */
	public static String readFile(String filepath) throws Exception {
		InputStreamReader read = null;
		BufferedReader bufferedReader = null;
		FileInputStream fileInput = null;
		try {
			fileInput = new FileInputStream(filepath);
			read = new InputStreamReader(fileInput, "GBK");//讀取檔案流內容
			bufferedReader = new BufferedReader(read);
			String lineTxt = null;
			StringBuffer buffer = new StringBuffer();
			while ((lineTxt = bufferedReader.readLine()) != null) {
				buffer.append(lineTxt + "\r\n");
			}
			String str1 = buffer.toString();
			return str1;
		} 
<span style="white-space:pre">		</span>finally {
			if (bufferedReader != null)
				bufferedReader.close();
			if (read != null)
				read.close();
			if(fileInput != null)
				fileInput.close();
		}
	}
將檔案內容按節點進行拆分為檔案頭與檔案體,檔案頭存放字型配置檔案頭、檔案頁的資訊,檔案體存放具體需要展示的pdf內容。
用第一步set進的物件中的map內容,替換返回的Str中的內容。

示例一種根據特定的xml格式設定的表示式替換方法,程式碼如下:

	/**
	 * 找到始終的表示式,並進行替換。   表示式的格式為:   ${status.index   -----}
	 * @param str
	 * @param statusName
	 * @param index
	 * @return
	 * @throws Exception
	 */
	private String findExpressAndReplace(String str, String statusName, int index) throws Exception {
		if ((statusName == null) || (statusName.trim().equals("")))
			return str;
		StringBuffer sb = new StringBuffer();
//		Pattern pattern = Pattern.compile("\\$\\{[\\w\\W]*?" + statusName + "\\.index[\\w\\W]*?\\}");
		
		Pattern pattern = Pattern.compile("\\$\\{" + statusName + "\\.index[\\w\\W]*?\\}");
		
		Matcher m = pattern.matcher(str);
		while (m.find()) {
			String sValue = m.group(0);
			sValue = sValue.substring(2, sValue.length() - 1);
			sValue = sValue.replace(statusName + ".index", index+"");
			
			sValue = runJsExpression(sValue);
			m.appendReplacement(sb, sValue);
		}
		m.appendTail(sb);
		return sb.toString();
	}

	private String runJsExpression(String expression) throws Exception {
		ScriptEngineManager manager = new ScriptEngineManager();
		ScriptEngine engine = manager.getEngineByName("JavaScript");
		System.out.println("表示式計算結果為:"+engine.eval(expression).toString());
		return engine.eval(expression).toString();
	}
2016/05/05  就寫到這了。

2016/05/06 開寫:

熟練運用正則表示式能節省很多程式碼。正則表示式一般包括兩種引擎,一種傳統NFA,一種DFA。java語言使用的是NFA引擎,使用表示式去匹配內容,當遇到第一個符合條件的值時,接收第一個匹配項。而DFA引擎則是用內容去匹配表示式。若需要匹配所有內容則需要用到Pattern與Matcher,用Matcher.find()讀取匹配的下一個字元序列。

第三步:使用jdom解析xml檔案,用模型物件儲存各個pdf物件的值。

此步驟需要有面向物件程式設計思想,首先需要一個DocModel存放包含全域性引數的全域性物件GlobalModel,以及包含內容引數的內容體物件BodyModel。

其次BodyModel向下可以包含pdf的各個組建物件,包括單行(p)、換頁(np)、圖片(img)、表格(table)、直線(line)、換行(br)。各個元組的內容append到BodyModel物件中。

第四步:建立各個物件元組的具體內容,加入到Document,生成pdf檔案。

主要呼叫iText包裡的方法set配置引數,生成pdf內容。程式碼如下:

	/**
	 * 根據model物件的內容,開始寫入pdf檔案
	 * @param model  存放檔案內容檔案物件
	 * @param os	檔案輸出流
	 * @throws Exception
	 */
	public void create(DocModel model, OutputStream os) throws Exception {
		this.docModel = model;
		PageModel pageModel = this.docModel.getGlobalModel().getPage();

		Document document = null;
		try {
			if ((pageModel.getMarginLeft() < 0) && (pageModel.getMarginRight() < 0) && (pageModel.getMarginTop() < 0) && (pageModel.getMarginBottom() < 0))
				document = new Document(PageSize.A4);  //如果page引數設定不完整,則預設使用A4大小
			else {
				document = new Document(PageSize.A4, pageModel.getMarginLeft(),
						pageModel.getMarginRight(), pageModel.getMarginTop(),
						pageModel.getMarginBottom());
			}
			this.pdfWriter = PdfWriter.getInstance(document, os);
			document.setFooter(createHeaderFooter());
			document.open();
			createContent(document, this.docModel.getBodyModel().getCells());
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		} finally {
			if (document != null)
				document.close();
			if (this.pdfWriter != null)
				this.pdfWriter.close();
		}
	}

	/**
	 * 新增各元組例項物件到Document中
	 * @param document
	 * @param cells
	 * @throws Exception
	 */
	private void createContent(Document document, List<CellModel> cells) throws Exception {
		for (CellModel cell : cells)
			if ((cell instanceof PModel))  //CellModel為所有模型均須實現的公共介面,可以用 instanceof 判斷具體內容具體是被哪個介面實現類例項化的
				document.add((Element) new PCreator(this.docModel.getGlobalModel(), this.pdfWriter).create(cell));
			
			else if ((cell instanceof LineModel)) 
			{
				new LineCreator(this.docModel.getGlobalModel(), this.pdfWriter,document, 10.0F).create(cell);
			}
			else if ((cell instanceof ImgModel))
				document.add((Element) new ImgCreator(this.docModel.getGlobalModel(), this.pdfWriter).create(cell));
			
			else if ((cell instanceof TableModel))
				document.add((Element) new TableCreator(this.docModel.getGlobalModel(), this.pdfWriter, document).create(cell));
			
			else if ((cell instanceof BrModel))
				document.add((Element) new BrCreator(this.docModel.getGlobalModel(), this.pdfWriter).create(cell));
			
			else if ((cell instanceof NpModel))
				document.newPage();
	}

到此處為止,pdf檔案已經生成完成。

後續需要好好研究一下正則表示式的使用,已經拓展面向物件程式設計思想。