C#开发B/S方式ActiveX控件

2024-05-14 01:48

本文主要是介绍C#开发B/S方式ActiveX控件,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1. 概念

ActiveX 是一个开放的集成平台,为开发人员、 用户和 Web生产商提供了一个快速而简便的在 Internet 和 Intranet 创建程序集成和内容的方法。使用 ActiveX, 可轻松方便的在 Web页中插入多媒体效果、 交互式对象、以及复杂程序,创建用户体验相当的高质量多媒体CD-ROM 。

2. 开发工具及使用环境

本文使用的是Microsoft Visual Studio 2010作为开发工具,刚开始我是使用VS2012版,但发现2012版制作安装时有点麻烦,所以才改为VS2010版作为开发工具。

VS2010下载地址:http://pan.baidu.com/s/1pJRoVAb

操作系统:windows7。

浏览器:IE8以上。

3. 开发项目实例

这里我们用一个实例来贯穿全文。

3.1项目开发实例:开发华视CVR100U-V3身份证扫描器的ActiveX控件,如下图:

3.2开发所需要的DLL库下载地址:http://pan.baidu.com/s/1c1rZJdm

3.3 DLL对应的API下载地址:http://pan.baidu.com/s/1kTNtpsz

3.4 例子:http://pan.baidu.com/s/1i4kyabV

细心的读者会问还有驱动程序呢?这里你没有必要知道驱动程序,如果你是买着机器,自然卖家就给你了,而我们的重点是如何用C#开发ActiveX控件。

所以我们主要的需要的是DLL和API就够了,有了这两样,我们就可以针对相应的机器开发ActiveX控件了。

4. 新建工程

打开VS2010,文件 > 新建 > 项目,打开新建项目面板,如下图:

我们选择.NET Framework 4,并创建类库,这样就创建了一个名为YdtcActiveX类库工程项目,这就是我们的ActiveX项目,如下图:

此时项目就只有一个名为Class1的C#类,此项目不能够执行,因为没有主函数,而且我们当前的项目性质是类库项目,类库的项目是不能够单独执行。我们修改项目的属性,选择项目右键属性,打开项目属性设置,如下:


修改输出类型:控制台应用程序。有些人会问,为啥不直接创建“控制台应用程序”呢?因为我们现在开发的不是能直接自己运行的应用程序呀,所以选择了类库项目,也就是指创建DLL呀,然后提供给浏览器使用呀,由浏览器永远程序来启动我们的控件程序,说白了我们就是提供DLL给浏览器使用。DLL就是程序集。当然你也可以创建控制台应用程序项目也行。

还有一个重点,设置ActiveX控件程序集COM可见,打开“程序集信息”框,勾选“使程序集对COM可见(M)”选项,如下:

别问我为啥要使程序集对COM可见(M),COM是啥,为啥对它可见,我也不知道为啥?哈哈。

ActiveX类库内容大致分为两部分,IObjectSafety接口和实现IObjectSafety接口的控件类,考虑到所有控件类都要实现IObjectSafety接口,可将该接口的实现抽象为一个控件基类

4.1         IObjectSafety接口

