sunyj 8 лет назад
Родитель
Сommit
608adca564

+ 203 - 14
src/main/java/com/uas/report/crystal2jasper/CrystalToJasper.java

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

+ 120 - 0
src/main/java/com/uas/report/crystal2jasper/Join.java

@@ -0,0 +1,120 @@
+package com.uas.report.crystal2jasper;
+
+import java.util.List;
+
+/**
+ * 表之间的join
+ * 
+ * @author sunyj
+ * @since 2017年5月23日 下午2:03:37
+ */
+public class Join {
+
+	private String fromTableName;
+	private String toTableName;
+	private JoinType joinType;
+	private List<Link> links;
+
+	public Join(String fromTableName, String toTableName, JoinType joinType) {
+		super();
+		this.fromTableName = fromTableName;
+		this.toTableName = toTableName;
+		this.joinType = joinType;
+	}
+
+	public Join(String fromTableName, String toTableName, JoinType joinType, List<Link> links) {
+		this.fromTableName = fromTableName;
+		this.toTableName = toTableName;
+		this.joinType = joinType;
+		this.links = links;
+	}
+
+	public String getFromTableName() {
+		return fromTableName;
+	}
+
+	public void setFromTableName(String fromTableName) {
+		this.fromTableName = fromTableName;
+	}
+
+	public String getToTableName() {
+		return toTableName;
+	}
+
+	public void setToTableName(String toTableName) {
+		this.toTableName = toTableName;
+	}
+
+	public JoinType getJoinType() {
+		return joinType;
+	}
+
+	public void setJoinType(JoinType joinType) {
+		this.joinType = joinType;
+	}
+
+	public List<Link> getLinks() {
+		return links;
+	}
+
+	public void setLinks(List<Link> links) {
+		this.links = links;
+	}
+
+	public String getExpression() {
+		StringBuilder builder = new StringBuilder(joinType.getExpression());
+		builder.append(" ").append(toTableName).append(" ON ");
+		int i = 0;
+		for (Link link : links) {
+			if (i++ != 0) {
+				builder.append("and ");
+			}
+			builder.append(fromTableName).append(".").append(link.getFromColumnName()).append(" ")
+					.append(link.getJoinType().getExpression()).append(" ").append(toTableName).append(".")
+					.append(link.getToColumnName());
+		}
+		return builder.toString();
+	}
+
+	@Override
+	public String toString() {
+		return "Join [fromTableName=" + fromTableName + ", toTableName=" + toTableName + ", joinType=" + joinType
+				+ ", links=" + links + "]";
+	}
+
+	public enum JoinType {
+		/**
+		 * Inner join.
+		 */
+		INNER("INNER JOIN"),
+
+		/**
+		 * Left outer join.
+		 */
+		LEFT("LEFT JOIN"),
+
+		/**
+		 * Right outer join.
+		 */
+		RIGHT("RIGHT JOIN"),
+
+		/**
+		 * Full outer join.
+		 */
+		FULL("FULL OUTER JOIN");
+
+		private String expression;
+
+		private JoinType(String expression) {
+			this.expression = expression;
+		}
+
+		public String getExpression() {
+			return expression;
+		}
+
+		public static JoinType getJoinType(String joinType) {
+			return valueOf(joinType.toUpperCase());
+		}
+	}
+}

+ 96 - 0
src/main/java/com/uas/report/crystal2jasper/Link.java

