|
|
@@ -4,9 +4,12 @@ import java.io.File;
|
|
|
import java.io.FileFilter;
|
|
|
import java.io.FileNotFoundException;
|
|
|
import java.io.IOException;
|
|
|
+import java.util.ArrayList;
|
|
|
import java.util.HashMap;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
+import java.util.Map.Entry;
|
|
|
+import java.util.Set;
|
|
|
|
|
|
import javax.xml.transform.TransformerException;
|
|
|
|
|
|
@@ -23,6 +26,8 @@ import org.slf4j.LoggerFactory;
|
|
|
import org.springframework.util.StringUtils;
|
|
|
|
|
|
import com.uas.report.core.exception.ReportException;
|
|
|
+import com.uas.report.crystal2jasper.Join.JoinType;
|
|
|
+import com.uas.report.crystal2jasper.Link.LinkType;
|
|
|
import com.uas.report.util.FileUtils;
|
|
|
import com.uas.report.util.ZipUtils;
|
|
|
|
|
|
@@ -169,7 +174,7 @@ public class CrystalToJasper {
|
|
|
String reportName = FileUtils.removeSuffix(rptZipFile.getName());
|
|
|
File reportDir = remainHierarchy ? new File(outDir, reportName) : outDir;
|
|
|
File uncompressedDir = new File(reportDir, "uncompressed");
|
|
|
- FileUtils.deleteDir(uncompressedDir);
|
|
|
+ FileUtils.deleteDir(uncompressedDir, false);
|
|
|
FileUtils.initDir(uncompressedDir);
|
|
|
|
|
|
// 先解压缩rpt压缩包
|
|
|
@@ -190,19 +195,31 @@ public class CrystalToJasper {
|
|
|
Integer subReportId = getSubReportId(subDir.getName());
|
|
|
String subReportName = getSubReportName(subDir);
|
|
|
subReportNames.put(subReportId, subReportName);
|
|
|
+ File rptXmlFile = new File(subDir, "content.xml");
|
|
|
File subReportFile = new File(reportDir, subReportName + ".jrxml");
|
|
|
- map(new File(subDir, "content.xml"), subReportFile, styleFile);
|
|
|
+ // 映射子报表为jrxml
|
|
|
+ map(rptXmlFile, subReportFile, styleFile);
|
|
|
+ // 修改报表名称
|
|
|
modifyReportName(subReportFile, subReportName);
|
|
|
+ // 修改查询语句
|
|
|
+ String queryString = parseQueryString(rptXmlFile);
|
|
|
+ modifyQueryString(subReportFile, queryString);
|
|
|
}
|
|
|
|
|
|
+ File rptXmlFile = new File(uncompressedDir, "content.xml");
|
|
|
File reportFile = new File(reportDir, reportName + ".jrxml");
|
|
|
- map(new File(uncompressedDir, "content.xml"), reportFile, styleFile);
|
|
|
+ // 映射主报表为jrxml
|
|
|
+ map(rptXmlFile, reportFile, styleFile);
|
|
|
+ // 修改报表名称
|
|
|
modifyReportName(reportFile, reportName);
|
|
|
+ // 修改查询语句
|
|
|
+ String queryString = parseQueryString(rptXmlFile);
|
|
|
+ modifyQueryString(reportFile, queryString);
|
|
|
// 替换子报表路径
|
|
|
processSubReportPath(reportFile, subReportNames);
|
|
|
|
|
|
// 完成转换后删除解压缩的文件
|
|
|
- FileUtils.deleteDir(uncompressedDir);
|
|
|
+ FileUtils.deleteDir(uncompressedDir, false);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -243,8 +260,7 @@ public class CrystalToJasper {
|
|
|
*/
|
|
|
private String getSubReportName(File subDir) throws DocumentException {
|
|
|
File metaXmlFile = new File(subDir, "meta.xml");
|
|
|
- SAXReader saxReader = new SAXReader();
|
|
|
- Document document = saxReader.read(metaXmlFile);
|
|
|
+ Document document = new SAXReader().read(metaXmlFile);
|
|
|
// XPath格式为:/*[name()='Meta']
|
|
|
Node node = document.selectSingleNode("//*[name()='Title']");
|
|
|
String text = node.getText();
|
|
|
@@ -263,15 +279,12 @@ public class CrystalToJasper {
|
|
|
* @throws IOException
|
|
|
*/
|
|
|
private void modifyReportName(File jrxmlFile, String reportName) throws DocumentException, IOException {
|
|
|
- SAXReader saxReader = new SAXReader();
|
|
|
- Document document = saxReader.read(jrxmlFile);
|
|
|
+ Document document = new 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();
|
|
|
+ saveXmlFile(document, jrxmlFile);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -287,8 +300,7 @@ public class CrystalToJasper {
|
|
|
@SuppressWarnings("unchecked")
|
|
|
private void processSubReportPath(File jrxmlFile, Map<Integer, String> subReportNames)
|
|
|
throws DocumentException, IOException {
|
|
|
- SAXReader saxReader = new SAXReader();
|
|
|
- Document document = saxReader.read(jrxmlFile);
|
|
|
+ Document document = new SAXReader().read(jrxmlFile);
|
|
|
List<Element> elements = document.selectNodes("//*[name()='subreport']");
|
|
|
for (Element element : elements) {
|
|
|
// id节点的值由xsl映射得到
|
|
|
@@ -304,7 +316,184 @@ public class CrystalToJasper {
|
|
|
subreportExpressionNode.setText("$P{REPORT_DIR} + \"/jrxml/" + subReportName + ".jasper\"");
|
|
|
element.remove(idNode);
|
|
|
}
|
|
|
- XMLWriter xmlWriter = new XMLWriter(new FileWriterWithEncoding(jrxmlFile, "UTF-8"));
|
|
|
+ saveXmlFile(document, jrxmlFile);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 解析rpt的xml文件,获取sql查询语句
|
|
|
+ *
|
|
|
+ * @param rptXmlFile
|
|
|
+ * rpt的xml文件
|
|
|
+ * @return sql查询语句
|
|
|
+ * @throws DocumentException
|
|
|
+ */
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ private String parseQueryString(File rptXmlFile) throws DocumentException {
|
|
|
+ Document document = new SAXReader().read(rptXmlFile);
|
|
|
+
|
|
|
+ // 字段
|
|
|
+ Map<String, List<String>> columnNames = new HashMap<>();
|
|
|
+
|
|
|
+ // 表名
|
|
|
+ // <Tablesource alias="FEEPLEASE"
|
|
|
+ // databaseIdentifier="E_SHINE_DIGIT.FEEPLEASE">
|
|
|
+ List<Element> tableSourceElements = document.selectNodes("//Tablesource");
|
|
|
+ List<String> tableNames = new ArrayList<>();
|
|
|
+ for (Element tableSourceElement : tableSourceElements) {
|
|
|
+ String text = tableSourceElement.attribute("databaseIdentifier").getText();
|
|
|
+ // 去除表名前的数据库名
|
|
|
+ int index = text.lastIndexOf(".");
|
|
|
+ String tableName = index < 0 ? text : text.substring(index + 1);
|
|
|
+ tableNames.add(tableName);
|
|
|
+
|
|
|
+ // <Column name="FP_V13" type="11" />
|
|
|
+ List<Element> columnElements = tableSourceElement.elements("Column");
|
|
|
+ List<String> columns = new ArrayList<>();
|
|
|
+ for (Element columnElement : columnElements) {
|
|
|
+ String columnName = columnElement.attribute("name").getText();
|
|
|
+ columns.add(columnName);
|
|
|
+ }
|
|
|
+ columnNames.put(tableName, columns);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 表之间的join关系
|
|
|
+ // <Join from="FEEPLEASE" to="FEEPLEASEDETAIL" type="loj">
|
|
|
+ // <Link from="FP_ID" to="FPD_FPID" type="eq"/>
|
|
|
+ // </Join>
|
|
|
+ List<Element> joinElements = document.selectNodes("//Join");
|
|
|
+ List<Join> joins = new ArrayList<>();
|
|
|
+ for (Element joinElement : joinElements) {
|
|
|
+ String fromTableName = joinElement.attribute("from").getText();
|
|
|
+ String toTableName = joinElement.attribute("to").getText();
|
|
|
+ String joinType = joinElement.attribute("type").getText();
|
|
|
+ Join join = new Join(fromTableName, toTableName, getJoinType(joinType));
|
|
|
+
|
|
|
+ List<Element> linkElements = joinElement.elements("Link");
|
|
|
+ List<Link> links = new ArrayList<>();
|
|
|
+ // 提取两个表join时,所连接的字段关系
|
|
|
+ for (Element linkElement : linkElements) {
|
|
|
+ String fromColumnName = linkElement.attribute("from").getText();
|
|
|
+ String toColumnName = linkElement.attribute("to").getText();
|
|
|
+ String linkType = linkElement.attribute("type").getText();
|
|
|
+ Link link = new Link(fromColumnName, toColumnName, getLinkType(linkType));
|
|
|
+ links.add(link);
|
|
|
+ }
|
|
|
+ join.setLinks(links);
|
|
|
+ joins.add(join);
|
|
|
+ // 有join关系的表需从列表中排除,防止重复
|
|
|
+ tableNames.remove(fromTableName);
|
|
|
+ tableNames.remove(toTableName);
|
|
|
+ }
|
|
|
+ return getQueryString(columnNames, tableNames, joins);
|
|
|
+ }
|
|
|
+
|
|
|
+ private JoinType getJoinType(String type) {
|
|
|
+ if ("inn".equalsIgnoreCase(type)) {
|
|
|
+ return JoinType.INNER;
|
|
|
+ } else if ("loj".equalsIgnoreCase(type)) {
|
|
|
+ return JoinType.LEFT;
|
|
|
+ } else if ("roj".equalsIgnoreCase(type)) {
|
|
|
+ return JoinType.RIGHT;
|
|
|
+ } else if ("foj".equalsIgnoreCase(type)) {
|
|
|
+ return JoinType.FULL;
|
|
|
+ } else {
|
|
|
+ throw new ReportException("无法解析join类型:" + type);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private LinkType getLinkType(String type) {
|
|
|
+ if ("eq".equalsIgnoreCase(type)) {
|
|
|
+ return LinkType.EQ;
|
|
|
+ } else if ("ne".equalsIgnoreCase(type)) {
|
|
|
+ return LinkType.NE;
|
|
|
+ } else if ("gt".equalsIgnoreCase(type)) {
|
|
|
+ return LinkType.GT;
|
|
|
+ } else if ("lt".equalsIgnoreCase(type)) {
|
|
|
+ return LinkType.LT;
|
|
|
+ } else if ("ge".equalsIgnoreCase(type)) {
|
|
|
+ return LinkType.GTE;
|
|
|
+ } else if ("le".equalsIgnoreCase(type)) {
|
|
|
+ return LinkType.LTE;
|
|
|
+ } else {
|
|
|
+ throw new ReportException("无法解析link类型:" + type);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据表名和连接关系获取查询语句
|
|
|
+ *
|
|
|
+ * @param columnNames
|
|
|
+ * 列名
|
|
|
+ * @param tableNames
|
|
|
+ * 表名
|
|
|
+ * @param joins
|
|
|
+ * 连接关系
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private String getQueryString(Map<String, List<String>> columnNames, List<String> tableNames, List<Join> joins) {
|
|
|
+ StringBuilder builder = new StringBuilder("select");
|
|
|
+ int i = 0;
|
|
|
+ if (columnNames != null) {
|
|
|
+ Set<Entry<String, List<String>>> entrySet = columnNames.entrySet();
|
|
|
+ for (Entry<String, List<String>> entry : entrySet) {
|
|
|
+ String tableName = entry.getKey();
|
|
|
+ List<String> columns = entry.getValue();
|
|
|
+ for (String columnName : columns) {
|
|
|
+ if (i++ != 0) {
|
|
|
+ builder.append(",");
|
|
|
+ }
|
|
|
+ // 列名前加表名,防止多个表含有相同字段
|
|
|
+ builder.append(" ").append(tableName).append(".").append(columnName);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ builder.append(" from ");
|
|
|
+
|
|
|
+ StringBuilder tableNameBuilder = new StringBuilder();
|
|
|
+ i = 0;
|
|
|
+ for (String tableName : tableNames) {
|
|
|
+ if (i++ != 0) {
|
|
|
+ tableNameBuilder.append(",");
|
|
|
+ }
|
|
|
+ tableNameBuilder.append(tableName);
|
|
|
+ }
|
|
|
+ for (Join join : joins) {
|
|
|
+ if (!tableNameBuilder.toString().contains(join.getFromTableName())) {
|
|
|
+ tableNameBuilder.append(", ").append(join.getFromTableName());
|
|
|
+ }
|
|
|
+ tableNameBuilder.append(" ").append(join.getExpression());
|
|
|
+ }
|
|
|
+ builder.append(tableNameBuilder);
|
|
|
+ return builder.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 修改queryString节点
|
|
|
+ *
|
|
|
+ * @param jrxmlFile
|
|
|
+ * 报表
|
|
|
+ * @param queryString
|
|
|
+ * queryString的值
|
|
|
+ * @throws DocumentException
|
|
|
+ * @throws IOException
|
|
|
+ */
|
|
|
+ private void modifyQueryString(File jrxmlFile, String queryString) throws DocumentException, IOException {
|
|
|
+ Document document = new SAXReader().read(jrxmlFile);
|
|
|
+ Node node = document.selectSingleNode("//*[name()='queryString']");
|
|
|
+ node.setText(queryString);
|
|
|
+ saveXmlFile(document, jrxmlFile);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 保存xml文件
|
|
|
+ *
|
|
|
+ * @param document
|
|
|
+ * @param xmlFile
|
|
|
+ * 保存的xml文件
|
|
|
+ * @throws IOException
|
|
|
+ */
|
|
|
+ private void saveXmlFile(Document document, File xmlFile) throws IOException {
|
|
|
+ XMLWriter xmlWriter = new XMLWriter(new FileWriterWithEncoding(xmlFile, "UTF-8"));
|
|
|
xmlWriter.write(document);
|
|
|
xmlWriter.flush();
|
|
|
}
|