Forráskód Böngészése

crystal => jasper工具类

sunyj 8 éve
szülő
commit
cd2961c4fc

+ 311 - 0
src/main/java/com/uas/report/crystal2jasper/CrystalToJasper.java

@@ -0,0 +1,311 @@
+package com.uas.report.crystal2jasper;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.transform.TransformerException;
+
+import org.apache.commons.io.output.FileWriterWithEncoding;
+import org.dom4j.Attribute;
+import org.dom4j.Document;
+import org.dom4j.DocumentException;
+import org.dom4j.Element;
+import org.dom4j.Node;
+import org.dom4j.io.SAXReader;
+import org.dom4j.io.XMLWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.util.StringUtils;
+
+import com.uas.report.core.exception.ReportException;
+import com.uas.report.util.FileUtils;
+import com.uas.report.util.ZipUtils;
+
+public class CrystalToJasper {
+
+	private static Logger logger = LoggerFactory.getLogger(CrystalToJasper.class);
+
+	public static void main(String[] args) throws IOException, DocumentException, TransformerException {
+		File rptZipFile = new File("C:/Users/sunyj-pc/Desktop/crystal-clear/formatted");
+		File outDir = new File("C:/Users/sunyj-pc/Desktop/crystal-clear/formatted/out");
+		File styleFile = new File("src/main/resources/crystal2jasper.xsl");
+
+		CrystalToJasper crystalToJasper = new CrystalToJasper();
+		crystalToJasper.translate(rptZipFile, outDir, false, styleFile);
+		logger.info("translation complete!");
+	}
+
+	/**
+	 * rpt压缩文件转为jasper
+	 * 
+	 * @param rptZipFile
+	 *            rpt压缩文件(夹)
+	 * @param outDir
+	 *            生成的jasper输出文件夹
+	 * @param remainHierarchy
+	 *            是否保持生成的jasper与rpt压缩路径层级相同
+	 * @param styleFile
+	 *            映射规则文件
+	 * @throws IOException
+	 * @throws DocumentException
+	 * @throws TransformerException
+	 */
+	private void translate(File rptZipFile, File outDir, boolean remainHierarchy, File styleFile)
+			throws IOException, DocumentException, TransformerException {
+		FileUtils.checkFile(rptZipFile);
+		if (rptZipFile.isFile()) {
+			toJasper(rptZipFile, new File(rptZipFile.getParentFile(), "success"), outDir, remainHierarchy, styleFile);
+		} else {
+			toJaspers(rptZipFile, new File(rptZipFile, "success"), outDir, remainHierarchy, styleFile);
+		}
+	}
+
+	/**
+	 * rpt压缩文件夹转为jasper
+	 * 
+	 * @param rptZipDir
+	 *            rpt压缩文件夹
+	 * @param successDir
+	 *            转换成功的rpt文件存放文件夹
+	 * @param outDir
+	 *            生成的jasper输出文件夹
+	 * @param remainHierarchy
+	 *            是否保持生成的jasper与rpt压缩路径层级相同
+	 * @param styleFile
+	 *            映射规则文件
+	 * @throws FileNotFoundException
+	 */
+	private void toJaspers(File rptZipDir, File successDir, File outDir, boolean remainHierarchy, File styleFile)
+			throws FileNotFoundException {
+		FileUtils.checkDir(rptZipDir);
+		File[] files = rptZipDir.listFiles(new FileFilter() {
+			@Override
+			public boolean accept(File file) {
+				if (file == null || !file.exists()) {
+					return false;
+				}
+				// success路径下的文件不进行转换
+				String filePath = file.getAbsolutePath();
+				if (filePath.endsWith("success") || filePath.contains("\\success\\")
+						|| filePath.contains("/success/")) {
+					return false;
+				}
+				// 文件必须是rpt或者zip格式
+				if (file.isFile() && !filePath.endsWith(".rpt") && !filePath.endsWith(".zip")) {
+					return false;
+				}
+				return true;
+			}
+		});
+		for (File file : files) {
+			try {
+				String fileName = file.getName();
+				// 是文件夹的话,递归处理
+				if (file.isDirectory()) {
+					// 不可直接修改successDir和outDir,否则会造成其他文件的路径有问题
+					File successDirCopy = new File(successDir, fileName);
+					File outDirCopy = remainHierarchy ? new File(outDir, fileName) : outDir;
+					toJaspers(file, successDirCopy, outDirCopy, remainHierarchy, styleFile);
+				} else {
+					toJasper(file, successDir, outDir, remainHierarchy, styleFile);
+				}
+			} catch (Throwable e) {
+				logger.error(file.getName(), e);
+			}
+		}
+	}
+
+	/**
+	 * 单个rpt压缩文件转为jasper
+	 * 
+	 * @param rptZipFile
+	 *            单个rpt压缩文件
+	 * @param successDir
+	 *            转换成功的rpt文件存放文件夹
+	 * @param outDir
+	 *            生成的jasper输出文件夹
+	 * @param remainHierarchy
+	 *            是否保持生成的jasper与rpt压缩路径层级相同
+	 * @param styleFile
+	 *            映射规则文件
+	 * @throws IOException
+	 * @throws DocumentException
+	 * @throws TransformerException
+	 */
+	private void toJasper(File rptZipFile, File successDir, File outDir, boolean remainHierarchy, File styleFile)
+			throws IOException, DocumentException, TransformerException {
+		toJasper(rptZipFile, outDir, remainHierarchy, styleFile);
+		// 转换成功之后,将文件移至其他路径下
+		FileUtils.initDir(successDir);
+		// FileUtils.move(rptZipFile, new File(successDir,
+		// rptZipFile.getName()));
+		System.out.println();
+	}
+
+	/**
+	 * 单个rpt压缩文件转为jasper
+	 * 
+	 * @param rptZipFile
+	 *            单个rpt压缩文件
+	 * @param outDir
+	 *            生成的jasper输出文件夹
+	 * @param remainHierarchy
+	 *            是否保持生成的jasper与rpt压缩路径层级相同
+	 * @param styleFile
+	 *            映射规则文件
+	 * @throws IOException
+	 * @throws DocumentException
+	 * @throws TransformerException
+	 */
+	private void toJasper(File rptZipFile, File outDir, boolean remainHierarchy, File styleFile)
+			throws IOException, DocumentException, TransformerException {
+		logger.info("translating... " + rptZipFile.getName());
+		FileUtils.initDir(outDir);
+		String reportName = FileUtils.removeSuffix(rptZipFile.getName());
+		File reportDir = remainHierarchy ? new File(outDir, reportName) : outDir;
+		File uncompressedDir = new File(reportDir, "uncompressed");
+		FileUtils.deleteDir(uncompressedDir);
+		FileUtils.initDir(uncompressedDir);
+
+		// 先解压缩rpt压缩包
+		ZipUtils.unzip(rptZipFile.getAbsolutePath(), uncompressedDir.getAbsolutePath());
+
+		// 获取解压后的所有子报表文件夹
+		File[] subDirs = uncompressedDir.listFiles(new FileFilter() {
+			@Override
+			public boolean accept(File file) {
+				if (file.isDirectory() && file.getName().startsWith("Sub_")) {
+					return true;
+				}
+				return false;
+			}
+		});
+		Map<Integer, String> subReportNames = new HashMap<>();
+		for (File subDir : subDirs) {
+			Integer subReportId = getSubReportId(subDir.getName());
+			String subReportName = getSubReportName(subDir);
+			subReportNames.put(subReportId, subReportName);
+			File subReportFile = new File(reportDir, subReportName + ".jrxml");
+			map(new File(subDir, "content.xml"), subReportFile, styleFile);
+			modifyReportName(subReportFile, subReportName);
+		}
+
+		File reportFile = new File(reportDir, reportName + ".jrxml");
+		map(new File(uncompressedDir, "content.xml"), reportFile, styleFile);
+		modifyReportName(reportFile, reportName);
+		// 替换子报表路径
+		processSubReportPath(reportFile, subReportNames);
+
+		// 完成转换后删除解压缩的文件
+		FileUtils.deleteDir(uncompressedDir);
+	}
+
+	/**
+	 * 根据映射文件将xml文件映射为jrxml文件
+	 * 
+	 * @param xmlFile
+	 *            xml源文件
+	 * @param outFile
+	 *            输出的jrxml文件
+	 * @param styleFile
+	 *            映射文件
+	 * @throws TransformerException
+	 * @throws IOException
+	 */
+	private void map(File xmlFile, File outFile, File styleFile) throws TransformerException, IOException {
+		String jrxml = MapHelper.map(xmlFile, styleFile);
+		FileUtils.write(outFile, jrxml);
+	}
+
+	/**
+	 * 获取子报表id
+	 * 
+	 * @param subDirName
+	 *            子报表文件夹名称(如"Sub_1")
+	 * @return 子报表id
+	 */
+	private Integer getSubReportId(String subDirName) {
+		return Integer.valueOf(subDirName.substring("Sub_".length()));
+	}
+
+	/**
+	 * 获取子报表名称
+	 * 
+	 * @param subDir
+	 *            子报表文件夹
+	 * @return 子报表名称
+	 * @throws DocumentException
+	 */
+	private String getSubReportName(File subDir) throws DocumentException {
+		File metaXmlFile = new File(subDir, "meta.xml");
+		SAXReader saxReader = new SAXReader();
+		Document document = saxReader.read(metaXmlFile);
+		// XPath格式为:/*[name()='Meta']
+		Node node = document.selectSingleNode("//*[name()='Title']");
+		String text = node.getText();
+		text = text.substring(0, text.length() - ".RPT".length());
+		return text;
+	}
+
+	/**
+	 * 修改报表名称
+	 * 
+	 * @param jrxmlFile
+	 *            报表
+	 * @param reportName
+	 *            报表名称
+	 * @throws DocumentException
+	 * @throws IOException
+	 */
+	private void modifyReportName(File jrxmlFile, String reportName) throws DocumentException, IOException {
+		SAXReader saxReader = new SAXReader();
+		Document document = saxReader.read(jrxmlFile);
+		Element element = (Element) document.selectSingleNode("*[name()='jasperReport']");
+		// 修改name节点
+		Attribute attribute = element.attribute("name");
+		attribute.setText(reportName);
+		XMLWriter xmlWriter = new XMLWriter(new FileWriterWithEncoding(jrxmlFile, "UTF-8"));
+		xmlWriter.write(document);
+		xmlWriter.flush();
+	}
+
+	/**
+	 * 处理报表中子报表的路径
+	 * 
+	 * @param jrxmlFile
+	 *            报表
+	 * @param subReportNames
+	 *            子报表ID和名称
+	 * @throws DocumentException
+	 * @throws IOException
+	 */
+	@SuppressWarnings("unchecked")
+	private void processSubReportPath(File jrxmlFile, Map<Integer, String> subReportNames)
+			throws DocumentException, IOException {
+		SAXReader saxReader = new SAXReader();
+		Document document = saxReader.read(jrxmlFile);
+		List<Element> elements = document.selectNodes("//*[name()='subreport']");
+		for (Element element : elements) {
+			// id节点的值由xsl映射得到
+			Node idNode = element.selectSingleNode("*[name()='id']");
+			Integer subReportId = Integer.valueOf(idNode.getText());
+			// 根据子报表id获取名称
+			String subReportName = subReportNames.get(subReportId);
+			if (StringUtils.isEmpty(subReportName)) {
+				throw new ReportException("子报表名称不存在:" + subReportId);
+			}
+			Node subreportExpressionNode = element.selectSingleNode("*[name()='subreportExpression']");
+			// 修改subreportExpression节点
+			subreportExpressionNode.setText("$P{REPORT_DIR} + \"/jrxml/" + subReportName + ".jasper\"");
+			element.remove(idNode);
+		}
+		XMLWriter xmlWriter = new XMLWriter(new FileWriterWithEncoding(jrxmlFile, "UTF-8"));
+		xmlWriter.write(document);
+		xmlWriter.flush();
+	}
+}

+ 39 - 0
src/main/java/com/uas/report/crystal2jasper/MapHelper.java

@@ -0,0 +1,39 @@
+package com.uas.report.crystal2jasper;
+
+import java.io.File;
+import java.io.StringWriter;
+
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+/**
+ * 格式化的xml与可读xml之间的映射
+ * 
+ * @author sunyj
+ * @since 2017年1月18日 下午3:36:36
+ */
+public class MapHelper {
+
+	/**
+	 * 映射
+	 * 
+	 * @param sourceXmlFile
+	 *            源xml文件
+	 * @param mapRuleFile
+	 *            映射处理文件
+	 * @return 映射后的xml
+	 * @throws TransformerException
+	 */
+	public static String map(File sourceXmlFile, File mapRuleFile) throws TransformerException {
+		TransformerFactory factory = TransformerFactory.newInstance();
+		Transformer transformer = factory.newTransformer(new StreamSource(mapRuleFile));
+		StringWriter writer = new StringWriter();
+		StreamResult result = new StreamResult(writer);
+		transformer.transform(new StreamSource(sourceXmlFile), result);
+		return writer.toString();
+	}
+
+}