为了让ActiveX控件获得客户端的信任,控件类需要实现一个名为“IObjectSafety”接口,我们先在项目里创建这个接口,为了区分其他程序集,所以我新建一个明文“”的文件夹来管理所创建的接口,需要注意:IObjectSafety接口的GUID值不能修改,接口代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace YdtcActiveX
{
[ComImport, Guid("A51D26F2-9057-4008-B910-9C21BE65D1E3")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
public interface IObjectSafety
{
[PreserveSig]
int GetInterfaceSafetyOptions(ref Guid riid,
[MarshalAs(UnmanagedType.U4)] ref int pdwSupportedOptions,
[MarshalAs(UnmanagedType.U4)] ref int pdwEnabledOptions);
[PreserveSig()]
int SetInterfaceSafetyOptions(ref Guid riid,
[MarshalAs(UnmanagedType.U4)] int dwOptionSetMask,
[MarshalAs(UnmanagedType.U4)] int dwEnabledOptions);
}
}

现在工程目录是:



4.2控件基类ActiveXControl.cs

我们也要创建一个文件夹来管理,文件夹名字是“impl”,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using YdtcActiveX.interfaces;
namespace YdtcActiveX
{
public abstract class ActiveXControl : IObjectSafety
{
#region IObjectSafety 成¨¦员¡À
private const string _IID_IDispatch = "{00020400-0000-0000-C000-000000000046}";
private const string _IID_IDispatchEx = "{a6ef9860-c720-11d0-9337-00a0c90dcaa9}";
private const string _IID_IPersistStorage = "{0000010A-0000-0000-C000-000000000046}";
private const string _IID_IPersistStream = "{00000109-0000-0000-C000-000000000046}";
private const string _IID_IPersistPropertyBag = "{37D84F60-42CB-11CE-8135-00AA004BB851}";
private const int INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001;
private const int INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002;
private const int S_OK = 0;
private const int E_FAIL = unchecked((int)0x80004005);
private const int E_NOINTERFACE = unchecked((int)0x80004002);
private bool _fSafeForScripting = true;
private bool _fSafeForInitializing = true;
public int GetInterfaceSafetyOptions(ref Guid riid, ref int pdwSupportedOptions,refint pdwEnabledOptions)
{
int Rslt = E_FAIL;
string strGUID = riid.ToString("B");
pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA;
switch (strGUID)
{
case _IID_IDispatch:
case _IID_IDispatchEx:
Rslt = S_OK;
pdwEnabledOptions = 0;
if (_fSafeForScripting ==true)
pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
break;
case _IID_IPersistStorage:
case _IID_IPersistStream:
case _IID_IPersistPropertyBag:
Rslt = S_OK;
pdwEnabledOptions = 0;
if (_fSafeForInitializing ==true)
pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA;
break;
default:
Rslt = E_NOINTERFACE;
break;
}
return Rslt;
}
public int SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions)
{
int Rslt = E_FAIL;
string strGUID = riid.ToString("B");
switch (strGUID)
{
case _IID_IDispatch:
case _IID_IDispatchEx:
if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_CALLER) &&
(_fSafeForScripting == true))
Rslt = S_OK;
break;
case _IID_IPersistStorage:
case _IID_IPersistStream:
case _IID_IPersistPropertyBag:
if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_DATA) &&
(_fSafeForInitializing == true))
Rslt = S_OK;
break;
default:
Rslt = E_NOINTERFACE;
break;
}
return Rslt;
}
#endregion
}
}

这个类实现了IObjectSafety接口,是作为接下来我们要编写的类的基础类,也就是我们接下来写的类都继承它了。

现在我们的工程目录是:

接下来就是我们的代码了,就是提供给浏览器使用的方法类,因为我们写的是华视CVR100U-V3身份证扫描器的ActiveX控件,所以就会用到华视的dll动态库和API,下面我们把创建工程开始就有的类Class1.cs改名,改为你需要的名字,我该为“Ydtc.cs”

工程目录现在如下:

为了使程序有个好看的界面能显示我们扫描的身份证信息,我添加了一个窗体,同样建文件夹“winform”,现在工程目录如下:

