我一直提倡的面向接口和约定编程,而打印元素绘制协议一直是我推荐的打印实现方式,我以前只是强调按打印元素绘制协议输出数据就行了,有实现程序按协议控制打印,说是可以用任何语言实现客户端程序而不影响打印业务,那么这次就用Java实现打印元素绘制协议,来感受一下按协议编程的魅力吧。
打印设计请参照打印设计
首先以前的M都由虚拟M层替代了,这个就是访问地址
然后实现Java调用虚拟M逻辑,客户端通过此逻辑调虚拟M拿到符合打印元素绘制协议的数据
package JRTPrintDraw.WebService;
import javax.net.ssl.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.SAXParserFactory;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import JRTPrintDraw.WebService.Parameters;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
/**
* 请求Webservice得到数据
*/
public class WebGetData {
/**
* 调用虚拟M方法得到数据
*
* @param Address 地址
* @param ClassName 类名
* @param FuncName 方法名
* @param Param 参数
* @param Session 会话
* @return
* @throws Exception
*/
public static String GetData(String Address, String ClassName, String FuncName, Parameters Param, String Session) throws Exception {
System.out.println("ClassName:" + ClassName);
System.out.println("FuncName:" + FuncName);
String result = "";
DealNullPara(Param);
String paraStr = "Method=GetData&ClassName=" + ClassName + "&FuncName=" + FuncName + "&Param=" + URLEncoder.encode(JRTPrintDraw.JsonDealUtil.Object2Json(Param), "UTF-8") + "&Session=" + URLEncoder.encode(Session, "UTF-8");
try {
//返回接受的数据
result = GetHttpStr(Address, paraStr);
//调用报错了
if (!result.contains("<Response>")) {
result = "<Response><SQLResult><SQL><FunRet></FunRet></SQL></SQLResult><RetVal>-1</RetVal><Error>" + result + "</Error><Node></Node><RowCount>0</RowCount></Response>";
}
} catch (Exception ex) {
result += ",异常信息:" + ex.getMessage() + ",调用:" + ClassName + "," + FuncName + "," + Param + "," + Session;
}
return DealXmlToJson(result);
}
/**
* 把xml处理成json串
*
* @param xmlStr
* @return
* @throws Exception
*/
private static String DealXmlToJson(String xmlStr) throws Exception {
System.out.println("返回串:" + xmlStr);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new InputSource(new StringReader(xmlStr)));
// 获得根节点
Element rootElement = document.getDocumentElement();
// 获得根节点下的所有子节点
NodeList childs = rootElement.getChildNodes();
HashMap dataMap = new HashMap();
String ResultName = "";
for (int i = 0; i < childs.getLength(); i++) {
// 由于节点多种类型,而一般我们需要处理的是元素节点
Node childNode = childs.item(i);
// 元素节点就是非空的子节点,也就是还有孩子的子节点
if (childNode.getNodeType() == Node.ELEMENT_NODE) {
Element childElement = (Element) childNode;
dataMap.put(childElement.getNodeName(), childElement.getTextContent());
//不是对象配置元素就忽略
if (childElement.getNodeName().equals("Node")) {
ResultName = childElement.getTextContent() + "Result";
}
}
}
String Error = dataMap.get("Error").toString();
if (!Error.isEmpty()) {
System.out.println("异常:" + Error);
throw new Exception(Error);
}
String ResType = dataMap.get("ResType").toString();
System.out.println("数据串:" + dataMap.get(ResultName).toString());
return dataMap.get(ResultName).toString();
}
/// <summary>
/// 处理空参数
/// </summary>
/// <param name="Param"></param>
private static void DealNullPara(Parameters Param) {
if (Param.P0 == null) {
Param.P0 = "";
}
if (Param.P1 == null) {
Param.P1 = "";
}
if (Param.P2 == null) {
Param.P2 = "";
}
if (Param.P3 == null) {
Param.P3 = "";
}
if (Param.P4 == null) {
Param.P4 = "";
}
if (Param.P5 == null) {
Param.P5 = "";
}
if (Param.P6 == null) {
Param.P6 = "";
}
if (Param.P7 == null) {
Param.P7 = "";
}
if (Param.P8 == null) {
Param.P8 = "";
}
if (Param.P9 == null) {
Param.P9 = "";
}
if (Param.P10 == null) {
Param.P10 = "";
}
if (Param.P11 == null) {
Param.P11 = "";
}
if (Param.P12 == null) {
Param.P12 = "";
}
if (Param.P13 == null) {
Param.P13 = "";
}
if (Param.P14 == null) {
Param.P14 = "";
}
}
/**
* 从http下载文本
*
* @param url url
* @param para 参数
* @return 文本串
* @throws Exception
*/
private static String GetHttpStr(String url, String para) throws Exception {
byte[] bytes = para.getBytes("UTF-8");
//忽略证书
if (url.contains("https://")) {
TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};
// Install the all-trusting trust manager
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// Create all-trusting host name verifier
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
}
URL u = new URL(url);
HttpURLConnection http = (HttpURLConnection) u.openConnection();
http.setAllowUserInteraction(true);
http.setDoOutput(Boolean.TRUE);
http.setDoInput(Boolean.TRUE);
http.setUseCaches(false);
http.setRequestProperty("Content-type", "application/x-www-form-urlencoded");
http.setInstanceFollowRedirects(false);
http.setRequestMethod("POST");
http.connect();
OutputStream outputStream = http.getOutputStream();
outputStream.write(bytes);
outputStream.flush();
outputStream.close();
InputStream is = http.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder stringBuilder = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line + System.lineSeparator());
}
return stringBuilder.toString();
}
}
然后实现打印元素绘制协议,这里把打印和绘图逻辑进行了分离,因为绘图逻辑后面还会给网站的在线打印预览用
按元素类型绘制
绘图与打印结合
package Monitor.Print;
import JRTPrintDraw.DrawConvert;
import JRTPrintDraw.DrawElement;
import JRTPrintDraw.JRTPrintDrawProtocol;
import JRTPrintDraw.JsonDealUtil;
import JRTPrintDraw.WebService.Parameters;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.print.DocFlavor;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.standard.Media;
import javax.print.attribute.standard.MediaSizeName;
import javax.print.attribute.standard.MediaTray;
import java.awt.*;
import java.awt.print.*;
import java.util.ArrayList;
import java.util.List;
public class PrintProtocol implements Printable {
/**
* 纸张名称
*/
private String PageName;
/**
* 打印句柄
*/
private JRTPrintDrawProtocol printHandeler=null;
/**
* 得到打印机
* @param printerName
* @return
*/
public static PrintService GetPrinter(String printerName) {
DocFlavor psInFormat = DocFlavor.INPUT_STREAM.AUTOSENSE;
HashPrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
PrintService printService[] = PrintServiceLookup.lookupPrintServices(psInFormat, pras);
PrintService myPrinter = null;
//遍历所有打印机如果没有选择打印机或找不到该打印机则调用默认打印机
for (PrintService printService2 : printService) {
String svcName = printService2.toString();
if (svcName.contains(printerName)) {
myPrinter = printService2;
break;
}
}
if (myPrinter == null) {
myPrinter = PrintServiceLookup.lookupDefaultPrintService();
return myPrinter;
}
return myPrinter;
}
/**
* 按打印元素绘制协议实现打印
* @param rowids 数据主键
* @param userCode 用户
* @param paramList 参数
* @param connectString 连接串
* @param printFlag 打印标识
* @param className 调用类名
* @param funcName 方法名称
*/
public PrintProtocol(String rowids, String userCode, String paramList, String connectString, String printFlag, String className, String funcName) throws Exception{
try {
Parameters para=new Parameters();
para.P0=rowids;
para.P1=userCode;
para.P2=paramList;
para.P3=rowids;
String json=JRTPrintDraw.WebService.WebGetData.GetData(connectString,className,funcName,para,"");
System.out.println("打印数据:"+json);
List<DrawElement> elementList= JsonDealUtil.Json2List(json,new DrawElement());
System.out.println("转换List");
// 通俗理解就是书、文档
Book book = new Book();
printHandeler=new JRTPrintDrawProtocol();
int pageNum=printHandeler.JRTPrintDrawInit(elementList);
System.out.println("页数:"+pageNum);
// 获取打印服务对象
PrinterJob job = PrinterJob.getPrinterJob();
// 设置打印类
job.setPageable(book);
//设置成竖打
PageFormat pf = new PageFormat();
pf.setOrientation(PageFormat.PORTRAIT);
boolean hasSetPaper=false;
//控制打印机的数据
if(elementList.get(0).PrintType.contains("PRINTER"))
{
DrawElement dr=elementList.get(0);
//打印机名称
String tPrinterName = elementList.get(0).PrintFlag;
//选择打印机
if(tPrinterName!=null&&!tPrinterName.isEmpty())
{
PrintService printService=GetPrinter(tPrinterName);
job.setPrintService(printService);
}
//设置打印机其他参数
if(dr.PrintType.equals("PRINTER"))
{
//设置打印机宽度
int PrinterWidth = DrawConvert.ToInt32(dr.PrintWidth);
//设置打印机高度
int PrinterHeight = DrawConvert.ToInt32(dr.PrintHeight);
printHandeler.WriteLog("PRINTER得到纸张宽高:" + PrinterWidth + " " + PrinterHeight);
//页面名称
PageName = dr.DataField;
//停靠
String ReportLayout = dr.PrintAlignment;
printHandeler.WriteLog("PRINTER得打印机名称:" + tPrinterName);
//指定打印机送纸来源
int iPaperSource = DrawConvert.ToInt32(dr.PrintFont);
if (ReportLayout == "Landscape")
{
pf.setOrientation(PageFormat.LANDSCAPE);
printHandeler.WriteLog("PRINTER旋转纸张:Landscape");
}
//宽高大于0就控制
if(PrinterWidth>0&&PrinterHeight>0)
{
//通过Paper设置页面的空白边距和可打印区域。必须与实际打印纸张大小相符。
Paper paper = new Paper();
// 设置纸张大小为 A4 大小(210 mm × 297 mm)
int width = PrinterWidth;
int height = PrinterHeight;
//旋转
if (ReportLayout == "Landscape") {
int tmp=width;
width=height;
height=tmp;
}
double margin = 0;
paper.setSize(width, height);
paper.setImageableArea(margin, margin, width - 2 * margin, height - 2 * margin);
pf.setPaper(paper);
hasSetPaper=true;
}
}
}
if(hasSetPaper==false)
{
Paper paper = new Paper();
// 设置纸张大小为 A4 大小(210 mm × 297 mm)
int width = 794;
int height = 1123;
double margin = 0;
paper.setSize(width, height);
paper.setImageableArea(margin, margin, width - 2 * margin, height - 2 * margin);
pf.setPaper(paper);
}
book.append(this, pf,pageNum);
if(printFlag.contains("PrintPreview"))
{
System.out.println("打印设置");
job.print();
}
else
{
System.out.println("打印");
job.print();
}
}
catch (PrinterException e) {
e.printStackTrace();
}
}
/**
* 画图
* @param graphics
* @param pageFormat
* @param pageIndex
* @return
* @throws PrinterException
*/
@Override
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
// 转换成Graphics2D 拿到画笔
Graphics2D g2 = (Graphics2D) graphics;
if(printHandeler!=null)
{
try {
int drawOneRet=printHandeler.DrawOnePage(g2, pageIndex);
System.out.println(pageIndex+":"+drawOneRet);
return drawOneRet;
}
catch (Exception ex)
{
if(ex.getCause()!=null)
{
printHandeler.WriteLog(ex.getCause().getMessage());
}
else
{
printHandeler.WriteLog(ex.getMessage());
}
ex.printStackTrace();
return 1;
}
}
return 1;
}
}
这样就实现了Java的打印层,只要按打印元素绘制协议打印的业务不需要改就能话环境执行了
C#的效果
Java的效果
打磨好之后再把导出Excel实现了就基本实现JRT的最终目标了,导出一样的实现的有导出协议,我一般不直接写死业务,到时候开发换Linux都没毛病了,实现可以用任何语言都行,为啥打印也有Java呢,因为成本,不可能客户端程序再用一套编程语言实现,增加维护和开发成本,虽然写的比C#丑陋很多,也得忍着把实现了