@@ -0,0 +1,96 @@
+package com.uas.report.crystal2jasper;
+
+/**
+ * @author sunyj
+ * @since 2017年5月23日 下午2:15:26
+ */
+public class Link {
+
+	private String fromColumnName;
+	private String toColumnName;
+	private LinkType joinType;
+
+	public Link(String fromColumnName, String toColumnName, LinkType joinType) {
+		super();
+		this.fromColumnName = fromColumnName;
+		this.toColumnName = toColumnName;
+		this.joinType = joinType;
+	}
+
+	public String getFromColumnName() {
+		return fromColumnName;
+	}
+
+	public void setFromColumnName(String fromColumnName) {
+		this.fromColumnName = fromColumnName;
+	}
+
+	public String getToColumnName() {
+		return toColumnName;
+	}
+
+	public void setToColumnName(String toColumnName) {
+		this.toColumnName = toColumnName;
+	}
+
+	public LinkType getJoinType() {
+		return joinType;
+	}
+
+	public void setJoinType(LinkType joinType) {
+		this.joinType = joinType;
+	}
+
+	@Override
+	public String toString() {
+		return "Link [fromColumnName=" + fromColumnName + ", toColumnName=" + toColumnName + ", joinType=" + joinType
+				+ "]";
+	}
+
+	public enum LinkType {
+		/**
+		 * 等于
+		 */
+		EQ("="),
+
+		/**
+		 * 不等于
+		 */
+		NE("!="),
+
+		/**
+		 * 大于
+		 */
+		GT(">"),
+
+		/**
+		 * 小于
+		 */
+		LT("<"),
+
+		/**
+		 * 大于等于
+		 */
+		GTE(">="),
+
+		/**
+		 * 小于等于
+		 */
+		LTE("<=");
+
+		private String expression;
+
+		private LinkType(String expression) {
+			this.expression = expression;
+		}
+
+		public String getExpression() {
+			return expression;
+		}
+
+		public static LinkType getLinkType(String linkType) {
+			return valueOf(linkType.toUpperCase());
+		}
+	}
+
+}

+ 19 - 28
src/main/resources/crystal2jasper.xsl

@@ -48,8 +48,7 @@
 			</parameter>
 			<!-- subreport parameters -->
 			<xsl:for-each select="PromptFields/Field[@type='PromptVarField']">
-				<xsl:variable name="name"
-					select="substring-after(substring-after(Name/@value,'Pm-'),'.')" />
+				<xsl:variable name="name" select="substring-after(Name/@value,'Pm-')" />
 				<xsl:if test="$name">
 					<parameter>
 						<xsl:variable name="type" select="@valueType" />
@@ -79,9 +78,11 @@
 
 			<!-- fields -->
 			<xsl:for-each select="Datasource/Tablesource/Column">
+				<xsl:variable name="tableName"
+					select="substring-after(../@databaseIdentifier,'.')" />
 				<field>
 					<xsl:attribute name="name"><xsl:value-of
-						select="@name" /></xsl:attribute>
+						select="concat($tableName,'.',@name)" /></xsl:attribute>
 					<xsl:attribute name="class">
 						<xsl:variable name="type" select="@type" />
 						<xsl:choose>
@@ -264,8 +265,7 @@
 											<textFieldExpression>
 												<xsl:choose>
 													<xsl:when test="$type='DatabaseField'">
-														<xsl:value-of
-															select="concat('$F{',substring-after($value,'.'),'}')" />
+														<xsl:value-of select="concat('$F{',$value,'}')" />
 													</xsl:when>
 													<xsl:when test="$type='FormulaField'">
 														<xsl:value-of select="concat('@FormulaField ',$value)" />
@@ -307,11 +307,10 @@
 												<xsl:choose>
 													<xsl:when test="$type='DatabaseField'">
 														<xsl:attribute name="name">
-															<xsl:value-of select="substring-after($value,'.')" />
+															<xsl:value-of select="$value" />
 														</xsl:attribute>
 														<subreportParameterExpression>
-															<xsl:value-of
-																select="concat('$F{',substring-after($value,'.'),'}')" />
+															<xsl:value-of select="concat('$F{',$value,'}')" />
 														</subreportParameterExpression>
 													</xsl:when>
 													<xsl:otherwise>
@@ -509,8 +508,7 @@
 											<textFieldExpression>
 												<xsl:choose>
 													<xsl:when test="$type='DatabaseField'">