Ydtc.cs代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
using System.IO;
/** 提供客户和程序员使用
------------------------*/
namespace YdtcActiveX
{
[Guid("BAC91DFC-CB54-49D0-B9D1-B9A06EAF520F")]
public class Ydtc : ActiveXControl
{
public static void Main()
{
Console.WriteLine("start...");
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
Console.WriteLine("end...");
}
private bool runStatus = false;
private Thread runThread = null;
public string getTest()
{
return "hello IDCardScanner!";
}
//启动身份证扫描器
public bool startIDCardScanner()
{
int resultUSB = 0;
int resultCOM = 0;
bool result = false;
try
{
//连接USB接口
int port;
for (port = 1001; port <= 1016; port++)
{
resultUSB = CVR_InitComm(port);
if (resultUSB == 1)
{
break;
}
}
if (resultUSB != 1)
{
for (port = 1; port <= 4; port++)
{
resultCOM = CVR_InitComm(port);
if (resultCOM == 1)
{
break;
}
}
}
if (resultUSB == 1 || resultCOM == 1)
{
Console.WriteLine("初始化成功......");
this.runStatus = true;
if (this.runThread == null)
{
Console.WriteLine("启动线程......");
this.runThread = new Thread(new ThreadStart(clickIDCardScanner));
this.runThread.Start();
}
result = true;
}
else
{
result = false;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
return false;
}
return result;
}
//监听读卡
private void clickIDCardScanner()
{
while (this.runStatus)
{
//链接成功
Thread.Sleep(1000);//认证间隔
if (runStatus == false)
{
Console.WriteLine("退出扫描...");
break;
}
Console.WriteLine("正在进行扫描...");
if (CVR_Authenticate() == 1)
{
//通过认证
Console.WriteLine("正在读卡");
int result = CVR_Read_Content(1);//正在读卡
if (result == 1)
{
Console.WriteLine("读卡正确");
}
else
{
Console.WriteLine("读卡出错");
}
}
}
return;
}
//停止身份证扫描器
public bool stopIDCardScanner()
{
int result = CVR_CloseComm();
if (result != 1)
{
Console.WriteLine("关闭失败");
return false;
}
this.runThread = null;
this.runStatus = false;
return true;
}
//获取名字
public String getName()
{
byte[] name = new byte[30];
int length = 30;
GetPeopleName(ref name[0], ref length);
return System.Text.Encoding.GetEncoding("GB2312").GetString(name).Replace("\0", "").Trim();
}
//获取身份证号码
public String getIDCardNo()
{
byte[] number = new byte[30];
int length = 36;
GetPeopleIDCode(ref number[0], ref length);
return System.Text.Encoding.GetEncoding("GB2312").GetString(number).Replace("\0", "").Trim();
}
//获取民族
public String getNationality()
{
byte[] people = new byte[30];
int length = 3;
GetPeopleNation(ref people[0], ref length);
return System.Text.Encoding.GetEncoding("GB2312").GetString(people).Replace("\0", "").Trim();
}
//生日
public String getBirthday()
{
byte[] birthday = new byte[30];
int length = 16;
GetPeopleBirthday(ref birthday[0], ref length);
return System.Text.Encoding.GetEncoding("GB2312").GetString(birthday).Replace("\0", "").Trim();
}
//住址
public String getAddress()
{
byte[] address = new byte[140];
int length = 140;
GetPeopleAddress(ref address[0], ref length);
return System.Text.Encoding.GetEncoding("GB2312").GetString(address).Replace("\0", "").Trim();
}
//有效开始日期
public String getValidityOfStart()
{
byte[] validtermOfStart = new byte[30];
int length = 16;
GetStartDate(ref validtermOfStart[0], ref length);
return System.Text.Encoding.GetEncoding("GB2312").GetString(validtermOfStart).Replace("\0", "").Trim();
}
//有效截止日期
public String getValidityOfEnd()
{
byte[] validtermOfEnd = new byte[30];
int length = 16;
GetEndDate(ref validtermOfEnd[0], ref length);
return System.Text.Encoding.GetEncoding("GB2312").GetString(validtermOfEnd).Replace("\0", "").Trim();
}
//发证机关信息
public String getInstitution()
{
byte[] signdate = new byte[30];
int length = 30;
GetDepartment(ref signdate[0], ref length);
return System.Text.Encoding.GetEncoding("GB2312").GetString(signdate).Replace("\0", "").Trim();
}
//性别
public String getSex()
{
byte[] sex = new byte[30];
int length = 3;
GetPeopleSex(ref sex[0], ref length);
return System.Text.Encoding.GetEncoding("GB2312").GetString(sex).Replace("\0", "").Trim();
}
//安全模块号码
public String getSamid()
{
byte[] samid = new byte[32];
CVR_GetSAMID(ref samid[0]);
return System.Text.Encoding.GetEncoding("GB2312").GetString(samid).Replace("\0", "").Trim();
}
//图片地址
public string getBmpPath()
{
return Application.StartupPath + "\\zp.bmp";
}
public string getTxtPath()
{
return Application.StartupPath + "\\wz.txt";
}
public bool deleteMessage()
{
try
{
FileInfo file = new FileInfo("/Windows/zp.bmp");
file.Delete();
}
catch (Exception)
{
Console.WriteLine("删除照片失败");
return false;
}
try
{
FileInfo file = new FileInfo("/Windows/wz.txt");
file.Delete();
}
catch (Exception)
{
Console.WriteLine("删除文件失败");
return false;
}
return true;
}
public bool deleteFile(string path)
{
try
{
if (File.Exists(@path))
{
FileInfo file = new FileInfo(path);
file.Delete();
return true;
}
else
{
return false;
}
}
catch (Exception)
{
Console.WriteLine("删除照片失败");
return false;
}
}
//获取图片地址
public string getPicturePath()
{
return "C:/Windows/zp.bmp";
}
/**文件复制
@sourcePath 源文件
@targetPath 目标文件
@isrewrite 是否覆盖*/
public bool copyFile(String sourcePath, String targetPath, bool isrewrite)
{
if (File.Exists(@sourcePath))
{
//存在
try
{
System.IO.File.Copy(sourcePath, targetPath, isrewrite);
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace);
return false;
}
Console.WriteLine("复制成功!");
}
else
{
Console.WriteLine("源文件不存在!");
return false;
}
return true;
}
//读取图片
public static byte[] getPicture()
{
long length = new FileInfo("C:/Windows/zp.bmp").Length;
byte[] data = new byte[length];
try
{
StreamReader reader = new StreamReader("C:/Windows/zp.bmp");
reader.BaseStream.Read(data, 0, (int)length);
reader.Close();
}
catch (Exception)
{
Console.WriteLine("读取照片失败");
}
return data;
}
[DllImport("termb.dll", EntryPoint = "CVR_InitComm", CharSet = CharSet.Auto, SetLastError = false)]
public static extern int CVR_InitComm(int Port);//声明外部的标准动态库, 跟Win32API是一样的
[DllImport("termb.dll", EntryPoint = "CVR_CloseComm", CharSet = CharSet.Auto, SetLastError = false)]
public static extern int CVR_CloseComm();
[DllImport("termb.dll", EntryPoint = "CVR_Authenticate", CharSet = CharSet.Auto, SetLastError = false)]
public static extern int CVR_Authenticate();
[DllImport("termb.dll", EntryPoint = "CVR_Read_Content", CharSet = CharSet.Auto, SetLastError = false)]
public static extern int CVR_Read_Content(int Active);
[DllImport("termb.dll", EntryPoint = "GetPeopleName", CharSet = CharSet.Ansi, SetLastError = false)]
public static extern int GetPeopleName(ref byte strTmp, ref int strLen);
[DllImport("termb.dll", EntryPoint = "GetPeopleNation", CharSet = CharSet.Ansi, SetLastError = false)]
public static extern int GetPeopleNation(ref byte strTmp, ref int strLen);
[DllImport("termb.dll", EntryPoint = "GetPeopleBirthday", CharSet = CharSet.Ansi, SetLastError = false, CallingConvention = CallingConvention.StdCall)]
public static extern int GetPeopleBirthday(ref byte strTmp, ref int strLen);
[DllImport("termb.dll", EntryPoint = "GetPeopleAddress", CharSet = CharSet.Ansi, SetLastError = false, CallingConvention = CallingConvention.StdCall)]
public static extern int GetPeopleAddress(ref byte strTmp, ref int strLen);
[DllImport("termb.dll", EntryPoint = "GetPeopleIDCode", CharSet = CharSet.Ansi, SetLastError = false, CallingConvention = CallingConvention.StdCall)]
public static extern int GetPeopleIDCode(ref byte strTmp, ref int strLen);
[DllImport("termb.dll", EntryPoint = "GetDepartment", CharSet = CharSet.Ansi, SetLastError = false, CallingConvention = CallingConvention.StdCall)]
public static extern int GetDepartment(ref byte strTmp, ref int strLen);
[DllImport("termb.dll", EntryPoint = "GetStartDate", CharSet = CharSet.Ansi, SetLastError = false, CallingConvention = CallingConvention.StdCall)]
public static extern int GetStartDate(ref byte strTmp, ref int strLen);
[DllImport("termb.dll", EntryPoint = "GetEndDate", CharSet = CharSet.Ansi, SetLastError = false, CallingConvention = CallingConvention.StdCall)]
public static extern int GetEndDate(ref byte strTmp, ref int strLen);
[DllImport("termb.dll", EntryPoint = "GetPeopleSex", CharSet = CharSet.Ansi, SetLastError = false, CallingConvention = CallingConvention.StdCall)]
public static extern int GetPeopleSex(ref byte strTmp, ref int strLen);
[DllImport("termb.dll", EntryPoint = "CVR_GetSAMID", CharSet = CharSet.Ansi, SetLastError = false, CallingConvention = CallingConvention.StdCall)]
public static extern int CVR_GetSAMID(ref byte strTmp);
[DllImport("termb.dll", EntryPoint = "GetManuID", CharSet = CharSet.Ansi, SetLastError = false, CallingConvention = CallingConvention.StdCall)]
public static extern int GetManuID(ref byte strTmp);
}
}

