Browse Source

支持导出为word;
增加获取pdf路径、页数的接口;
System.err的输出定位到logs/log.log文件;

sunyj 8 years ago
parent
commit
557c56740f

+ 9 - 0
src/main/java/com/uas/report/Application.java

@@ -1,5 +1,9 @@
 package com.uas.report;
 
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+
 import org.apache.log4j.Logger;
 import org.springframework.beans.BeansException;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -28,6 +32,11 @@ public class Application extends SpringBootServletInitializer implements Applica
 
 	@Override
 	protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
+		try {
+			System.setErr(new PrintStream(new FileOutputStream("logs/log.log", true)));
+		} catch (FileNotFoundException e) {
+			logger.error("", e);
+		}
 		// 程序入口
 		return builder.sources(Application.class);
 	}

+ 65 - 0
src/main/java/com/uas/report/controller/PrintController.java

@@ -41,6 +41,11 @@ public class PrintController {
 
 	private static Logger logger = LoggerFactory.getLogger(PrintController.class);
 
+	/**
+	 * 报表支持的最大页数,无论是下载excel、pdf还是预览,超过该数值,均不提供服务
+	 */
+	private static final Integer MAX_PAGE_SIZE = 1000;
+
 	@Autowired
 	private PrintService printService;
 
@@ -94,6 +99,11 @@ public class PrintController {
 		else if (printType.equals(ReportConstants.EXCEL_PRINT_TYPE)) {
 			export(userName, profile, reportName, whereCondition, otherParameters,
 					ReportConstants.EXCEL_WITH_ONLY_DATA_FILE_TYPE, true, request, response);
+		}
+		// 下载word
+		else if (printType.equals(ReportConstants.WORD_PRINT_TYPE)) {
+			export(userName, profile, reportName, whereCondition, otherParameters, ReportConstants.WORD_FILE_TYPE, true,
+					request, response);
 		} else {
 			throw new ReportException("printType不合法");
 		}
@@ -266,6 +276,61 @@ public class PrintController {
 		return result;
 	}
 
+	/**
+	 * 获取pdf路径
+	 * 
+	 * @param userName
+	 *            不为null;当前账套名称
+	 * @param profile
+	 *            可选(UAS等系统不必传递该参数),用于标识请求源(B2C、B2B)是正式、测试还是开发版本:prod、test、dev
+	 * @param reportName
+	 *            不为null;需要预览的报表的名称,不带任何后缀(如预览采购单,即为"Purchase")
+	 * @param whereCondition
+	 *            可为null;where之后的条件(包括where)
+	 * @param otherParameters
+	 *            若模板已指定需要的参数,则不可为null;其他参数,区别于whereCondition,报表某些字段的值取决于这些参数;
+	 *            JSON格式,数据为键值对
+	 * @param request
+	 * @param response
+	 * @return 包括pageSize、pdfPath(或overload)
+	 */
+	@RequestMapping(value = "/pdfPath")
+	@ResponseBody
+	public Map<String, Object> getPdfPath(final String userName, final String profile, final String reportName,
+			final String whereCondition, final String otherParameters, HttpServletRequest request,
+			HttpServletResponse response) {
+		ReportUtils.checkParameters(userName, reportName);
+		Map<String, Object> result = new HashMap<>();
+
+		// pdf相对路径
+		String pdfPath = ReportConstants.GENERATED_FILES_PATH + reportName + "/"
+				+ fileService.generateFileName(userName, profile, reportName, whereCondition, otherParameters,
+						ReportConstants.PDF_FILE_TYPE)
+				+ "." + ReportConstants.PDF_FILE_TYPE;
+		final File file = new File(ReportConstants.GENERATED_FILES_DIR + pdfPath);
+		// 创建pdf文件
+		// 需要生成第一页,再生成总的pdf(可能页数过多,此时不再生成总的pdf)
+		Integer pageSize = printService.createPdfFile(userName, profile, reportName, whereCondition, otherParameters,
+				file.getPath().replace("." + ReportConstants.PDF_FILE_TYPE, "_1." + ReportConstants.PDF_FILE_TYPE), 1);
+		result.put("pageSize", pageSize);
+		if (pageSize > MAX_PAGE_SIZE) {
+			result.put("overload", "true");
+		} else {
+			result.put("pdfPath", pdfPath);
+			// 生成总的pdf
+			printService.createPdfFile(userName, profile, reportName, whereCondition, otherParameters, file.getPath(),
+					null);
+			// 再开线程生成后面页的pdf
+			new Thread(new Runnable() {
+				@Override
+				public void run() {
+					fileService.createPagedPdfFiles(file.getPath());
+				}
+			}).start();
+		}
+		return result;
+	}
+
 	/**
 	 * 获取生成的pdf或者xls的信息
 	 * 

+ 92 - 4
src/main/java/com/uas/report/service/impl/PrintServiceImpl.java

@@ -1,10 +1,13 @@
 package com.uas.report.service.impl;
 
 import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.FileReader;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.OutputStream;
 import java.sql.Connection;
 import java.sql.PreparedStatement;
@@ -16,6 +19,7 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -24,12 +28,14 @@ import javax.sql.DataSource;
 
 import org.apache.commons.io.output.FileWriterWithEncoding;
 import org.apache.commons.lang.ArrayUtils;
+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.dom4j.tree.DefaultElement;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -44,8 +50,8 @@ import com.uas.report.jasperreports.engine.export.CustomJRXlsExporter;
 import com.uas.report.model.Master;
 import com.uas.report.service.FileService;
 import com.uas.report.service.PrintService;
-import com.uas.report.util.MasterManager;
 import com.uas.report.util.FileUtils;
+import com.uas.report.util.MasterManager;
 import com.uas.report.util.ReportConstants;
 import com.uas.report.util.ReportUtils;
 
@@ -56,6 +62,7 @@ import net.sf.jasperreports.engine.JasperPrint;
 import net.sf.jasperreports.engine.JasperReport;
 import net.sf.jasperreports.engine.design.JasperDesign;
 import net.sf.jasperreports.engine.export.JRPdfExporter;
+import net.sf.jasperreports.engine.export.JRRtfExporter;
 import net.sf.jasperreports.engine.export.JRXlsExporter;
 import net.sf.jasperreports.engine.xml.JRXmlLoader;
 import net.sf.jasperreports.export.ExporterInput;
@@ -63,6 +70,8 @@ import net.sf.jasperreports.export.OutputStreamExporterOutput;
 import net.sf.jasperreports.export.SimpleExporterInput;
 import net.sf.jasperreports.export.SimpleOutputStreamExporterOutput;
 import net.sf.jasperreports.export.SimplePdfReportConfiguration;
+import net.sf.jasperreports.export.SimpleWriterExporterOutput;
+import net.sf.jasperreports.export.WriterExporterOutput;
 
 /**
  * 报表打印
@@ -160,22 +169,30 @@ public class PrintServiceImpl implements PrintService {
 				logger.info("export fillReport...");
 				boolean customCellStyle = false;
 				// 只导出数据
-				if (exportFileType.equals("xls_with_only_data")) {
+				if (exportFileType.equals(ReportConstants.EXCEL_WITH_ONLY_DATA_FILE_TYPE)) {
 					// 需自定义单元格格式
 					customCellStyle = true;
 					JasperDesign jasperDesign = JRXmlLoader.load(jrxmlFilePath);
 					// 移除模板中多余元素
 					removeUnusedElements(jasperDesign);
-					exportFileType = "xls";
+					exportFileType = ReportConstants.EXCEL_FILE_TYPE;
 					JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign);
 					jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, connection);
 
+				} else if (exportFileType.equals(ReportConstants.WORD_FILE_TYPE)) {
+					// 导出word时需要对字体、行距等进行调整
+					InputStream inputStream = new ByteArrayInputStream(replaceFont(jrxmlFilePath).getBytes());
+					JasperReport jasperReport = JasperCompileManager.compileReport(inputStream);
+					jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, connection);
+					inputStream.close();
 				} else {
 					jasperPrint = JasperFillManager.fillReport(jasperFilePath, parameters, connection);
 				}
 
-				if (exportFileType.equals("xls")) {
+				if (exportFileType.equals(ReportConstants.EXCEL_FILE_TYPE)) {
 					exportReportToXls(jasperPrint, outputStream, customCellStyle);
+				} else if (exportFileType.equals(ReportConstants.WORD_FILE_TYPE)) {
+					exportReportToDoc(jasperPrint, outputStream);
 				} else {
 					exportReportToPdf(jasperPrint, outputStream, pageIndex);
 				}
@@ -408,6 +425,48 @@ public class PrintServiceImpl implements PrintService {
 		return result;
 	}
 
+	/**
+	 * 替换jrxml中的字体等信息
+	 * 
+	 * @param jrxmlFilePath
+	 * @return
+	 * @throws FileNotFoundException
+	 * @throws IOException
+	 * @throws DocumentException
+	 */
+	private String replaceFont(String jrxmlFilePath) throws FileNotFoundException, IOException, DocumentException {
+		File jrxmlFile = new File(jrxmlFilePath);
+		SAXReader saxReader = new SAXReader();
+		Document document = saxReader.read(jrxmlFile);
+		@SuppressWarnings("unchecked")
+		// 获取所有textElement节点(jrxml的XPath格式为:/*[name()='jasperReport']/*[name()='columnHeader']/*[name()='band']/*[name()='textField'])
+		List<Element> textElements = document.selectNodes("//*[name()='textElement']");
+		for (Element textElement : textElements) {
+			// 获取font节点
+			Element fontElement = (Element) textElement.selectSingleNode("*[name()='font']");
+			// 将字体MSYahei改为Microsoft YaHei UI
+			Attribute fontName = fontElement.attribute("fontName");
+			if (Objects.equals(fontName.getText(), "MSYahei")) {
+				fontName.setText("Microsoft YaHei UI");
+			}
+
+			// 更改可换行的textField的行距
+			Element parent = textElement.getParent();
+			if (parent != null && Objects.equals(parent.getName(), "textField")) {
+				// 如果textElement节点指定isStretchWithOverflow为true(可换行),则调整行距
+				Attribute isStretchWithOverflow = parent.attribute("isStretchWithOverflow");
+				if (isStretchWithOverflow != null && Objects.equals(isStretchWithOverflow.getText(), "true")) {
+					// 添加节点paragraph,调整行距为固定值12磅
+					Element paragraphElement = new DefaultElement("paragraph", textElement.getNamespace());
+					paragraphElement.addAttribute("lineSpacing", "Fixed");
+					paragraphElement.addAttribute("lineSpacingSize", "12.0");
+					textElement.add(paragraphElement);
+				}
+			}
+		}
+		return document.asXML();
+	}
+
 	/**
 	 * 以xls的格式导出报表
 	 * 
@@ -425,6 +484,35 @@ public class PrintServiceImpl implements PrintService {
 		exporter.exportReport();
 	}
 
+	/**
+	 * 以doc的格式导出报表
+	 * 
+	 * @param jasperPrint
+	 * @param outputStream
+	 * @throws JRException
+	 * @throws IOException
+	 */
+	private void exportReportToDoc(JasperPrint jasperPrint, OutputStream outputStream) throws JRException, IOException {
+		exportReportToRtf(jasperPrint, outputStream);
+	}
+
+	/**
+	 * 以rtf的格式导出报表
+	 * 
+	 * @param jasperPrint
+	 * @param outputStream
+	 * @throws JRException
+	 * @throws IOException
+	 */
+	private void exportReportToRtf(JasperPrint jasperPrint, OutputStream outputStream) throws JRException, IOException {
+		JRRtfExporter exporter = new JRRtfExporter();
+		ExporterInput exporterInput = new SimpleExporterInput(jasperPrint);
+		exporter.setExporterInput(exporterInput);
+		WriterExporterOutput exporterOutput = new SimpleWriterExporterOutput(outputStream);
+		exporter.setExporterOutput(exporterOutput);
+		exporter.exportReport();
+	}
+
 	/**
 	 * 以pdf的格式导出报表
 	 * 

+ 10 - 0
src/main/java/com/uas/report/util/ReportConstants.java

@@ -38,6 +38,11 @@ public class ReportConstants {
 	 */
 	public static final String EXCEL_PRINT_TYPE = "EXCEL";
 
+	/**
+	 * 请求类型:下载word
+	 */
+	public static final String WORD_PRINT_TYPE = "WORD";
+
 	/**
 	 * 导出文件的格式:pdf
 	 */
@@ -53,6 +58,11 @@ public class ReportConstants {
 	 */
 	public static final String EXCEL_WITH_ONLY_DATA_FILE_TYPE = "xls_with_only_data";
 
+	/**
+	 * 导出文件的格式:word
+	 */
+	public static final String WORD_FILE_TYPE = "doc";
+
 	/**
 	 * 生成的pdf、excel等文件的相对路径
 	 */

+ 4 - 0
src/main/webapp/WEB-INF/views/preview.html

@@ -51,6 +51,10 @@
 			<button id="downloadPdf" class="toolbarButton" title="下载PDF">
 				<i class="fa fa-file-pdf-o fa-lg" aria-hidden="true"></i>
 			</button>
+			<button id="downloadWord" hidden="true" class="toolbarButton"
+				title="下载Word">
+				<i class="fa fa-file-word-o fa-lg" aria-hidden="true"></i>
+			</button>
 			<button id="downloadExcel" class="toolbarButton" title="下载Excel">
 				<i class="fa fa-file-excel-o fa-lg" aria-hidden="true"></i>
 			</button>

+ 9 - 1
src/main/webapp/resources/js/preview/app.js

@@ -143,7 +143,15 @@ function downloadPdf() {
 	hiddenFrame.src = wholePdfPath;
 }
 
-// 下载纯数据excel
+// 下载word
+$("#downloadWord").click(function() {
+	if (!pdfDoc) {
+		return;
+	}
+	window.open(downloadUrl("doc"));
+});
+
+// 下载excel
 $("#downloadExcel").click(function() {
 	if (!pdfDoc) {
 		return;