|
|
@@ -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();
|
|
|
+ }
|
|
|
+}
|