到这,我们写的代码完成了,当然这只是代码有了而已,还有安装、发布呢!从Ydt.cs代码中就可以看到有程序入口Main函数,而且我们要开启了窗体程序,Ydt.cs类用了几个DLL,就是上面我们说的DLL,这些DLL只能通过DllImport引用,不能直接引用,如下:


我们把用到的DLL 放在Debug路径下,就能通过工程启动程序了。启动如下图:不过这只是界面应用程序,我们的目标是要给浏览器使用。所以要打包成.CAB文件。

5. 制作安装包

在解决方案中添加一个安装项目,文件 > 添加,打开“添加新项目”面板,如下图:

添加名为“YdtcActiveX.Setup”安装项目,现在可以说说上面我为什么选择VS2010作为开发工具了,因为VS2010还保留微软自己的安装制作工具 Visual Studio Installer,而之后的那些版本都用别家的安装工具了,自己的东西不用,非得用别人的,真不理解为啥。“确定”之后就在当前工程添加了一个安装项目,如下图:

选择新添加的安装项目,右键添加 > 项目输出,如下:

选择“YdtcActiveX”作为输出项目。确定后,就会自动检测到依赖Microsoft.NET Framework

5.1查看依赖包版本

单击“Microsoft.NET Framework”,打开启动条件页(右边),如下图:

选到“.NET Framework”按F4打开属性窗口,如下图:

选择工程使用的依赖程序版本,Version:.NET Framework 4。

5.2设置“主输出来着YdtcActiveX(活动)”的属性

下一步设置“主输出来着YdtcActiveX(活动)”的属性,单击“主输出来着YdtcActiveX(活动)”,看右边属性设置,设置Register的值为:vsdrpCOM。

 

5.3设置安装项目注册表版本

选中安装项目YdtcActiveX.Setup,右键“视图”>“注册表”,打开如图:


在“HKEY_CLASSES_ROOT”下添加键“CLSID”和“{GUID值}”(你的类的GUID,这里是Ydct.cs的GUID),还有“InstalledVersion”,右键新建“字符串值”,写上版本,注意,版本用逗号“,”不是“.”号。如下图所示:

InstalledVersion这个版本号要和以下三处设置一致:

(1)、是YdtcActiveX工程属性的“程序集信息”一样,如下:

(2)和安装项目YdtcActiveX.Setup的属性一样

选中YdtcActiveX.Setup 按F4,如下:

(3)和IE页面的<object>标签一样,这个先不说明
以上都设置好之后就可以生成.msi和.EXE文件了,选中“YdtcActiveX.Setup”右键 > 生成。在YdtcActiveX.Setup\Debug下就能看到了,如图:

