基于Win服务的标签打印(模板套打)

最近做了几个项目,都有在产品贴标的需求

基本就是有个证卡类打印机,然后把产品的信息打印在标签上。

然后通过机器人把标签贴到产品上面

标签信息包括文本,二维码,条形码之类的,要根据对应的数据生成二维码,条形码。

打印标签的需求接到手后,开始了我的填坑之旅。

打印3.0源代码:https://github.com/zeqp/ZEQP.Print

打印1.0

第一个项目开始,因为原来没有研究过打印,所以在Bing上查了一下.Net打印机关的资料

发现基本上都是基于.net的
System.Drawing.Printing.PrintDocument
这个类来做自定义打印

大家都用这个做打印,我想按理也没有问题。

所以开始了我的代码。

PrintDocument去做打印,无非就是设置好打印机名称,
DefaultPageSettings.PrinterSettings.PrinterName
打印份数
DefaultPageSettings.PrinterSettings.Copies
纸张方向
DefaultPageSettings.Landscape
然后打印的具体的信息就是事件PrintPage写进去
然后调用
Graphics.DrawString,Graphics.DrawImage来写入具体的文本与图片
Graphics.Draw的时候要指定字体,颜色,位置等数据
我把这些做成配置数据。
然后1.0版本就成了。

下图为位置的配置文件

代码一写完,用VS调试的时候。跑得飞起。、

所有的字体,要打印数据的位置也通过配置文件可以动态的调整。感觉还算完美。
但是现实很骨感,马上就拍拍打脸了

PrintDocument类只能以WinForm的方式运行,不能以服务的方式运行。
具体可以参考:https://docs.microsoft.com/zh-cn/dotnet/api/system.drawing.printing?redirectedfrom=MSDN&view=netframework-4.8

幸好客户方面没有什么要求,而且生产的时候会有一台专门的上位机可以做这个事,所以做了一个无界面的WinForm。在电脑启动的时候运行

从而解决了不能以服务的方式运行的问题。

打印2.0

做完打印1.0后,又接到了一个项目。又是有打印相关的功能,自然又分配到我这里来了。

但是对于上一个版本的打印。不能做为服务运行,做为自己写的一个程序,居然有这么大的瑕疵。总感觉心里不爽

想去解决这个问题,但是在Bing上找到.Net的所有打印都是这样做的。也找不到什么更好的方法。

只到问了很多相关的相关人士。最后给了我一个第三方的商业解决方案BarTender
相关参考:https://www.bartendersoftware.com/
这个有自己的模板编辑器,

有自己的SDK,有编辑器,功能也非学强大。不愧是商业打印解决方案。

根据他的SDK,同时安装了相关程序,写下几句打印代码。一个基于Win服务的打印出来了

于是。打印2.0出来了。

打印3.0
但是对于一个基于第三方的商业打印方案,所有功能都是很强大。实现也简单。

就是对于一般公司的小项目。挣的钱还不够买这个商业套件的License

而且对于一个只会使用别人家的SDK的程序。不是一个有灵魂的程序。

因为你都不知道人家背后是怎么实现的。原理是什么都不知道。

对于我,虽然能把这个项目用BarTender完成。但是总是对这个打印方案不是很满意。

因为我只在这个上面加了一层壳。不知道后面做了什么。

所以我一直想自己开发一个可以基于Win服务运行的打印程序。最好也要有自己的模板编辑器。

只到有一天。无意找到一篇文章

https://docs.aspose.com/display/wordsnet/Print+a+Document

他这里也解释了有关基于服务的打印有关的问题不能解决。

并且他们已经找到了对应的解决方案。基于他的解决方案。写了对应一个打印帮助类。

这个是基于Windows的XPS文档API打印。

XPS是在Win 7后就是windows支持的打印文档类型 类比PDF

基本 XpsPrint API   的相关说明

