打印元素绘制协议Java实现
我一直提倡的面向接口和约定编程,而打印元素绘制协议一直是我推荐的打印实现方式,我以前只是强调按打印元素绘制协议输出数据就行了,有实现程序按协议控制打印,说是可以用任何语言实现客户端程序而不影响打印业务,那么这次就用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 managerSSLContext sc = SSLContext.getInstance("SSL");sc.init(null, trustAllCerts, new java.security.SecureRandom());HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());// Create all-trusting host name verifierHostnameVerifier 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*/@Overridepublic 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#丑陋很多,也得忍着把实现了
相关文章:
打印元素绘制协议Java实现
我一直提倡的面向接口和约定编程,而打印元素绘制协议一直是我推荐的打印实现方式,我以前只是强调按打印元素绘制协议输出数据就行了,有实现程序按协议控制打印,说是可以用任何语言实现客户端程序而不影响打印业务,那么…...
js 处理编译器html 包含img的标签并设置width
var imgElements document.getElementsByTagName(img); for (let imgElement of imgElements) { //1.如果有style属性,去掉style属性中的width属性和height属性 if (imgElement.hasAttribute(st…...
同旺科技 分布式数字温度传感器 -- OPC Servers测试
内附链接 1、数字温度传感器 主要特性有: ● 支持PT100 / PT1000 两种铂电阻; ● 支持 2线 / 3线 / 4线 制接线方式; ● 支持5V~17V DC电源供电; ● 支持电源反接保护; ● 支持通讯波特率1200bps、2…...
php获取过去一段的时间范围
在 PHP 中获取过去一周的时间,你可以使用 DateTime 和 DateInterval 类。这里是一个示例代码,展示如何获取从今天起算的过去一周(7天)的日期: // 当前日期 $today new DateTime();// 设置日期为一周前 $oneWeekAgo …...
张三、如花、王婆带你了解Shell命令以及运行原理
文章目录 前言概述张三、王婆、如花的故事Shell命令以及运行原理后记 前言 Linux严格意义上说的是一个操作系统,我们称之为“核心(kernel)“ ,但我们一般用户,不能直接使用kernel。而是通过kernel的“外壳”程序&…...
redis介绍和安装、redis普通连接和连接池、字符串类型、hash类型、列表类型列表类型
文章目录 redis介绍和安装安装步骤启动,连接 redis普通连接和连接池普通连接连接池 redis字符串类型redis hash类型redis列表类型 redis介绍和安装 redis 什么? 数据库就是个存数据的地方:只是不同数据库数据组织,存放形式不一样…...
集成开发环境PyCharm的使用【侯小啾python领航计划系列(三)】
集成开发环境 PyCharm 的使用【侯小啾python领航计划系列(三)】 大家好,我是博主侯小啾, 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ�…...
Flink(九)【时间语义与水位线】
前言 2023-12-02-20:05,终于写完啦,最近状态不错。刚写完又收到了她的消息哈哈哈哈,开心。 再去全力打拼一次,奋战一场,就算最后打了败仗也无所谓,至少你留下了足迹。 《解忧杂货店》 1、时间语义 …...
torch中的随机数种子
如何在torch生成随机数时,设置随机种子,要求每次调用生成的随机数都一样 在 PyTorch 中,可以使用 torch.manual_seed(seed) 函数设置随机种子,以确保每次运行代码时生成的随机数都一样。 以下是一个示例代码,展示了如…...
C 标准库 <math.h>
C 标准库 <math.h> C <math.h>头文件声明了一组函数来执行数学运算,例如:sqrt()计算平方根,log()查找数字的自然对数,等等。 math.h 头文件定义了各种数学函数和一个宏。在这个库中所有可用的函数都带有一个 double…...
一篇带你串通数据结构
文章目录 导论数据结构的定义数据结构在计算机科学中的重要性为什么学习数据结构很重要 1、基本概念1.1、数据、数据元素和数据项的概念1.2、数据对象与数据结构的关系1.3、逻辑结构与物理结构 2、线性结构2.1、数组2.2、链表2.3、栈2.4、队列 3、非线性结构3.1、树3.2、图 4、…...
网络篇---第九篇
系列文章目录 文章目录 系列文章目录前言一、说说TCP/IP四层网络模型二、说说域名解析详细过程?三、 IP 地址分为几类,每类都代表什么,私网是哪些?四、说说TCP 如何保证可靠性的?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家…...
Python基础学习快速入门
文章目录 Number变量String字符串Def函数Class类List列表Tuple元组Dictionary字典Set集合值与引用类型if条件控制Loop循环 Number变量 python直接赋值,不需要定义变量类型。不需要**,逗号结尾符 使用print**直接进行输出 #赋值 a 1.0 print(a)a 7 print(a)p…...
C语言-预处理与库
预处理、动态库、静态库 1. 声明与定义分离 一个源文件对应一个头文件 注意: 头文件名以 .h 作为后缀头文件名要与对应的原文件名 一致 例: 源文件:01_code.c #include <stdio.h> int num01 10; int num02 20; void add(int a, in…...
王道数据结构课后代码题p40 9.给定一个带表头结点的单链表,写出算法 : 按递增次序输出单链表中各结点的数据元素并释放结点 (c语言代码实现)
本题代码如下(有注释) void delete_min(linklist* head) {while ((*head)->next ! NULL)//循环到只剩下头节点{lnode* pre *head;//pre为元素最小结点的前驱结点指针lnode* p (*head)->next;//p为工作指针lnode* q;//指向被删除的结点while (p-…...
对系统的 Go 版本进行升级
方法一 直接升级系统的 Go 版本 注意以下操作仅适用于:amd64 架构的 Centos 系统。如果需要适配其他架构,需要自行编写代码实现。 手动执行: # 显示当前版本 go version # 查看环境变量 cat /etc/profile # 进入 go 的安装目录,…...
【从删库到跑路 | MySQL总结篇】事务详细介绍
个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【MySQL学习专栏】🎈 本专栏旨在分享学习MySQL的一点学习心得,欢迎大家在评论区讨论💌 目录 一、事务…...
七牛云1024创建节-赛后有感
距离比赛结束已经过去快半个月时间,七牛云又发起了有奖征文的活动,正好借此机会记录一下自己参加这次比赛的经历,感受和一些比赛的心得。 如何了解到的比赛信息 其实我很早就开始关注七牛云了,最早是在今年二三月的时候…...
CSS 选择器优先级,!important 也会被覆盖?
目录 1,重要性2,专用性3,源代码顺序 CSS 属性值的计算过程中。其中第2步层叠冲突只是简单说明了下,这篇文章来详细介绍。 层叠冲突更广泛的被称为 CSS选择器优先级计算。 为什么叫层叠冲突,可以理解为 CSS 是 Cascadi…...
关于src别名的配置之tsconfig.json配置
tsconfig.json {"compilerOptions": {"baseUrl": "./", // 解析非相对模块的基地址,默认是当前目录"paths": { //路径映射,相对于baseUrl"/*": ["src/*"] }} } ① "baseUrl": &…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...
蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...
376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
Rust 异步编程
Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...
【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能
1. 开发环境准备 安装DevEco Studio 3.1: 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK 项目配置: // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...
AI语音助手的Python实现
引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...
c# 局部函数 定义、功能与示例
C# 局部函数:定义、功能与示例 1. 定义与功能 局部函数(Local Function)是嵌套在另一个方法内部的私有方法,仅在包含它的方法内可见。 • 作用:封装仅用于当前方法的逻辑,避免污染类作用域,提升…...