双击exe或者msi就可以在你电脑上安装你写的ActiveX控件,可是我们不能让客户来做这个,我们要让客户的浏览器来提示下载安装,所以下一步要制作CAB文件,这个文件会被发布到服务器项目上,浏览器通过<object>标签识别下载并安装它,就可以使用它来驱动身份证扫描器进行工作了。

6. 制作CAB

制作CAB需要以下文件:

(1)YdtcActiveX.Setup.msi(改名为YdtcActiveX.msi)

(2)华视提供的DLL(3个分别是:sdtapi.dll、UnPack.dll、termb.dll)

(3)makecab.exe工具

(4)installer.inf和cab.ddf配置文件

最后写一个bat文件进行制作,只要点bat文件就会自动制作CAB文件,这些文件我们都拷贝到安装目录的YdtcActiveX.Setup\Debug路径下,如图:


打开YdtcActiveX.CAB文件,你就会看到以下图:


就是把这些文件都一起打包了,这些文件我的代码我会提供。制作CAB的教程网上有很多。下面我把这些文件的内容贴出来

安装配置文件installer.inf代码如下:

[Version]
Signature= "$CHICAGO$"
AdvancedInf=1.0
[Add.Code]
sdtapi.dll=sdtapi.dll
UnPack.dll=UnPack.dll
termb.dll=termb.dll
[sdtapi.dll]
file-win32-x86=thiscab
RegisterServer=no
DestDir=10
[UnPack.dll]
file-win32-x86=thiscab
RegisterServer=no
DestDir=10
[termb.dll]
file-win32-x86=thiscab
RegisterServer=no
DestDir=10
[Setup Hooks]
hook1=hook1
[hook1]
run=msiexec /i %EXTRACT_DIR%\YdtcActiveX.msi /qn

cab.ddf文件代码如下:

.OPTION   EXPLICIT
.Set Cabinet=on
.Set Compress=on
.Set MaxDiskSize=CDROM
.Set ReservePerCabinetSize=6144
.Set DiskDirectoryTemplate="."
.Set CompressionType=MSZIP
.Set CompressionLevel=7
.Set CompressionMemory=21
.Set CabinetNameTemplate="YdtcActiveX.CAB"
"installer.inf"
"YdtcActiveX.msi"

makeCAB.bat文件的代码如下:

makecab.exe   /f   "cab.ddf"

del "setup.inf"

del "setup.rpt"

到这里C# 开发ActiveX控件就制作好了,下面就是发布、和使用。

7. 发布CAB

就是将YdtcActiveX.CAB发布到你的系统中,下一个html页面使用这个文件,浏览器访问这个页面时,就会提示下载安装YdtcActiveX.CAB控件。

页面的主要代码是<object>标签,

<object id="YdtcActiveX" classid="clsid: BAC91DFC-CB54-49D0-B9D1-B9A06EAF520F"

        codebase="YdtcActiveX.CAB#version=1,0,8" style="display: none;">

         </object>

Classid就是Ydtc.cs中的GUID,version就是上面所说的5(3)所说的了。

 

脚本使用,