-														<xsl:value-of
-															select="concat('$F{',substring-after($value,'.'),'}')" />
+														<xsl:value-of select="concat('$F{',$value,'}')" />
 													</xsl:when>
 													<xsl:when test="$type='FormulaField'">
 														<xsl:value-of select="concat('@FormulaField ',$value)" />
@@ -552,11 +550,10 @@
 												<xsl:choose>
 													<xsl:when test="$type='DatabaseField'">
 														<xsl:attribute name="name">
-															<xsl:value-of select="substring-after($value,'.')" />
+															<xsl:value-of select="$value" />
 														</xsl:attribute>
 														<subreportParameterExpression>
-															<xsl:value-of
-																select="concat('$F{',substring-after($value,'.'),'}')" />
+															<xsl:value-of select="concat('$F{',$value,'}')" />
 														</subreportParameterExpression>
 													</xsl:when>
 													<xsl:otherwise>
@@ -756,8 +753,7 @@
 											<textFieldExpression>
 												<xsl:choose>
 													<xsl:when test="$type='DatabaseField'">
-														<xsl:value-of
-															select="concat('$F{',substring-after($value,'.'),'}')" />
+														<xsl:value-of select="concat('$F{',$value,'}')" />
 													</xsl:when>
 													<xsl:when test="$type='FormulaField'">
 														<xsl:value-of select="concat('@FormulaField ',$value)" />
@@ -799,11 +795,10 @@
 												<xsl:choose>
 													<xsl:when test="$type='DatabaseField'">
 														<xsl:attribute name="name">
-															<xsl:value-of select="substring-after($value,'.')" />
+															<xsl:value-of select="$value" />
 														</xsl:attribute>
 														<subreportParameterExpression>
-															<xsl:value-of
-																select="concat('$F{',substring-after($value,'.'),'}')" />
+															<xsl:value-of select="concat('$F{',$value,'}')" />
 														</subreportParameterExpression>
 													</xsl:when>
 													<xsl:otherwise>
@@ -1001,8 +996,7 @@
 											<textFieldExpression>
 												<xsl:choose>
 													<xsl:when test="$type='DatabaseField'">
-														<xsl:value-of
-															select="concat('$F{',substring-after($value,'.'),'}')" />
+														<xsl:value-of select="concat('$F{',$value,'}')" />
 													</xsl:when>
 													<xsl:when test="$type='FormulaField'">
 														<xsl:value-of select="concat('@FormulaField ',$value)" />
@@ -1044,11 +1038,10 @@
 												<xsl:choose>
 													<xsl:when test="$type='DatabaseField'">
 														<xsl:attribute name="name">
-															<xsl:value-of select="substring-after($value,'.')" />
+															<xsl:value-of select="$value" />
 														</xsl:attribute>
 														<subreportParameterExpression>
-															<xsl:value-of
-																select="concat('$F{',substring-after($value,'.'),'}')" />
+															<xsl:value-of select="concat('$F{',$value,'}')" />
 														</subreportParameterExpression>
 													</xsl:when>
 													<xsl:otherwise>
@@ -1246,8 +1239,7 @@
 											<textFieldExpression>
 												<xsl:choose>
 													<xsl:when test="$type='DatabaseField'">
-														<xsl:value-of
-															select="concat('$F{',substring-after($value,'.'),'}')" />
+														<xsl:value-of select="concat('$F{',$value,'}')" />
 													</xsl:when>
 													<xsl:when test="$type='FormulaField'">
 														<xsl:value-of select="concat('@FormulaField ',$value)" />
@@ -1289,11 +1281,10 @@
 												<xsl:choose>
 													<xsl:when test="$type='DatabaseField'">
 														<xsl:attribute name="name">
-															<xsl:value-of select="substring-after($value,'.')" />
+															<xsl:value-of select="$value" />
 														</xsl:attribute>
 														<subreportParameterExpression>
-															<xsl:value-of
-																select="concat('$F{',substring-after($value,'.'),'}')" />
+															<xsl:value-of select="concat('$F{',$value,'}')" />
 														</subreportParameterExpression>
 													</xsl:when>
 													<xsl:otherwise>