近期农信项目后台系统客户新提出需求的其中一项涉及到“打印”功能,前期技术储备时,发现网上相关资源甚少且混杂,特别是有关web打印技术,被码农们一致称为“老大难”。现整理了几项经本人验证的可行的打印方法,包括C/S和B/S的,供码友们参考。
一、C/S
1.利用Java.awt中提供的打印API,继承Printable实现接口方法print进行打印。
参考文献:《Java实现打印功能》-----------百度文库。
此方法实际是C/S的打印方法,但是在某些特殊情况下,B/S的打印依然可用,例如在某些特殊的管理系统,操作此系统的用户可以非常方便的设置发布此系统的服务器,那么将服务器所连接的打印机设置成用户指定的打印机,此时再将代码设置成直接打印状态(不弹出打印提示页面),就可以顺利完成打印操作。
该方法的弊端也比较明显,java.awt所提供API实现接口的方法print,最后是用Graphics2D直接输出,所以有关长篇文字的格式只能手动调整(可参考官方API文档的格式调整算法),且参数中只有一个Graphics,以至于整篇文档的字体、颜色都是统一格式,无法调整(也许是本人对Graphics实在不了解),且无法操作页眉页脚(当以Word文档格式时);优点不用说,一般的打印还是可以实现的,且Graphics能画出来的也就都能打印出来,所以,此种打印方式所适用的和不适用的情况也就比较明显了吧。
以下是关键代码,详细请见文件夹下printHelp.java文件中内容。
package com.hepow.cbrc.help;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
importjava.awt.Image;
importjava.awt.Toolkit;
import java.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.awt.geom.Point2D;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
importjava.text.AttributedString;
publicclassprintHelpimplementsPrintable {
/**
* @param Graphic指明打印的图形环境
* @param PageFormat指明打印页格式(页面大小以点为计量单位,1点为1英才的1/72,1英寸为25.4毫米。A4纸大致为595×842点)
* @param pageIndex指明页号
**/
publicintprint(Graphicsgra,PageFormatpf,intpageIndex)throws PrinterException {
System.out.println("pageIndex="+pageIndex);
Component c =null;
//print string
String test = "根据国家劳动管理规定以及本公司员工聘用办法,甲方招聘乙方为试用员<br/>工,双方在平等、自愿的基础上,经协商一致签订本试用合同,共同遵守本协议所列条款"
+ "根据国家劳动管理规定以及本公司员工聘用办法,甲方招聘乙方为试用员工,双方在平等、自愿的基础上,经协商一致签订本试用合同,共同遵守本协议所列条款"
+ "根据国家劳动管理规定以及本公司员工聘用办法,甲方招聘乙方为试用员工,双<br/>方在平等、自愿的基础上,经协商一致签订本试用合同,共同遵守本协议所列条款"
+ "根据国家劳动管理规定以及本公司员工聘用办法,甲方招聘乙方为试用员工,双方在平等、自愿的基础上,经协商一致签订本试用合同,共同遵守本协议所列条款";
String head ="劳动合同范本(二)——试用期劳动合同范本";
String str ="";
String str01 ="甲方:______________________";
String str02 ="乙方: (身份证号)______________________";
String str03 =" 根据国家劳动管理规定以及本公司员工聘用办法,甲方招聘乙方为试用员工,双方在平等、自愿的基础上,经协商一致签订本试用合同,共同遵守本协议所列条款";
String str033 ="基础上,经协商一致签订本试用合同,共同遵守本协议所列条款。";
String str04 ="一、试用合同期限:试用期为个月,自_____年_____月_____日至_____年_____月_____日止。";
String str05 ="二、根据甲方的工作安排,聘用乙方在_______________工作岗位。";
String str06 ="三、甲方聘用乙方的月薪为_____元(含养老、医疗、住房公积金)。试用期满后,并经考核合格,可";
String str066 ="根据平等协商的原则,签订正式劳动合同。";
String str07 ="四、甲方的基本权利与义务:";
String str08 ="1.甲方的权利";
String str09 =" 有权要求乙方遵守国家法律和公司各项规章制度;";
String str10 =" 在试用期间,乙方如严重违反劳动纪律或企业规章制度,甲方有权终止合同。乙方的行为给甲方";
String str100 ="造成损失的,由乙方赔偿,情节严重的追究法律责任;";
String str11 =" 试用期间,乙方由于个人原因所发生的疾病以及伤残等意外事故,乙方自行负责;";
String str12 ="2.甲方的义务";
String str13 =" 为乙方提供必要的工作条件;";
String str14 =" 负责对乙方进行职业道德、业务技能及公司规章制度的教育和培训;";
String str15 ="五、乙方的基本权利和义务。";
String str16 ="1.乙方的权利";
String str17 =" 享有国家法律法规赋予的一切公民权利;";
String str18 =" 享有公司规章制度规定可以享有的福利待遇的权利;";
String str19 =" 试用期间如变更单位,须提前一个月通知甲方,双方协商终止试用合同;";
String str20 ="2.乙方的义务";
String str21 =" 遵守国家法律法规、当地政府规定的公民义务;";
String str22 =" 遵守公司的各项规章制度、员工手册、行为规范的义务;";
String str23 =" 维护公司的声誉、利益的义务。";
String str24 ="六、甲方的其他权利、义务";
String str25 =" 试用期间,乙方不能胜任工作或弄虚作假不符合录用条件,甲方有权提前解除本合同;";
String str26 =" 乙方有突出表现,甲方可提前结束试用,与乙方签订正式劳动合同;";
String str27 ="七、乙方的其他权利、义务";
String str28 =" 试用期满,有权决定是否签订正式劳动合同;";
String str29 =" 具有参与公司民主管理、提出合理化建议的权利;";
String str30 =" 反对和投诉对乙方试用身份不公平的歧视。";
String str31 ="八、本合同如有未尽事宜,双方本着友好协商原则处理。";
String str32 ="九、本合同一式两份,甲、乙双方各执一份,具有同等效力,经甲乙双方签章生效。";
String str33 ="甲方(盖章) 乙方(盖章)";
String str35 ="法定代表人签字:";
String str36 ="签约日期:_____年_____月_____日";
String str37 ="签约地点:";
//转换成Graphics2D
Graphics2D g2 = (Graphics2D) gra;
//设置打印颜色为黑色
g2.setColor(Color.black);
/*Paper paper =pf.getPaper();//得到页面格式的纸张
paper.setSize(500,500);//纸张大小
paper.setImageableArea(0,0,500,500); //设置打印区域的大小
System.out.println(paper.getWidth());
System.out.println(paper.getHeight());
pf.setPaper(paper);//将该纸张作为格式 */
//打印起点坐标
doublex =pf.getImageableX();
doubley =pf.getImageableY();
switch(pageIndex){
case 0:
//设置打印字体(字体名称、样式和点大小)(字体名称可以是物理或者逻辑名称)
//Java平台所定义的五种字体系列:Serif、SansSerif、Monospaced、Dialog和 DialogInput
Font font = new Font("新宋体", Font.PLAIN, 9);
g2.setFont(font);//设置字体
float[]dash1 = {4.0f};
g2.setStroke(new BasicStroke(0.5f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,4.0f,dash1,0.0f));
floatheigth =font.getSize2D();//字体高度
/*g2.drawString(head, 3*(float)x, (float)y + 1*heigth);
g2.drawString(str, (float)x,(float)y + 2*heigth);
g2.drawString(str01, (float)x,(float)y + 3*heigth+2);
g2.drawString(str02, (float)x,(float)y + 4*heigth+2);
g2.drawString(str03, (float)x,(float)y + 5*heigth+2);
g2.drawString(str033, (float)x,(float)y + 6*heigth+2);
g2.drawString(str04, (float)x,(float)y + 7*heigth+2);
g2.drawString(str05, (float)x, (float)y+ 8*heigth+2);
g2.drawString(str06, (float)x,(float)y + 9*heigth+2);
g2.drawString(str066, (float)x,(float)y + 10*heigth+2);
g2.drawString(str07, (float)x,(float)y + 11*heigth+2);
g2.drawString(str08, (float)x,(float)y + 12*heigth+2);
g2.drawString(str09, (float)x,(float)y + 13*heigth+2);
g2.drawString(str10, (float)x,(float)y + 14*heigth+2);
g2.drawString(str100, (float)x,(float)y + 15*heigth+2);
g2.drawString(str11, (float)x,(float)y + 16*heigth+2);
g2.drawString(str12, (float)x,(float)y + 17*heigth+2);
g2.drawString(str13, (float)x,(float)y + 18*heigth+2);
g2.drawString(str14, (float)x,(float)y + 19*heigth+2);
g2.drawString(str15, (float)x,(float)y + 20*heigth+2);
g2.drawString(str16, (float)x,(float)y + 21*heigth+2);
g2.drawString(str17, (float)x,(float)y + 22*heigth+2);
g2.drawString(str18, (float)x,(float)y + 23*heigth+2);
g2.drawString(str19, (float)x,(float)y + 24*heigth+2);
g2.drawString(str20, (float)x,(float)y + 25*heigth+2);
g2.drawString(str21, (float)x,(float)y + 26*heigth+2);
g2.drawString(str22, (float)x,(float)y + 27*heigth+2);
g2.drawString(str23, (float)x,(float)y + 28*heigth+2);
g2.drawString(str24, (float)x,(float)y + 29*heigth+2);
g2.drawString(str25, (float)x,(float)y + 30*heigth+2);
g2.drawString(str26, (float)x,(float)y + 31*heigth+2);
g2.drawString(str27, (float)x,(float)y + 32*heigth+2);
g2.drawString(str28, (float)x,(float)y + 33*heigth+2);
g2.drawString(str29, (float)x,(float)y + 34*heigth+2);
g2.drawString(str30, (float)x,(float)y + 35*heigth+2);
g2.drawString(str31, (float)x,(float)y + 36*heigth+2);
g2.drawString(str32, (float)x,(float)y + 37*heigth+2);
g2.drawString(str33, (float)x, (float)y+ 39*heigth+2);
g2.drawString(str, (float)x,(float)y + 43*heigth);
g2.drawString(str35, (float)x,(float)y + 44*heigth+2);
g2.drawString(str36, (float)x,(float)y + 45*heigth+2);
g2.drawString(str37, (float)x,(float)y + 46*heigth+2);*/
FontRenderContextfrc =g2.getFontRenderContext();
TextLayout layout = new TextLayout(test,font,frc);
AttributedString text = new AttributedString(test);
text.addAttribute(TextAttribute.FONT,font);
LineBreakMeasurerlineBreaker =new LineBreakMeasurer(text.getIterator(),frc);
doublewidth =pf.getImageableWidth(); //每行字符显示长度(点)
Point2D.Double pen = new Point2D.Double (100,y+3*heigth); //首字符的基线位于用户空间中的 (x, y)位置处
while ( (layout =lineBreaker.nextLayout((float)width)) != null){
layout.draw(g2, (float)x, (float)pen.y);
pen.y +=layout.getAscent();
}
returnPAGE_EXISTS;
default:
returnNO_SUCH_PAGE;
}
}
}
调用时:
//获取打印服务对象方法1
Book book =new Book();
PageFormat pageFormat =new PageFormat(); //设置成竖打
pageFormat.setOrientation(PageFormat.PORTRAIT);
//通过Paper设置页面的空白边距和可打印区域。必须与实际打印纸张大小相符。
Paper pager =new Paper();
pager.setSize(590,840); //纸张大小
//A4(595 X 842)设置打印区域,其实0,0应该是72,72,因为A4纸的默认X,Y边距是72
pager.setImageableArea(72,72, 590, 840);
pageFormat.setPaper(pager);
//把 PageFormat和 Printable添加到书中,组成一个页面
book.append(new printHelp(),pageFormat);
PrinterJob job = PrinterJob.getPrinterJob(); //获取打印服务对象
job.setPageable(book); //设置打印类
try {
//Boolean a = job.printDialog();//显示打印提示窗口
//if(a) {
job.print();
//}
} catch (Exceptione) {
e.printStackTrace();
}
//获取打印服务对象方法2
PrinterJob job = PrinterJob.getPrinterJob();
PageFormat pageFormat =job.defaultPage();//得到默认页格式
job.setPrintable(new printHelp());//设置打印类
try {
//Boolean a = job.printDialog();//显示打印提示窗口
//if(a) {
job.print();
//}
} catch (PrinterExceptione) {
e.printStackTrace();
}
以上方法的弊端催生了关于打印的另一种思路,那就是利用Java操作Word(或其他文件),然后让Word去打印这种曲线救国思路。一开始我真的以为这是个好想法,但是后来我发现确实只是个好的“想法”而已,我可以用Java POI实现对Word内容的读取写入,但是我实现不了通过java让Word自己去触发打印动作(网上资料说java不支持这种方法<纯代码方式实现>,可作者依然坚信这种方法是有大神可以实现的)。
对于该技术研究到此时算是遇到了瓶颈,作者不免在办公室里小发牢骚目的是寻求身边其他码友的帮助,此时王琦(本社iOS码神)帮我找到了网上的一份资源,让我不禁感慨码界里还是神多。不再啰嗦,请看:
2.史上最强大java Word(文件)打印方案
参考文献:(1)《史上最强大Java Word打印方案》------- http://blog.csdn.net/ylz2007/article/details/41172653
publicvoidprintWordFile(Stringfilename){
try{
Runtime.getRuntime().exec("cmd.exe /c start /min winword " +filename+" /q /n /f /mFilePrint/mFileExit");
}catch(Exceptione){
logger.info("打印异常:" +e.getMessage());}}
调用代码:
printWordFile("D:\\Users\\Desktop\\tomcat部署文档-new.docx");
这个的具体解释我就不再多说了,C/S打印中终极中的终极,曲线中的曲线!
小结:
利用com组件进行打印功能的实现由于本人没有亲试过,所以也就不敢造次,还请路过的你亲自研究。
二、B/S
1.最直接,最科普的打印方式:window.print()以及WB.execWB()
用window.print()可以直接打印整个页面的内容,也可以打印指定部分的内容。这个是比较科普的方式,但是,其功能之简陋也是比较科普的。
网页WB.ExecWB控件打印方法:
4,1保存网页
4,2保存网页(可以重新命名)
6,1直接打印
6,2直接打印
7,1打印预览
7,2 打印预览
8,1选择参数
8,2选择参数
10,1查看页面属性
10,2查看页面属性
17,1全选
17,2全选
22,1重新载入当前页
22,2重新载入当前页
<OBJECT classid=CLSID:8856F961-340A-11D0-A96B-00C04FD705A2 height=0 id=WebBrowser width=0></OBJECT>
<input name=Button onClick=document.all.WebBrowser.ExecWB(1,1) type=button value=打开>
<input name=Button onClick=document.all.WebBrowser.ExecWB(2,1) type=button value=关闭所有>
<input name=Button onClick=document.all.WebBrowser.ExecWB(4,1) type=button value=另存为>
<input name=Button onClick=document.all.WebBrowser.ExecWB(6,1) type=button value=打印>
<input name=Button onClick=document.all.WebBrowser.ExecWB(6,6) type=button value=直接打印>
<input name=Button onClick=document.all.WebBrowser.ExecWB(8,1) type=button value=页面设置>
<input name=Button onClick=document.all.WebBrowser.ExecWB(10,1) type=button value=属性>
<input name=Button onClick=document.all.WebBrowser.ExecWB(17,1) type=button value=全选>
<input name=Button onClick=document.all.WebBrowser.ExecWB(22,1) type=button value=刷新>
<input name=Button onClick=document.all.WebBrowser.ExecWB(45,1) type=button value=关闭>
开篇里提到web 打印是“老大难”,这个难度究竟如何?这么说吧,有一个公司为了解决WEB打印的问题,专门组织了一个强大的团队,并得到全国1000多家软件公司的技术支持,经N年呕心沥血,制作出了“露肚皮”,开发团队称:“她是全国1000多家软件公司的智慧结晶,诞生7年了,几乎每个功能细节都蕴藏着无数开发者的期待和汗水”。
2. 作者推荐:WEB开发必选伴侣 ——LODOP
泰安梦泰尔软件有限公司旗下产品,Lodop(标音:劳道谱,俗称:露肚皮)是专业WEB控件,用它既可裁剪输出页面内容,又可用程序代码直接实现复杂打印。控件功能强大,支持页面打印、报表打印、条码打印、图表打印、套打等,简单易用。
<script language="JavaScript"src="<s:url value="/style/script/LodopFuncs.js"/>"></script>
<object id="LODOP_OB" classid="clsid:2105C259-1E0C-4534-8141-A753534CB4CA" width=0 height=0>
<embed id="LODOP_EM"type="application/x-print-lodop" width=0 height=0></embed>
</object>
function prn3_preview(){
LODOP=getLodop();
LODOP.PRINT_INIT("打印控件功能演示_Lodop功能_全页");
LODOP.ADD_PRINT_HTM(0,0,"100%","100%",document.getElementById("print").innerHTML);
LODOP.PREVIEW();
};
几行简单的JS,便实现了复杂的WEB打印。
其具体使用方法以及例子请见LODOP文件夹内的文件。