function getTest(){

                 var activeX = document.getElementById("YdtcActiveX");

                   var result = activeX.getTest();                  

}

就是调用了Ydtc.cs中的函数getTest();

当然,我们要对浏览器进行设置才能够安装我们的控件,或则你就制作证书浏览器才能安装此插件。

8. 浏览器设置

请看YdtcActiveX.CAB安装文档:http://pan.baidu.com/s/1skyvRTb

此文档的代码:http://pan.baidu.com/s/1gevszFd

9.参考资料

参考资料:http://pan.baidu.com/s/1bnL8V2f

参考的文档:http://pan.baidu.com/s/1nub32BZ

 


这篇关于C#开发B/S方式ActiveX控件的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/987412

相关文章

Debezium 与 Apache Kafka 的集成方式步骤详解

《Debezium与ApacheKafka的集成方式步骤详解》本文详细介绍了如何将Debezium与ApacheKafka集成,包括集成概述、步骤、注意事项等,通过KafkaConnect,D... 目录一、集成概述二、集成步骤1. 准备 Kafka 环境2. 配置 Kafka Connect3. 安装 D

C#中读取XML文件的四种常用方法

《C#中读取XML文件的四种常用方法》Xml是Internet环境中跨平台的,依赖于内容的技术,是当前处理结构化文档信息的有力工具,下面我们就来看看C#中读取XML文件的方法都有哪些吧... 目录XML简介格式C#读取XML文件方法使用XmlDocument使用XmlTextReader/XmlTextWr

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

Springboot中分析SQL性能的两种方式详解

《Springboot中分析SQL性能的两种方式详解》文章介绍了SQL性能分析的两种方式:MyBatis-Plus性能分析插件和p6spy框架,MyBatis-Plus插件配置简单,适用于开发和测试环... 目录SQL性能分析的两种方式:功能介绍实现方式:实现步骤:SQL性能分析的两种方式:功能介绍记录

SQL 中多表查询的常见连接方式详解

《SQL中多表查询的常见连接方式详解》本文介绍SQL中多表查询的常见连接方式,包括内连接(INNERJOIN)、左连接(LEFTJOIN)、右连接(RIGHTJOIN)、全外连接(FULLOUTER... 目录一、连接类型图表(ASCII 形式)二、前置代码(创建示例表)三、连接方式代码示例1. 内连接(I

Android里面的Service种类以及启动方式

《Android里面的Service种类以及启动方式》Android中的Service分为前台服务和后台服务,前台服务需要亮身份牌并显示通知,后台服务则有启动方式选择,包括startService和b... 目录一句话总结:一、Service 的两种类型:1. 前台服务(必须亮身份牌)2. 后台服务(偷偷干

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操

最长公共子序列问题的深度分析与Java实现方式

《最长公共子序列问题的深度分析与Java实现方式》本文详细介绍了最长公共子序列(LCS)问题,包括其概念、暴力解法、动态规划解法,并提供了Java代码实现,暴力解法虽然简单,但在大数据处理中效率较低,... 目录最长公共子序列问题概述问题理解与示例分析暴力解法思路与示例代码动态规划解法DP 表的构建与意义动

JS 实现复制到剪贴板的几种方式小结

《JS实现复制到剪贴板的几种方式小结》本文主要介绍了JS实现复制到剪贴板的几种方式小结,包括ClipboardAPI和document.execCommand这两种方法,具有一定的参考价值,感兴趣的... 目录一、Clipboard API相关属性方法二、document.execCommand优点:缺点:

Python创建Excel的4种方式小结

《Python创建Excel的4种方式小结》这篇文章主要为大家详细介绍了Python中创建Excel的4种常见方式,文中的示例代码简洁易懂,具有一定的参考价值,感兴趣的小伙伴可以学习一下... 目录库的安装代码1——pandas代码2——openpyxl代码3——xlsxwriterwww.cppcns.c