吉特日化MES系统--通过浏览器调用标签打印
三年来做制造行业,差不多做了近30个工厂,也由纯软件转入到了大量的硬件对接,包含厂房设计(这个目前还只是小菜鸟),硬件设计(只是提提意见),安装实施调试(软件和硬件撕逼操作),当然面向的对象也由计算机转向了和各种人员的对接,一直想做一个牛逼的技术人员,可是天不如人愿只能游走于各种琐事中,也很少写技术相关的文章了,今天分享一个小小的应用点《打印标签》
一 标签打印
在制造行业中,在仓库物流行业中标签打印是非常常用的需求,标签除了标识物体之外,我们还有一个比较重要的应用 就是在标签上附上 条码 或 二维码, 特别是二维码目前在我们生活中无处不在。 而标签中使用 条码或二维码,其实就是为了加快物体的识别效率。 当然市面上有很多打印的标签软件,各个打印机厂商也都有自带打印软件,而打印机厂商自带的软件大部分都是CS结构的程序,而且无法和BS网页交互。、
以上标签在生产制造行业中比较常见,除了以上在原料,生产过程中使用,还有成品仓库包装,物流发货等,当然还有一些特殊的情况比如 包装外箱等使用喷码机来喷码的情况,这种并不是使用打印来打印的。标签的应用很多,但是有一点不同的就是标签纸张规格大小的不一样,以及经常变动的表现形式。
二 为什么不使用浏览器打印
浏览器也是带有打印功能的,一般比较常用使用浏览器打印都是打印A4,A5 等这种比较规整的纸张,当然浏览器也能够打印各种小标签。但是浏览器打印有一个不好的就是清晰度不够,至于为什么清晰度不够这个我也说不清楚,然后在连续打印等方面都比较弱,可能很多人会问我们也经常见到连续打印的,一般这种打印都是使用浏览器插件或者和打印客户端相连接的,这也是在《吉特日化MES系统》中应用的方式。
另外目前市面上见到的浏览器打印客户端大部分都是收费的,虽然很多费用还不低,另外就是绑架销售,比如很多打印都是集成在报表组件里面的,目前的报表组件随随便便一个授权就是几十万,这也是客户无法接受的,我们自己做项目也无法接受。
三 自己开发的打印组件
其实算不上自己开发的打印组件,只是基于.NET 的documentprint 打印类做了一定的封装,在之间的文字中有分享过。具体可以看看如下文章
当然也还有一些其他的打印案例的分享,有兴趣的可以翻阅一下以前的文章。
关于自己的打印组件源代码如下: https://github.com/hechenqingyuan/gitprint
四 用网页打印怎么办
上位系统的开发使用BS架构,这也就必然遇到了打印头疼的地方,如何打印标签。其实思路很简单,那就是网页出发打印指令,然后发送到客户单软件来打印,这是我这边的一个基本思路。
如图是一个打印标签的操作界面,就目前而言操作还是相对比较方便了,要想达到如上效果要解决如下几个问题:
(1) 读取本地连接的打印机(客户端获取)
public class DBPaperSize
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct structPrinterDefaults
{
[MarshalAs(UnmanagedType.LPTStr)]
public String pDatatype;
public IntPtr pDevMode;
[MarshalAs(UnmanagedType.I4)]
public int DesiredAccess;
}; [DllImport("winspool.Drv", EntryPoint = "OpenPrinter", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = false, CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()]
internal static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPTStr)]string printerName, out IntPtr phPrinter, ref structPrinterDefaults pd); [DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = false, CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()]
internal static extern bool ClosePrinter(IntPtr phPrinter); [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct structSize
{
public Int32 width;
public Int32 height;
} [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct structRect
{
public Int32 left;
public Int32 top;
public Int32 right;
public Int32 bottom;
} [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct structFormInfo1
{
[MarshalAs(UnmanagedType.I4)]
public int Flags;
[MarshalAs(UnmanagedType.LPTStr)]
public String pName;
public structSize Size;
public structRect ImageableArea;
}; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct structDevMode
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public String dmDeviceName;
[MarshalAs(UnmanagedType.U2)]
public short dmSpecVersion;
[MarshalAs(UnmanagedType.U2)]
public short dmDriverVersion;
[MarshalAs(UnmanagedType.U2)]
public short dmSize;
[MarshalAs(UnmanagedType.U2)]
public short dmDriverExtra;
[MarshalAs(UnmanagedType.U4)]
public int dmFields;
[MarshalAs(UnmanagedType.I2)]
public short dmOrientation;
[MarshalAs(UnmanagedType.I2)]
public short dmPaperSize;
[MarshalAs(UnmanagedType.I2)]
public short dmPaperLength;
[MarshalAs(UnmanagedType.I2)]
public short dmPaperWidth;
[MarshalAs(UnmanagedType.I2)]
public short dmScale;
[MarshalAs(UnmanagedType.I2)]
public short dmCopies;
[MarshalAs(UnmanagedType.I2)]
public short dmDefaultSource;
[MarshalAs(UnmanagedType.I2)]
public short dmPrintQuality;
[MarshalAs(UnmanagedType.I2)]
public short dmColor;
[MarshalAs(UnmanagedType.I2)]
public short dmDuplex;
[MarshalAs(UnmanagedType.I2)]
public short dmYResolution;
[MarshalAs(UnmanagedType.I2)]
public short dmTTOption;
[MarshalAs(UnmanagedType.I2)]
public short dmCollate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public String dmFormName;
[MarshalAs(UnmanagedType.U2)]
public short dmLogPixels;
[MarshalAs(UnmanagedType.U4)]
public int dmBitsPerPel;
[MarshalAs(UnmanagedType.U4)]
public int dmPelsWidth;
[MarshalAs(UnmanagedType.U4)]
public int dmPelsHeight;
[MarshalAs(UnmanagedType.U4)]
public int dmNup;
[MarshalAs(UnmanagedType.U4)]
public int dmDisplayFrequency;
[MarshalAs(UnmanagedType.U4)]
public int dmICMMethod;
[MarshalAs(UnmanagedType.U4)]
public int dmICMIntent;
[MarshalAs(UnmanagedType.U4)]
public int dmMediaType;
[MarshalAs(UnmanagedType.U4)]
public int dmDitherType;
[MarshalAs(UnmanagedType.U4)]
public int dmReserved1;
[MarshalAs(UnmanagedType.U4)]
public int dmReserved2;
} [DllImport("winspool.Drv", EntryPoint = "AddForm", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = false, CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()]
internal static extern bool AddForm(IntPtr phPrinter, [MarshalAs(UnmanagedType.I4)] int level, ref structFormInfo1 form);
[DllImport("winspool.Drv", EntryPoint = "DeleteForm", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = false, CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()]
internal static extern bool DeleteForm(IntPtr phPrinter, [MarshalAs(UnmanagedType.LPTStr)] string pName);
[DllImport("winspool.Drv", EntryPoint = "SetForm", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = false, CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()]
internal static extern bool SetForm(IntPtr phPrinter, [MarshalAs(UnmanagedType.LPTStr)] string pName, [MarshalAs(UnmanagedType.I4)] int level, ref structFormInfo1 form);
[DllImport("kernel32.dll", EntryPoint = "GetLastError", SetLastError = false, ExactSpelling = true, CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()]
internal static extern Int32 GetLastError();
[DllImport("GDI32.dll", EntryPoint = "CreateDC", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = false, CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()]
internal static extern IntPtr CreateDC([MarshalAs(UnmanagedType.LPTStr)]string pDrive, [MarshalAs(UnmanagedType.LPTStr)] string pName, [MarshalAs(UnmanagedType.LPTStr)] string pOutput, ref structDevMode pDevMode);
[DllImport("GDI32.dll", EntryPoint = "ResetDC", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = false, CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()]
internal static extern IntPtr ResetDC(IntPtr hDC, ref structDevMode pDevMode);
[DllImport("GDI32.dll", EntryPoint = "DeleteDC", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = false, CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()]
internal static extern bool DeleteDC(IntPtr hDC); public System.Drawing.Printing.PaperSize GetPrintForm(string printerName, string paperName)
{
System.Drawing.Printing.PaperSize paper = null;
System.Drawing.Printing.PrinterSettings printer = new System.Drawing.Printing.PrinterSettings();
printer.PrinterName = printerName;
foreach (System.Drawing.Printing.PaperSize ps in printer.PaperSizes)
{
if (ps.PaperName.ToLower() == paperName.ToLower())
{
paper = ps;
break;
}
}
return paper;
} public void SetPrintForm(string printerName, string paperName, float width, float height)
{
if (PlatformID.Win32NT == Environment.OSVersion.Platform)
{
const int PRINTER_ACCESS_USE = 0x00000008;
const int PRINTER_ACCESS_ADMINISTER = 0x00000004;
structPrinterDefaults defaults = new structPrinterDefaults();
defaults.pDatatype = null;
defaults.pDevMode = IntPtr.Zero;
defaults.DesiredAccess = PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE;
IntPtr hPrinter = IntPtr.Zero;
if (OpenPrinter(printerName, out hPrinter, ref defaults))
{
try
{
structFormInfo1 formInfo = new structFormInfo1();
formInfo.Flags = 0;
formInfo.pName = paperName;
formInfo.Size.width = (int)(width * 100.0);
formInfo.Size.height = (int)(height * 100.0);
formInfo.ImageableArea.left = 0;
formInfo.ImageableArea.right = formInfo.Size.width;
formInfo.ImageableArea.top = 0;
formInfo.ImageableArea.bottom = formInfo.Size.height;
bool rslt = false;
if (GetPrintForm(printerName, paperName) != null)
{
rslt = SetForm(hPrinter, paperName, 1, ref formInfo);
}
else
{
this.AddCustomPaperSize(printerName, paperName, width, height);
rslt = true;
}
if (!rslt)
{
StringBuilder strBuilder = new StringBuilder();
strBuilder.AppendFormat("添加纸张{0}时发生错误!, 系统错误号: {1}", paperName, GetLastError());
MessageBox.Show(strBuilder.ToString());
}
}
finally
{
ClosePrinter(hPrinter);
}
}
}
} public void AddCustomPaperSize(string printerName, string paperName, float width, float height)
{
if (PlatformID.Win32NT == Environment.OSVersion.Platform)
{
const int PRINTER_ACCESS_USE = 0x00000008;
const int PRINTER_ACCESS_ADMINISTER = 0x00000004;
structPrinterDefaults defaults = new structPrinterDefaults();
defaults.pDatatype = null;
defaults.pDevMode = IntPtr.Zero;
defaults.DesiredAccess = PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE;
IntPtr hPrinter = IntPtr.Zero;
if (OpenPrinter(printerName, out hPrinter, ref defaults))
{
try
{
DeleteForm(hPrinter, paperName);
structFormInfo1 formInfo = new structFormInfo1();
formInfo.Flags = 0;
formInfo.pName = paperName;
formInfo.Size.width = (int)(width * 100.0);
formInfo.Size.height = (int)(height * 100.0);
formInfo.ImageableArea.left = 0;
formInfo.ImageableArea.right = formInfo.Size.width;
formInfo.ImageableArea.top = 0;
formInfo.ImageableArea.bottom = formInfo.Size.height;
if (!AddForm(hPrinter, 1, ref formInfo))
{
StringBuilder strBuilder = new StringBuilder();
strBuilder.AppendFormat("添加纸张{0}时发生错误!, 系统错误号: {1}", paperName, GetLastError());
throw new ApplicationException(strBuilder.ToString());
}
}
finally
{
ClosePrinter(hPrinter);
}
}
else
{
StringBuilder strBuilder = new StringBuilder();
strBuilder.AppendFormat("打开打印机{0} 时出现异常!, 系统错误号: {1}", printerName, GetLastError());
throw new ApplicationException(strBuilder.ToString());
}
}
else
{
structDevMode pDevMode = new structDevMode();
IntPtr hDC = CreateDC(null, printerName, null, ref pDevMode);
if (hDC != IntPtr.Zero)
{
const long DM_PAPERSIZE = 0x00000002L;
const long DM_PAPERLENGTH = 0x00000004L;
const long DM_PAPERWIDTH = 0x00000008L;
pDevMode.dmFields = (int)(DM_PAPERSIZE | DM_PAPERWIDTH | DM_PAPERLENGTH);
pDevMode.dmPaperSize = 256;
pDevMode.dmPaperWidth = (short)(width * 2.54 * 10000.0);
pDevMode.dmPaperLength = (short)(height * 2.54 * 10000.0);
ResetDC(hDC, ref pDevMode);
DeleteDC(hDC);
}
}
} [DllImport("Winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool SetDefaultPrinter(string printerName); [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool GetDefaultPrinter(StringBuilder pszBuffer, ref int pcchBuffer); public static bool SetDefaultPrint(string printName)
{
return SetDefaultPrinter(printName);
} /// <summary>
/// 获取所有打印机名称
/// </summary>
/// <returns></returns>
public List<string> GetLocalPrinters()
{
List<string> fPrinters = new List<string>();
string defaultprint = DBPaperSize.GetDefaultPrinter();
if (!string.IsNullOrEmpty(defaultprint))
{
fPrinters.Add(defaultprint);
}
foreach (string fPrinterName in PrinterSettings.InstalledPrinters)
{
if (!fPrinters.Contains(fPrinterName))
fPrinters.Add(fPrinterName);
}
//fPrinters = fPrinters.Where(item => item.ToLower().Contains("zdesigner")).ToList();
return fPrinters;
} /// <summary>
/// 获取默认的打印机
/// </summary>
/// <returns></returns>
public static string GetDefaultPrinter()
{
const int ERROR_FILE_NOT_FOUND = 2; const int ERROR_INSUFFICIENT_BUFFER = 122; int pcchBuffer = 0; if (GetDefaultPrinter(null, ref pcchBuffer))
{
return null;
} int lastWin32Error = Marshal.GetLastWin32Error(); if (lastWin32Error == ERROR_INSUFFICIENT_BUFFER)
{
StringBuilder pszBuffer = new StringBuilder(pcchBuffer);
if (GetDefaultPrinter(pszBuffer, ref pcchBuffer))
{
return pszBuffer.ToString();
} lastWin32Error = Marshal.GetLastWin32Error();
}
if (lastWin32Error == ERROR_FILE_NOT_FOUND)
{
return null;
}
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
(2) 网页获取本地连接打印机
其实这个比较简单,就是将客户端启动时候,获取本地连接的打印机,然后发送到服务端,然后服务端打开选择打印机时获取本地注册的打印机。注册的打印机信息使用Redis缓存,为什么使用Redis 是有用处的.
(3)将网页发送的执行传递给打印客户端
其实我们知道Redis除了缓存功能之外,还有简单的订阅发布的功能,将消息传递给打印客户端我们暂时就是使用的Redis,因为属于小量的消息发布订阅个人觉得Redis还比较合适,但是问题也会有,也有很多其他的方式解决。
(4) 打印机的上线和下线
这个其实就是取决于打印客户端是否启动了,其实是否真正连接到打印其实还是打印客户端说了算。当打印客户端启动的时候,将本地打印机信息发送到服务端,关闭的时候发送请求注销服务端缓存的打印机信息。所以为了能够完整的实现打印,打印客户端必须启动,这也是我们在实施过程中很难搞的部分,因为要打开浏览器又要打开客户端(目前我们的办法是设置开机自动启动打印客户端),客户觉得很麻烦。
另外Redis 掉线的问题,必须考虑重连,否则就无法接受到推送的信息,另外重复连接又导致消息订阅重复,导致一个指令可以打印多张标签出来。
五 将打印客户端注册成本地服务
上面说的这种方式是我们用的比较多的一种方式打印,但是有点就是如果有多个打印机站点,我选择的时候可以看到全工厂所有连接的打印机,这个选择就很头疼了。于是就出现了本机网页只调用本地的打印机服务。
这个时候我们就需要将本地的打印服务发布成一个可调用的http服务,IP地址指向127.0.0.1 ,由JS调用本地服务打印,至于如何转化为http服务,可以参考文章
<<吉特日化MES&WMS系统--三色灯控制协议转http>>
六 WebSocket 解决通讯问题
前面也提到了,解决问题的思路和方式都比较简单,也比较固话,只要解决操作端和打印机之间的通讯问题即可,我们还可以使用到WebSocket方式连接网页与打印客户端程序。
七 Windows 强大的注册表
你知道从淘宝网页上如何打开一个 阿里旺旺 聊天工具么,怎么在网页上唤醒 QQ 客服,这两个给了我一个比较不错的思路,我通过网页唤醒一个打印客户端程序,及时客户端未打开的情况下。
《吉特仓库管理系统(开源)-如何在网页端启动WinForm 程序》
只要能够启动打印客户端,就能够传递参数发送打印指令。
八 移动终端调用打印
说到这里绝大部分想到的可以使用蓝牙打印机,没错,蓝牙打印机的确是很不错的一个选择,但是有一点就是打印指令的编排问题,以及难以设置的打印格式。再就是我们开发移动终端的时候使用的是H5, 调用蓝牙通讯这个稳定性实在不敢恭维(当然也有可能是我们的技术能力太弱了,不求甚解)。
其实我们的方式还是采用 4 章节提到的思路,H5 ,http 协议这个不是很完美的方式么,H5 终端发送http指令,通过Redis推送打印消息到打印客户端
选择好打印机之后,然后确定就可以顺利打印出标签了。
以上的方式和方法在之前分享文字以及共享的代码中都有提到使用,只是这一次是集中汇总一次,虽然是小功能但是感觉是应用软件的刚需问题,说简单也简单说复杂也还有那么一些小的弯弯绕绕。
在这几年的工作中,虽然很多精力被分散到其他的事情上去了,但是也从其他领域学到了很多东西,希望有更多的时间能够记录这些经历和经验,这几年的工作领域跨度是非常大的,虽然年纪上来了也有些迷茫和担忧,但是一腔热血暂时还没有消退。世界之大,制造业领域的应用也跨越了众多学科,要学的东西还很多,虽然和高喊着 智能制造,数字化转型,工业互联网,5G+,大数据工业应用的专家和大佬比起来有很大的差距,自己更希望能够从工业制造的工艺应用上去有点突破,虽然要顺势而为但也要实事求是。
这几年主要工作都是从事 日化产品,化妆品类的工厂生产制造,包括 家用清洗剂,牙膏,香水,粉底彩妆,护肤,香水,保健品以及制药方面,希望有更多自己的时间来反思记录这些年遇到的问题。
吉特日化MES系统--通过浏览器调用标签打印的更多相关文章
- 吉特日化MES&WMS系统--三色灯控制协议转http
关于硬件控制大部分都是使用CS客户端程序,一般连接口都是用网口,串口,USB口等,应用通讯是不支持HTTp协议操作的,而目前一般做技术的人员都在于BS开发,使用HTTP 协议,所以在硬件交互上可能觉得 ...
- 织梦(dedecms)系统常用全局变量调用标签及路径
{dede:global.cfg_memberurl/} 指的是会员中心 对应/member/目录 {dede:global.cfg_cmsurl/} 对应的是网站根目录/ {dede:global. ...
- 吉特仓储管系统(开源WMS)--Web在线报表以及打印模板分享
很早之前就想写这篇文章与大家分享一下自己在吉特仓储管理系统中开发打印和报表的功能,在GitHub(https://github.com/hechenqingyuan/gitwms)上公开下载的代码中很 ...
- 吉特日化MES-生产制造的几种形态
1. 订货型和备货型 工厂的生产形态是以接受订单时间和开始生产时间来划分的,因为生产要么得到销售指令要么得到备货指令不能无缘无故的生产.销售指令驱动生产直接受市场销售影响,而备货型可能是对市场的一种预 ...
- 吉特日化MES-工业生产盲区
工业生产的几大盲区 1 重硬件忽略软件 : 目前只要提到智能化,大家都是想到的是一大堆自动执行的设备,什么机器人,输送线,人脸识别摄像头等,在一成套的系统中可能硬件几百万上千万,软件可以是几万几千几 ...
- 吉特仓储管系统(开源WMS)--分享两月如何做到10W+的项目
在此文开篇之处先特别申明,此文在有些人的眼中会有广告的嫌疑,但是本人不想将其作为一个广告宣传的文章,在此提到软件内容部分请大家予以谅解和包含,作为时间不算短的程序员给大家分享一些自己开发吉特仓储管理软 ...
- 吉特仓库管理系统-.NET打印问题总结
在仓储系统的是使用过程中避免不了的是打印单据,仓库系统中包含很多单据:入库单,出库单,盘点单,调拨单,签收单等等,而且还附带着很多的条码标签的打印.本文在此记录一下一个简单的打印问题处理方式.处理问题 ...
- Selenium+Python浏览器调用:Firefox
如何查看python selenium的API python -m pydoc -p 4567 说明: python -m pydoc表示打开pydoc模块,pydoc是查看python文档的首选工 ...
- 转:HTML5页面如何在手机端浏览器调用相机、相册功能
HTML5页面如何在手机端浏览器调用相机.相册功能 开发微信端浏览器访问的HTML5的页面,页面中有一个<input id="input" type="file&q ...
- MES系统在小批量电子行业生产管理中的应用
小批量电子产品生产管理的主要问题 电子电器制造类企业,既有单件小批量生产,也有批量生产:有按库存生产,也有按订单生产,属于典型的离散制造行业.因产品的不同其生产工艺流程也不尽相同,生产设备的布置不是按 ...
随机推荐
- React-Chat移动端聊天实例|react18 hooks仿微信App聊天界面
基于react18+react-vant+zustand仿微信手机端聊天室ReactChat. react18-chat 一款使用最新react18.x hooks.zustand搭配react-va ...
- 【腾讯云 Cloud Studio 实战训练营】在线 IDE 编写 canvas 转换黑白风格头像
关于 Cloud Studio Cloud Studio 是基于浏览器的集成式开发环境(IDE),为开发者提供了一个永不间断的云端工作站.用户在使用Cloud Studio 时无需安装,随时随地打开浏 ...
- ETL之apache hop数据增量同步功能
ETL增量数据抽取CDC 概念:Change Data Capture,变化的数据捕获,也称:[增量数据抽取](名词解释) CDC是一种实现数据的增量抽取解决方案,是实现[ETL整体解决方案]中的一项 ...
- ceph分布式存储软件pgs inconsistent
Ceph是一个开源的分布式存储系统,它提供了高性能.高可靠性以及高扩展性.Ceph的设计理念是基于对象存储模型,通过将数据分割成多个对象并存储在不同的节点上,实现数据的分布式存储和访问. Ceph的核 ...
- 【krpano】 ASP说一说插件
简述 这是一个Asp版krpano说一说案例,运用asp+jquery读写存储入xml文件数据库,结合krpano代码实现的功能:现将案例上传网站供大家学习研究,希望对大家有所帮助. 功能 用户可在网 ...
- 5.2 磁盘CRC32完整性检测
CRC校验技术是用于检测数据传输或存储过程中是否出现了错误的一种方法,校验算法可以通过计算应用与数据的循环冗余校验(CRC)检验值来检测任何数据损坏.通过运用本校验技术我们可以实现对特定内存区域以及磁 ...
- TCP连接的关键之谜:揭秘三次握手的必要性
TCP 连接建立 当我们浏览网页.发送电子邮件或者进行在线游戏时,我们常常不会想到背后复杂的网络连接过程.然而,正是这些看似不起眼的步骤,确保了我们与服务器之间的稳定通信.其中最重要的步骤之一就是TC ...
- 前端三件套系例之JQuery——JQuery基础、JQuery选择器、JQuery文本属性样式操作、JQuery操作DOM
文章目录 1 JQuery基础 1. 了解jQuery 1.1 什么是jQuery 1.2 什么事JS类库 1.3 常见JS类库 1.4 jQuery的优势 1.5 jQuery的版本 1.6 jQu ...
- PostgreSQL学习笔记-4.基础知识:空值NULL、别名AS
NULL 值代表遗漏的未知数据. 默认地,表的列可以存放 NULL 值. 本章讲解 IS NULL 和 IS NOT NULL 操作符. 语法 当创建表时,NULL 的基本语法如下: CREATE T ...
- vue项目打包,解决静态资源无法加载和路由加载无效(404)问题
打包后的项目静态资源无法使用,导致页面空白 静态资源无法使用,那就说明项目打包后,图片和其他静态资源文件相对路径不对,此时找到config里面的index.js,在build模块下加入assetsPu ...