同时基本他的XPS打印帮助类。我做了测试。可以完美的在Windows服务里面运行关打印。

  1 namespace ZEQP.Print.Framework
  2 {
  3     /// <summary>
  4     /// A utility class that converts a document to XPS using Aspose.Words and then sends to the XpsPrint API.
  5     /// </summary>
  6     public class XpsPrintHelper
  7     {
  8         /// <summary>
  9         /// No ctor.
 10         /// </summary>
 11         private XpsPrintHelper()
 12         {
 13         }
 14
 15         // ExStart:XpsPrint_PrintDocument
 16         // ExSummary:Convert an Aspose.Words document into an XPS stream and print.
 17         /// <summary>
 18         /// Sends an Aspose.Words document to a printer using the XpsPrint API.
 19         /// </summary>
 20         /// <param name="document"></param>
 21         /// <param name="printerName"></param>
 22         /// <param name="jobName">Job name. Can be null.</param>
 23         /// <param name="isWait">True to wait for the job to complete. False to return immediately after submitting the job.</param>
 24         /// <exception cref="Exception">Thrown if any error occurs.</exception>
 25         public static void Print(string xpsFile, string printerName, string jobName, bool isWait)
 26         {
 27             Console.WriteLine("Print");
 28             if (!File.Exists(xpsFile))
 29                 throw new ArgumentNullException("xpsFile");
 30             using (var stream = File.OpenRead(xpsFile))
 31             {
 32                 Print(stream, printerName, jobName, isWait);
 33             }
 34             //// Use Aspose.Words to convert the document to XPS and store in a memory stream.
 35             //File.OpenRead
 36             //MemoryStream stream = new MemoryStream();
 37
 38             //stream.Position = 0;
 39             //Console.WriteLine("Saved as Xps");
 40             //Print(stream, printerName, jobName, isWait);
 41             Console.WriteLine("After Print");
 42         }
 43         // ExEnd:XpsPrint_PrintDocument
 44         // ExStart:XpsPrint_PrintStream
 45         // ExSummary:Prints an XPS document using the XpsPrint API.
 46         /// <summary>
 47         /// Sends a stream that contains a document in the XPS format to a printer using the XpsPrint API.
 48         /// Has no dependency on Aspose.Words, can be used in any project.
 49         /// </summary>
 50         /// <param name="stream"></param>
 51         /// <param name="printerName"></param>
 52         /// <param name="jobName">Job name. Can be null.</param>
 53         /// <param name="isWait">True to wait for the job to complete. False to return immediately after submitting the job.</param>
 54         /// <exception cref="Exception">Thrown if any error occurs.</exception>
 55         public static void Print(Stream stream, string printerName, string jobName, bool isWait)
 56         {
 57             if (stream == null)
 58                 throw new ArgumentNullException("stream");
 59             if (printerName == null)
 60                 throw new ArgumentNullException("printerName");
 61
 62             // Create an event that we will wait on until the job is complete.
 63             IntPtr completionEvent = CreateEvent(IntPtr.Zero, true, false, null);
 64             if (completionEvent == IntPtr.Zero)
 65                 throw new Win32Exception();
 66
 67             //            try
 68             //            {
 69             IXpsPrintJob job;
 70             IXpsPrintJobStream jobStream;
 71             Console.WriteLine("StartJob");
 72             StartJob(printerName, jobName, completionEvent, out job, out jobStream);
 73             Console.WriteLine("Done StartJob");
 74             Console.WriteLine("Start CopyJob");
 75             CopyJob(stream, job, jobStream);
 76             Console.WriteLine("End CopyJob");
 77
 78             Console.WriteLine("Start Wait");
 79             if (isWait)
 80             {
 81                 WaitForJob(completionEvent);
 82                 CheckJobStatus(job);
 83             }
 84             Console.WriteLine("End Wait");
 85             /*            }
 86                         finally
 87                         {
 88                             if (completionEvent != IntPtr.Zero)
 89                                 CloseHandle(completionEvent);
 90                         }
 91             */
 92             if (completionEvent != IntPtr.Zero)
 93                 CloseHandle(completionEvent);
 94             Console.WriteLine("Close Handle");
 95         }
 96         // ExEnd:XpsPrint_PrintStream
 97
 98         private static void StartJob(string printerName, string jobName, IntPtr completionEvent, out IXpsPrintJob job, out IXpsPrintJobStream jobStream)
 99         {
100             int result = StartXpsPrintJob(printerName, jobName, null, IntPtr.Zero, completionEvent,
101                 null, 0, out job, out jobStream, IntPtr.Zero);
102             if (result != 0)
103                 throw new Win32Exception(result);
104         }
105
106         private static void CopyJob(Stream stream, IXpsPrintJob job, IXpsPrintJobStream jobStream)
107         {
108
109             //            try
110             //            {
111             byte[] buff = new byte[4096];
112             while (true)
113             {
114                 uint read = (uint)stream.Read(buff, 0, buff.Length);
115                 if (read == 0)
116                     break;
117
118                 uint written;
119                 jobStream.Write(buff, read, out written);
120
121                 if (read != written)
122                     throw new Exception("Failed to copy data to the print job stream.");
123             }
124
125             // Indicate that the entire document has been copied.
126             jobStream.Close();
127             //            }
128             //            catch (Exception)
129             //            {
130             //                // Cancel the job if we had any trouble submitting it.
131             //                job.Cancel();
132             //                throw;
133             //            }
134         }
135
136         private static void WaitForJob(IntPtr completionEvent)
137         {
138             const int INFINITE = -1;
139             switch (WaitForSingleObject(completionEvent, INFINITE))
140             {
141                 case WAIT_RESULT.WAIT_OBJECT_0:
142                     // Expected result, do nothing.
143                     break;
144                 case WAIT_RESULT.WAIT_FAILED:
145                     throw new Win32Exception();
146                 default:
147                     throw new Exception("Unexpected result when waiting for the print job.");
148             }
149         }
150
151         private static void CheckJobStatus(IXpsPrintJob job)
152         {
153             XPS_JOB_STATUS jobStatus;
154             job.GetJobStatus(out jobStatus);
155             switch (jobStatus.completion)
156             {
157                 case XPS_JOB_COMPLETION.XPS_JOB_COMPLETED:
158                     // Expected result, do nothing.
159                     break;
160                 case XPS_JOB_COMPLETION.XPS_JOB_FAILED:
161                     throw new Win32Exception(jobStatus.jobStatus);
162                 default:
163                     throw new Exception("Unexpected print job status.");
164             }
165         }
166
167         [DllImport("XpsPrint.dll", EntryPoint = "StartXpsPrintJob")]
168         private static extern int StartXpsPrintJob(
169             [MarshalAs(UnmanagedType.LPWStr)] String printerName,
170             [MarshalAs(UnmanagedType.LPWStr)] String jobName,
171             [MarshalAs(UnmanagedType.LPWStr)] String outputFileName,
172             IntPtr progressEvent,   // HANDLE
173             IntPtr completionEvent, // HANDLE
174             [MarshalAs(UnmanagedType.LPArray)] byte[] printablePagesOn,
175             UInt32 printablePagesOnCount,
176             out IXpsPrintJob xpsPrintJob,
177             out IXpsPrintJobStream documentStream,
178             IntPtr printTicketStream);  // This is actually "out IXpsPrintJobStream", but we don‘t use it and just want to pass null, hence IntPtr.
179
180         [DllImport("Kernel32.dll", SetLastError = true)]
181         private static extern IntPtr CreateEvent(IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, string lpName);
182
183         [DllImport("Kernel32.dll", SetLastError = true, ExactSpelling = true)]
184         private static extern WAIT_RESULT WaitForSingleObject(IntPtr handle, Int32 milliseconds);
185
186         [DllImport("Kernel32.dll", SetLastError = true)]
187         [return: MarshalAs(UnmanagedType.Bool)]
188         private static extern bool CloseHandle(IntPtr hObject);
189     }
190
191     /// <summary>
192     /// This interface definition is HACKED.
193     ///
194     /// It appears that the IID for IXpsPrintJobStream specified in XpsPrint.h as
195     /// MIDL_INTERFACE("7a77dc5f-45d6-4dff-9307-d8cb846347ca") is not correct and the RCW cannot return it.
196     /// But the returned object returns the parent ISequentialStream inteface successfully.
197     ///
198     /// So the hack is that we obtain the ISequentialStream interface but work with it as
199     /// with the IXpsPrintJobStream interface.
200     /// </summary>
201     [Guid("0C733A30-2A1C-11CE-ADE5-00AA0044773D")]  // This is IID of ISequenatialSteam.
202     [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
203     interface IXpsPrintJobStream
204     {
205         // ISequentualStream methods.
206         void Read([MarshalAs(UnmanagedType.LPArray)] byte[] pv, uint cb, out uint pcbRead);
207         void Write([MarshalAs(UnmanagedType.LPArray)] byte[] pv, uint cb, out uint pcbWritten);
208         // IXpsPrintJobStream methods.
209         void Close();
210     }
211
212     [Guid("5ab89b06-8194-425f-ab3b-d7a96e350161")]
213     [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
214     interface IXpsPrintJob
215     {
216         void Cancel();
217         void GetJobStatus(out XPS_JOB_STATUS jobStatus);
218     }
219
220     [StructLayout(LayoutKind.Sequential)]
221     struct XPS_JOB_STATUS
222     {
223         public UInt32 jobId;
224         public Int32 currentDocument;
225         public Int32 currentPage;
226         public Int32 currentPageTotal;
227         public XPS_JOB_COMPLETION completion;
228         public Int32 jobStatus; // UInt32
229     };
230
231     enum XPS_JOB_COMPLETION
232     {
233         XPS_JOB_IN_PROGRESS = 0,
234         XPS_JOB_COMPLETED = 1,
235         XPS_JOB_CANCELLED = 2,
236         XPS_JOB_FAILED = 3
237     }
238
239     enum WAIT_RESULT
240     {
241         WAIT_OBJECT_0 = 0,
242         WAIT_ABANDONED = 0x80,
243         WAIT_TIMEOUT = 0x102,
244         WAIT_FAILED = -1 // 0xFFFFFFFF
245     }
246 }

XpsPrintHelper

到此,基于windows服务的打印已经解决。

就只有模板编辑器的事情了。

对于原来做过基于Word的邮件合并域的经验。自己开发一个编辑器来说工程量有点大

所以选择了一个现有的,功能又强大的文档编辑器。Word来做为我的标签编辑器了。

Word可以完美的解决纸张,格式,位置等问题。只是在对应的地方用“文本域”来做占位符

然后用自定义的数据填充就可以了。

下图为Word模板编辑

编辑占位符(域)

这样的话。一个模板就出来了

如果是图片的话。就在域名前加Image:

如果是表格的话。在表格的开始加上TableStart:表名
在表格的未尾加上TableEnd:表名

协议的话。走的是所有语言都支持的http,对于以后开发SDK也方便

对于上面的模板,只要发送这样的请球POST

对于Get请求

然后打印出来的效果

到此,打印3.0已经完成。

关键代码
根据请求数据生成打印实体

 1 private PrintModel GetPrintModel(HttpListenerRequest request)
 2         {
 3             var result = new PrintModel();
 4             result.PrintName = ConfigurationManager.AppSettings["PrintName"];
 5             result.Template = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Template", "Default.docx");
 6             result.Action = PrintActionType.Print;
 7
 8             var query = request.Url.Query;
 9             var dicQuery = this.ToNameValueDictionary(query);
10             if (dicQuery.ContainsKey("PrintName")) result.PrintName = dicQuery["PrintName"];
11             if (dicQuery.ContainsKey("Copies")) result.Copies = int.Parse(dicQuery["Copies"]);
12             if (dicQuery.ContainsKey("Template"))
13             {
14                 var tempPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Template", dicQuery["Template"]);
15                 if (File.Exists(tempPath))
16                     result.Template = tempPath;
17             }
18             if (dicQuery.ContainsKey("Action")) result.Action = (PrintActionType)Enum.Parse(typeof(PrintActionType), dicQuery["Action"]);
19
20             foreach (var item in dicQuery)
21             {
22                 if (item.Key.StartsWith("Image:"))
23                 {
24                     var keyName = item.Key.Replace("Image:", "");
25                     if (result.ImageContent.ContainsKey(keyName)) continue;
26                     var imageModel = item.Value.ToObject<ImageContentModel>();
27                     result.ImageContent.Add(keyName, imageModel);
28                     continue;
29                 }
30                 if (item.Key.StartsWith("Table:"))
31                 {
32                     var keyName = item.Key.Replace("Table:", "");
33                     if (result.TableContent.ContainsKey(keyName)) continue;
34                     var table = item.Value.ToObject<DataTable>();
35                     table.TableName = keyName;
36                     result.TableContent.Add(keyName, table);
37                     continue;
38                 }
39                 if (result.FieldCotent.ContainsKey(item.Key)) continue;
40                 result.FieldCotent.Add(item.Key, item.Value);
41             }
42
43             if (request.HttpMethod.Equals("POST", StringComparison.CurrentCultureIgnoreCase))
44             {
45                 var body = request.InputStream;
46                 var encoding = Encoding.UTF8;
47                 var reader = new StreamReader(body, encoding);
48                 var bodyContent = reader.ReadToEnd();
49                 var bodyModel = bodyContent.ToObject<Dictionary<string, object>>();
50                 foreach (var item in bodyModel)
51                 {
52                     if (item.Key.StartsWith("Image:"))
53                     {
54                         var imageModel = item.Value.ToJson().ToObject<ImageContentModel>();
55                         var keyName = item.Key.Replace("Image:", "");
56                         if (result.ImageContent.ContainsKey(keyName))
57                             result.ImageContent[keyName] = imageModel;
58                         else
59                             result.ImageContent.Add(keyName, imageModel);
60                         continue;
61                     }
62                     if (item.Key.StartsWith("Table:"))
63                     {
64                         var table = item.Value.ToJson().ToObject<DataTable>();
65                         var keyName = item.Key.Replace("Table:", "");
66                         table.TableName = keyName;
67                         if (result.TableContent.ContainsKey(keyName))
68                             result.TableContent[keyName] = table;
69                         else
70                             result.TableContent.Add(keyName, table);
71                         continue;
72                     }
73                     if (result.FieldCotent.ContainsKey(item.Key))
74                         result.FieldCotent[item.Key] = HttpUtility.UrlDecode(item.Value.ToString());
75                     else
76                         result.FieldCotent.Add(item.Key, HttpUtility.UrlDecode(item.Value.ToString()));
77                 }
78             }
79             return result;
80         }

GetPrintModel

文档邮件合并域

  1 public class MergeDocument : IDisposable
  2     {
  3         public PrintModel Model { get; set; }
  4         public Document Doc { get; set; }
  5         private PrintFieldMergingCallback FieldCallback { get; set; }
  6         public MergeDocument(PrintModel model)
  7         {
  8             this.Model = model;
  9             this.Doc = new Document(model.Template);
 10             this.FieldCallback = new PrintFieldMergingCallback(this.Model);
 11             this.Doc.MailMerge.FieldMergingCallback = this.FieldCallback;
 12         }
 13         public Stream MergeToStream()
 14         {
 15             if (this.Model.FieldCotent.Count > 0)
 16                 this.Doc.MailMerge.Execute(this.Model.FieldCotent.Keys.ToArray(), this.Model.FieldCotent.Values.ToArray());
 17             if (this.Model.ImageContent.Count > 0)
 18             {
 19                 this.Doc.MailMerge.Execute(this.Model.ImageContent.Keys.ToArray(), this.Model.ImageContent.Values.Select(s => s.Value).ToArray());
 20             };
 21             if (this.Model.TableContent.Count > 0)
 22             {
 23                 foreach (var item in this.Model.TableContent)
 24                 {
 25                     var table = item.Value;
 26                     table.TableName = item.Key;
 27                     this.Doc.MailMerge.ExecuteWithRegions(table);
 28                 }
 29             }
 30             this.Doc.UpdateFields();
 31
 32             var fileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "PrintDoc", $"{DateTime.Now.ToString("yyMMddHHmmssfff")}.docx");
 33             var ms = new MemoryStream();
 34             this.Doc.Save(ms, SaveFormat.Xps);
 35             return ms;
 36         }
 37
 38         public void Dispose()
 39         {
 40             this.FieldCallback.Dispose();
 41         }
 42
 43         private class PrintFieldMergingCallback : IFieldMergingCallback, IDisposable
 44         {
 45             public HttpClient Client { get; set; }
 46             public PrintModel Model { get; set; }
 47             public PrintFieldMergingCallback(PrintModel model)
 48             {
 49                 this.Model = model;
 50                 this.Client = new HttpClient();
 51             }
 52             public void FieldMerging(FieldMergingArgs args)
 53             {
 54             }
 55
 56             public void ImageFieldMerging(ImageFieldMergingArgs field)
 57             {
 58                 var fieldName = field.FieldName;
 59                 if (!this.Model.ImageContent.ContainsKey(fieldName)) return;
 60                 var imageModel = this.Model.ImageContent[fieldName];
 61                 switch (imageModel.Type)
 62                 {
 63                     case ImageType.Local:
 64                         {
 65                             field.Image = Image.FromFile(imageModel.Value);
 66                             field.ImageWidth = new MergeFieldImageDimension(imageModel.Width);
 67                             field.ImageHeight = new MergeFieldImageDimension(imageModel.Height);
 68                         };
 69                         break;
 70                     case ImageType.Network:
 71                         {
 72                             var imageStream = this.Client.GetStreamAsync(imageModel.Value).Result;
 73                             var ms = new MemoryStream();
 74                             imageStream.CopyTo(ms);
 75                             ms.Position = 0;
 76                             field.ImageStream = ms;
 77                             field.ImageWidth = new MergeFieldImageDimension(imageModel.Width);
 78                             field.ImageHeight = new MergeFieldImageDimension(imageModel.Height);
 79                         }; break;
 80                     case ImageType.BarCode:
 81                         {
 82                             var barImage = this.GenerateImage(BarcodeFormat.CODE_128, imageModel.Value, imageModel.Width, imageModel.Height);
 83                             field.Image = barImage;
 84                         }; break;
 85                     case ImageType.QRCode:
 86                         {
 87                             var qrImage = this.GenerateImage(BarcodeFormat.QR_CODE, imageModel.Value, imageModel.Width, imageModel.Height);
 88                             field.Image = qrImage;
 89                         }; break;
 90                     default: break;
 91                 }
 92             }
 93             private Bitmap GenerateImage(BarcodeFormat format, string code, int width, int height)
 94             {
 95                 var writer = new BarcodeWriter();
 96                 writer.Format = format;
 97                 EncodingOptions options = new EncodingOptions()
 98                 {
 99                     Width = width,
100                     Height = height,
101                     Margin = 2,
102                     PureBarcode = false
103                 };
104                 writer.Options = options;
105                 if (format == BarcodeFormat.QR_CODE)
106                 {
107                     var qrOption = new QrCodeEncodingOptions()
108                     {
109                         DisableECI = true,
110                         CharacterSet = "UTF-8",
111                         Width = width,
112                         Height = height,
113                         Margin = 2
114                     };
115                     writer.Options = qrOption;
116                 }
117                 var codeimg = writer.Write(code);
118                 return codeimg;
119             }
120
121             public void Dispose()
122             {
123                 this.Client.Dispose();
124             }
125         }
126     }

MergeDocument

 

原文地址:https://www.cnblogs.com/liuju150/p/Service_Print_Template_Solution.html

时间: 2024-11-11 15:19:31

基于Win服务的标签打印(模板套打)的相关文章

重复造轮子系列——基于FastReport设计打印模板实现桌面端WPF套打和商超POS高度自适应小票打印

重复造轮子系列——基于FastReport设计打印模板实现桌面端WPF套打和商超POS高度自适应小票打印 一.引言 桌面端系统经常需要对接各种硬件设备,比如扫描器.读卡器.打印机等. 这里介绍下桌面端系统打印经常使用的场景. 1.一种是类似票务方面的系统需要打印固定格式的票据.比如景点门票.车票.电影票. 这种基本是根据模板调整位置套打. 2.还有一种是交易小票,比如商超POS小票,打印长度会随着内容的大小自动伸缩. 这种就不仅仅是固定格式的套打了,还得计算数据行以适应不同的打印长度. 打印方式

吉特仓储管系统(开源WMS)--Web在线报表以及打印模板分享

很早之前就想写这篇文章与大家分享一下自己在吉特仓储管理系统中开发打印和报表的功能,在GitHub(https://github.com/hechenqingyuan/gitwms)上公开下载的代码中很多人觉得在线设计报表这个功能比较不错,但是很多人也会有疑问.这边文章就简单讲解一下如何开发这个功能的,供大家学习参考,如果有任何疑问可以直接联系我,当然也有很多不足之处希望大家多多谅解和指点. 一. 各种需求报表以及打印 最开始之初在Web上做打印是每个打印也都会做一个页面,利用的是浏览器自身带的打

可视化、高智能、多功能、XML配置型工业条码打印、标签打印解决方案

前言 现代工业生产中,标签打印无处不在,可以说标签就是产品的脸面.标签种类繁琐,特别是在工业生产中,标签信息需要与生产系统相关联,动态地获取打印信息.当然我们可以为每个标签写一个生成程序,但如果标签种类成千上万,那么就需要投入大量的人力.物力.比如一个很小的布局变动也去修改程序代码,显然是不明智的.如何构建一个可视化.高智能.多功能的工业条码打印解决框架,正是我们迫切需要解决的难题. 可视化.高智能.多功能.XML配置型工业条码打印解决方案应运而生,旨在解决上述难题.下面简要的给出部分截图,有兴

基于Rest服务实现的RPC

前言:现在RPC成熟的框架已经很多了,比喻Motan和Dubbo,但是今天我这里提供一种基于Rest服务的Rpc.和上一篇连着的http://www.cnblogs.com/LipeiNet/p/5856414.html 1:原理 首先我们要建立一个Rest服务,如果其他应用程序想要获取这个服务的资源就只需要一个URI就可以了.但是由于内部程序的调用我们在通过URI获取json然后在自己处理很不方便,也不是很合适,那么我们就需要利用一个中间层,把访问Rest服务返回的资源重新包装,然后其他工程只

如何利用标签打印软件制作商品标签?

标签是我们日常生活中随处可见的东西,购买珠宝首饰给的小票里面订的有珠宝标签,购物超市里有商品计价标签,买衣服时的吊牌标签及合格证等,商品标签各式各样,到底是怎么制作的呢?今天就来以日常所用的笔记本标签为例,来介绍一下怎么利用领跑标签打印软件制作商品标签. 如下图所示,即为我们要设计的商品标签: 首先,要测量该笔记本标签的规格大小,也就是长和宽.测量完成后在领跑标签打印软件上新建标签,在"纸张"选项中设置"自定义大小",设置纸张宽度和高度,然后在"布局&qu

基于微服务的软件架构模式(转载)

转载:原文链接 基于微服务的软件架构模式 [编者的话]微服务只是最近提出的概念,实际上很多巨头公司(FB.Twitter.AWS等)已经在亲身实践.微服务并不是银弹,但是我们可以参考它的 思想来解决自己遇到的问题.对于已经找准市场,业务即将或者马上就要急剧发展的创业公司,适合使用基于微服务的软件架构. 今天阅读了两篇关于微服务的文章,总结一些笔记,简单翻译了一篇文章.说明:并没有严格按照原文一字语句翻译,有部分自己的理解,还有部分是意译. 微服务(micro services)这个概念不是新概念

[zz] 基于国家标准的 EndNote 输出样式模板

基于国家标准的 EndNote 输出样式模板 https://cnzhx.net/blog/endnote-output-style-cnzhx/ 发表于 2013-05-26 作者 Haoxian Zeng 更新于 2015-01-13 47 EndNote 相当于一个数据库,将添加/导入的文献存档.需要引用文献的时候就从中选择一个插入到文档中,EndNote 会自动给你编号.在文档末尾建立相应的参考文献列表.但是各种杂志.单位要求的文献著录格式是不一样的,所以在插入文献到文档之前,我们应该选

如何解决升级WIN服务的时候,不暴力停止服务 达到升级的目的

同一个WIN服务,分别部署在A.B两台服务器上,前面使用netscaler负载均衡 ,A和B被请求频繁,几乎时时刻刻都被请求   .PS:发布WIN服务的正常流程是,停止WIN服务->发布WIN服务程序->启动WIN服务        问:升级WIN服务的时候,如何保证正常请求不被中断 利用负载均衡机制,轮流升级服务器 N'S切所有的请求到B,A不停机,可以响应请求,但不接受请求.等A没有请求也没有响应请求线程的时候,对A执行发布

【C#】win服务 定时器

win服务: using System.ServiceProcess; 继承 ServiceBase 即可 定时器: private System.Timers.Timer PushOrderTimer; 绑定事件Elapsed    private void PushOrderTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)