Spring POI 从模板生成Excel并打印
来源:互联网 发布:用手机淘宝买东西步骤 编辑:程序博客网 时间:2024/06/10 06:00
Spring POI 从模板生成Excel并打印
提醒:
java运行在服务器端,使用java调用打印时,外部连接服务器访问打印程序,调用的是服务器端的打印机。
如果想调用本地打印机可以使用JavaScript。
理想:
实际:
项目需求:从数据库中生成报表并打印。之前已经写好报表导出成Excel模块,所以我想在此基础上进行扩充,先生成Excel文件,再将该文件打印。由于本次项目使用Chrome,如果是IE浏览器可以使用自带打印功能,但是Chrome并没有。下面是解决过程:
Java自带打印功能
在查询资料工程中得知java自带打印功能,但是不能打印office文档,可以打印PDF。
在测试过程中发现PDF也打印不了,不知道是什么原因。
虽然打印类型可选DocFlavor.INPUT_STREAM.PDF
,或者自动识别DocFlavor.INPUT_STREAM.AUTOSENSE
,但是打印PDF时还是会抛异常(使用PDF打印机测试):
Exception in thread "main" java.lang.IllegalArgumentException: services must be non-null and non-empty at javax.print.ServiceUI.printDialog(ServiceUI.java:167) at com.srie.util.test.TestPrinter.main(TestPrinter.java:32)
打印图片正常,可以设置打印参数,代码如下:(忘记是从哪位朋友博客里看到的了o(╯□╰)o)
package com.srie.util.test;import javax.print.*;import javax.print.attribute.DocAttributeSet;import javax.print.attribute.HashDocAttributeSet;import javax.print.attribute.HashPrintRequestAttributeSet;import javax.swing.*;import java.io.File;import java.io.FileInputStream;public class TestPrinter { public static void main(String[] args) { JFileChooser fileChooser = new JFileChooser(); // 创建打印作业 int state = fileChooser.showOpenDialog(null); if (state == JFileChooser.APPROVE_OPTION) { File file = fileChooser.getSelectedFile(); // 获取选择的文件 // 构建打印请求属性集 HashPrintRequestAttributeSet pras = new HashPrintRequestAttributeSet(); // 设置打印格式,打印JPG图片 DocFlavor flavor = DocFlavor.INPUT_STREAM.JPEG; // 查找所有的可用的打印服务 PrintService printService[] = PrintServiceLookup .lookupPrintServices(flavor, pras); // 定位默认的打印服务 PrintService defaultService = PrintServiceLookup .lookupDefaultPrintService(); // 显示打印对话框 PrintService service = ServiceUI.printDialog(null, 200, 200, printService, defaultService, flavor, pras); if (service != null) { try { DocPrintJob job = service.createPrintJob(); // 创建打印作业 FileInputStream fis = new FileInputStream(file); // 构造待打印的文件流 DocAttributeSet das = new HashDocAttributeSet(); Doc doc = new SimpleDoc(fis, flavor, das); job.print(doc, pras); } catch (Exception e) { e.printStackTrace(); } } } }}
JACOB - Java COM Bridge
下载链接:http://download.csdn.net/detail/wangxiaoan1234/9909130
使用jacob可以方便的操作office文档,甚至打印,而我的关注点在打印上。
1. 使用jacob首先要将jar包对应的dll文件放到“某个目录”下。
有说放在Windows/system32
下的,有说放在%JAVA_HOME/jre/bin%
下的。经我测试得到的结果是Windows7系统只在%JAVA_HOME/jre/bin%
放一份dll文件即可,Windows10不需要dll文件。
在使用过程中我遇到一个问题,同样的代码在两台电脑上一个打印成功,一个抛异常。
Windows7_64位系统:
- office2007
- eclipse_32位
- jdk1.8_32位
在%JAVA_HOME/jre/bin%
下放入×64dll文件后打印正常。
Windows10_64位系统:
- office2016
- eclipse_32位
- jdk1.8_32位
在%JAVA_HOME/jre/bin%
下放入dll文件后打印抛如下异常:
java.lang.NoSuchMethodError: com.jacob.com.Dispatch.put(Lcom/jacob/com/Dispatch;Ljava/lang/String;Ljava/lang/Object;)V
换成jdk1.8_64位后报错如下:
java.lang.NoClassDefFoundError: Could not initialize class com.jacob.com.ComThread
原因:jar包对应的dll文件是32位,应该用64位,换成64位打印正常。
Windows10_64位系统:
- office2007
- IDEA2017.1
- jdk1.8_32位
添不添加dll文件打印时都会抛如下异常:
## A fatal error has been detected by the Java Runtime Environment:## EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x77a282a5, pid=14440, tid=15272## JRE version: Java(TM) SE Runtime Environment (8.0_31-b13) (build 1.8.0_31-b13)# Java VM: Java HotSpot(TM) Client VM (25.31-b07 mixed mode windows-x86 )# Problematic frame:# C [ntdll.dll+0x782a5]## Failed to write core dump. Minidumps are not enabled by default on client versions of Windows## An error report file with more information is saved as:# D:\tools\tomcat-7.0.57\bin\hs_err_pid14440.log## If you would like to submit a bug report, please visit:# http://bugreport.java.com/bugreport/crash.jsp# The crash happened outside the Java Virtual Machine in native code.# See problematic frame for where to report the bug.#
**Windows10_64位系统:
- office2007
- IDEA2017.1
- jdk1.8_64位
无需dll文件打印正常。**
在遇到抛异常的情况的时候,检查代码无错,请确认JDK与IDE的版本,dll文件需和jar包对应,位数和电脑系统对应。
2. 在项目中添加jar包依赖。
由于项目采用maven管理,将jacob-1.18.jar放到WEB-INF/lib下,在pom.xml中添加如下代码后maven更新项目。
<!-- 打印依赖的jar包 --><dependency> <groupId>com.jacob</groupId> <artifactId>jacob</artifactId> <version>1.18</version> <scope>system</scope> <systemPath>${basedir}/src/main/webapp/WEB-INF/lib/jacob-1.18.jar</systemPath></dependency>
3. 代码
首先感谢甲方公司的chykong大神,代码是基于他写的方法上完成的。
打印参数类:PrintsVo
package com.srie.common.vo;/** * 打印页面设置条件 * @author 王晓安 * @date 2017-7-11 */public class PrintVo { private final double rate = 0.393700787; //1厘米=0.393700787英寸 private short zzxh; //纸张型号,如A4 private boolean dyfx; //打印方向,true为横向,false为竖向 private double topMargin; //页面上边距 private double bottomMargin; //页面下边距 private double leftMargin; //页面左边距 private double rightMargin; //页面右边距 public short getZzxh() { return zzxh; } public void setZzxh(short zzxh) { this.zzxh = zzxh; } public boolean getDyfx() { return dyfx; } public void setDyfx(boolean dyfx) { this.dyfx = dyfx; } public double getTopMargin() { return topMargin; } public void setTopMargin(double topMargin) { this.topMargin = topMargin * rate; } public double getBottomMargin() { return bottomMargin; } public void setBottomMargin(double bottomMargin) { this.bottomMargin = bottomMargin * rate; } public double getLeftMargin() { return leftMargin; } public void setLeftMargin(double leftMargin) { this.leftMargin = leftMargin * rate; } public double getRightMargin() { return rightMargin; } public void setRightMargin(double rightMargin) { this.rightMargin = rightMargin * rate; } @Override public String toString() { return "PrintVo [zzxh=" + zzxh + ", dyfx=" + dyfx + ", topMargin=" + topMargin + ", bottomMargin=" + bottomMargin + ", leftMargin=" + leftMargin + ", rightMargin=" + rightMargin + "]"; }}
打印方法类:Printer
package com.srie.util.test;import com.jacob.activeX.ActiveXComponent;import com.jacob.com.ComThread;import com.jacob.com.Dispatch;import com.jacob.com.Variant;import com.srie.common.vo.PrintVo;import org.apache.poi.hssf.usermodel.HSSFPrintSetup;import org.apache.poi.hssf.usermodel.HSSFSheet;import org.apache.poi.hssf.usermodel.HSSFWorkbook;import org.apache.poi.hssf.util.HSSFColor;import org.apache.poi.ss.usermodel.*;import java.io.*;/** * 打印测试 * @author 王晓安 * 2017年7月16日 */public class Printer { //打印文件依赖的jacob-1.18.jar需要在jre路径下放jacob-1.18-x86.dll文件 static { FileOutputStream os = null; FileInputStream in = null; //获取Windows版本,取得对应dll文件 String systemBit = System.getProperties().get("os.arch").toString().substring(3); //amd64 or amd32 String dllFile = ""; if (systemBit.equals("64")) dllFile = "jacob-1.18-x64.dll"; else dllFile = "jacob-1.18-x86.dll"; //jre目录下bin目录,将web-inf下lib文件里的dll文件放到这里,打印需要这个文件 File jreBinDll = new File(System.getProperty("java.home") + "/bin/" + dllFile); //打印所需的dll文件路径(系统根目录) File printDLL = new File(Thread.currentThread().getContextClassLoader().getResource("").getPath() + "../../" + dllFile); if (!jreBinDll.exists()) { try { in = new FileInputStream(printDLL); os = new FileOutputStream(jreBinDll); byte[] tempArr = new byte[(int) printDLL.length()]; in.read(tempArr); os.write(tempArr); } catch (Exception e) { e.printStackTrace(); } } } /** * 打印报表,后台调取数据并生成Excel文件参考自exportRpt方法, * 不同之处是将生成的Excel以文件形式直接保存在本地,并调用系统默认打印机打印生成的Excel * @author 王晓安 * @param data 需要转换成Excel的二维数组 * @param srcFile 报表模板 * @param file_name 生成的Excel文件名 * @param titleRows 标题栏行数 * @param alignment Excel每列的对齐方式数组 * @param printVo 打印参数 */ public static void print(String[][] data, String srcFile, String file_name, int titleRows, short[] alignment, PrintVo printVo) { FileOutputStream os = null; FileInputStream in = null; //临时文件夹,用于保存将要打印的Excel文件 File tempFolder= new File("D:/tempPrint"); //Excel文件名 String fileName = "temp.xls"; //保存将要打印的excel File printFile = null; try { in = new FileInputStream(srcFile); Workbook work = new HSSFWorkbook(in); HSSFSheet sheet = (HSSFSheet) work.getSheetAt(0); sheet.getPrintSetup().setLandscape(printVo.getDyfx());// 打印方向,true:横向,false:纵向(默认) sheet.setMargin(HSSFSheet.TopMargin, printVo.getTopMargin());// 页边距(上) sheet.setMargin(HSSFSheet.BottomMargin, printVo.getBottomMargin());// 页边距(下) sheet.setMargin(HSSFSheet.LeftMargin, printVo.getLeftMargin());// 页边距(左) sheet.setMargin(HSSFSheet.RightMargin, printVo.getRightMargin());// 页边距(右) sheet.setVerticallyCenter(false);//设置Excel是否垂直居中 sheet.setHorizontallyCenter(false);//设置Excel是否水平居中 //设置打印纸张 HSSFPrintSetup ps = sheet.getPrintSetup(); ps.setPaperSize(printVo.getZzxh()); // 数据样式 Font fontData = work.createFont(); fontData.setFontHeightInPoints((short) 11); fontData.setFontName("宋体"); fontData.setBoldweight((short) 1); Font fontDataBold = work.createFont(); fontDataBold.setFontHeightInPoints((short) 10); fontDataBold.setFontName("宋体"); fontDataBold.setBoldweight(Font.BOLDWEIGHT_BOLD); CellStyle cellDataStyleBold = work.createCellStyle(); cellDataStyleBold.setFont(fontDataBold); cellDataStyleBold.setBorderBottom((short) 1); cellDataStyleBold.setBorderLeft((short) 1); cellDataStyleBold.setBorderRight((short) 1); cellDataStyleBold.setBorderTop((short) 1); cellDataStyleBold.setFillPattern(CellStyle.SOLID_FOREGROUND); cellDataStyleBold.setFillForegroundColor(HSSFColor.WHITE.index); cellDataStyleBold.setAlignment(CellStyle.ALIGN_CENTER); cellDataStyleBold.setVerticalAlignment(CellStyle.VERTICAL_CENTER); cellDataStyleBold.setWrapText(true); //填充单元格样式 CellStyle cellTextStyle = work.createCellStyle(); cellTextStyle.setFont(fontData); cellTextStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER); cellTextStyle.setWrapText(true); // 得到行,并填充数据和表格样式 for (int i = 0; i < data.length; i++) { Row row = sheet.createRow(i + titleRows);// 创建新行 for (int j = 0; j < data[i].length; j++) { cellDataStyleBold.setAlignment(alignment[j]); String str = data[i][j]; Cell cell = row.createCell(j);// 得到第j个单元格 cell.setCellStyle(cellDataStyleBold);// 填充样式 cell.setCellValue(str);// 填充值 } } //如果文件夹不存在,则创建该临时文件夹 if (!tempFolder.exists()) { tempFolder.mkdirs(); } //如果文件夹还不存在,可能该用户电脑没有D盘,在C盘创建相应文件夹 if (!tempFolder.exists()) { tempFolder = new File(tempFolder.getPath().replace('D', 'C')); tempFolder.mkdirs(); } printFile = new File(tempFolder, fileName); os = new FileOutputStream(printFile); work.write(os); os.flush(); work.close(); //初始化COM线程 ComThread.InitSTA(); //新建Excel对象 ActiveXComponent xl = new ActiveXComponent("Excel.Application"); //设置打印时不打开文档,true为打开文档 Dispatch.put(xl, "Visible", new Variant(false)); //打开具体的工作簿 Dispatch workbooks = xl.getProperty("Workbooks").toDispatch(); // 打开文档 Dispatch excel = Dispatch.call(workbooks, "Open", printFile.getPath()).toDispatch(); // 开始打印 Dispatch.call(excel, "PrintOut"); xl.invoke("Quit", new Variant[] {}); } catch (FileNotFoundException e) { System.out.println("文件路径错误"); e.printStackTrace(); } catch (IOException e) { System.out.println("文件输入流错误"); e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } finally { if (os != null) { try { os.close(); } catch (IOException e) { e.printStackTrace(); } } if (in != null) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } // 释放资源 ComThread.Release(); } }}
打印测试类:TestPrinter
package com.srie.util.test;import com.srie.common.vo.PrintVo;import org.apache.poi.ss.usermodel.CellStyle;import org.apache.poi.ss.usermodel.PrintSetup;public class TestPrinter { public static void main(String[] args) { PrintVo printVo = new PrintVo(); //设置打印参数的类 printVo.setTopMargin(1); //上边距 1cm printVo.setBottomMargin(1); //下边距 1cm printVo.setLeftMargin(1); //左边距 1cm printVo.setRightMargin(1); //右边距 1cm printVo.setDyfx(true); //打印方向,true横向,false纵向 printVo.setZzxh(PrintSetup.A4_PAPERSIZE); //打印纸张型号A4, /** A4 - 210x297 mm */short A4_PAPERSIZE = 9; short[] alignment = new short[]{CellStyle.ALIGN_CENTER, CellStyle.ALIGN_CENTER}; //short ALIGN_CENTER = 0x2; String srcFile = "D:/测试模板.xls";//定义报表模板 String[][] data = new String[][]{{"Lisa", "22"}, {"Tony", "21"}}; Printer printer = new Printer(); String fileName = "测试"; printer.print(data, srcFile, fileName, 1, alignment, printVo); }}
测试结果:
hhhh
可以写一个前台页面,用来传递打印参数和调取打印方法。
- Spring POI 从模板生成Excel并打印
- poi实现根据excel模板,生成excel并导入数据
- 使用POI生成Excel文档并设置打印样式
- 使用POI生成Excel文档并设置打印样式
- 借助POI实现Java生成并打印报表(Excel)
- java poi 生成excel模板
- POI运用Excel模板打印报表
- 10、借助POI实现Java生成并打印excel报表(1)
- 11、借助POI实现Java生成并打印excel报表(2)
- 用POI加载模板生成excel报表
- poi-----无模板生成Excel的方法
- java生成excel并下载(poi)
- poi写入excel并生成文件
- 从POI 生成EXCEL 到二进制下载
- spring里结合POI生成EXCEL
- 利用spring的poi生成Excel
- spring里结合POI生成EXCEL
- POI通过读取Excel模板生成Excel文件
- Ubuntu搭建PHP环境实现和微信通信
- SpringMVC学习之数据绑定和表单标签库
- RNN实例(一)
- 二分图与二分图匹配概念
- MB Link Permission statement
- Spring POI 从模板生成Excel并打印
- 【leetcode】1. Two Sum(Python & C++)
- MySQL函数
- [BZOJ2934]业务
- 一些常用的网站
- 文件的相对路径和绝对路径,加载资源文件失败
- 随笔分类
- 数据库范式
- 斐波那契迭代和递归